May 21, 2020
Hooks from the simulink servo
We have already talked about how the servo gets started
(by a dynamic call to rt_run()) and how it gets triggered to
run at 1 kHz (via the registered callback to mmt_mount_connect()).
However the running servo needs access to several things, as
follows:
- It needs the current position command (the target value).
- It needs the current actual position (the encoder value).
- It needs to send a command somewhere (the DAC).
- It may need to report an error situation.
Looking at the disassembly of el_servo.o, we can learn the following:
The function mdlOutputs() makes a number of calls:
- It calls pci_dac_sim_out() in switch.c to send a value to the DAC.
- It calls el_sim_encoder() in switch.c to report the predicted encoder value
generated by the SS model. There are notes on this in switch.c
- It calls el_poserr() in switch.c to report the position error.
A decision to shut the drives down may be made in switch.c
- It calls el_velest() in switch.c to report the estimated velocity.
This is simply logged (or can be) at this time.
Finding where the model gets the command and encoders is not so straightforward
looking at the disassembled code. Interestingly, there are multiple definitions
of some symbols like "mdlStart". This is because the object file links together
several "models", each of which defines this symbol. They each have a structure
with function pointers to keep all of this straight, but that is not readily
apparent looking at the disassembled code first hand.
With this in mind, it is worthwhile to look at "mdlOutputs()", of which there are
several. Since I defined an encoder block, it became a "model" and its output
routine is responsible for returning encoder value(s). And indeed I see a call
to mmt_el_encoders() which is in switch.c -- and it is prefixed by a comment:
/* ================================================ */
/* Hooks for the simulink el_encoders S-function */
/* ================================================ */
The function mmt_el_encoders() sends an array of 7 values, which are documented
in the afore mentioned comment.
Studying all of the mdlOutputs() routines in the disassembly, I find an unexpected
one that calls mmt_params_out(), which is in telem_sv.c.
This is apparently part of getting telemetry from the servo which goes into SV files
that we can log.
All told there are 4 definitions of mdlOutputs() in the disassembly, as follows:
- One to get encoder values and call mmt_el_encoders().
- One to output DAC values and the ultimate servo outputs.
- One that calls mmt_logger_out().
- One that calls mmt_params_out().
The mystery of the target value -- solved!
How the servo gets the target value was a dark mystery for some time.
The trick is not being fooled by a name.
The mmt_el_encoders() routine sends an array of 7 values, and
one of these is the target value for the servo!
Just because it has the name "encoders" does not mean that it does only that.
And I can understand why I would do this. Why set up a whole separate
block and S function just for the command value.