Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Update from latest axisCore code base
Squashed commit of the following: Add field MsgTxt in driver Add a text field to show what the motor is doing. The base idea is taken from motor8x.opi, which has a number of texts displayed like "Moving" or "Soft limit". On the long run, it is better to prepare these texts already in the IOC, and use which display whatever to display it, including camonitor. The current implementation does not (yet) show soft limit violations, like the widget does. The main advantage is that the driver can put in human readable texts, which are fetched from the motion controller. Status of limit switches updated independent of movement direction. Issue epics-modules#35 The raw limit switches found in the MSTA field are converted into LLS and HLS: - When the DIR field is 1, they are swapped - When the limit switch is not in the direction of the commanded direction, it is not shown. This is useful when a controller has only one bit which reports both limit switches. It had been useful when these controllers where more common. Today there are different reasons to remove this filtering from the record: - the motor can be moved outside the record into the other direction - The motor is slowly creeping towards the limit switch and hits it - The cable is broken or disconnected - The HOMF button is pressed and the motor starts his own homing sequence, which hits the low limit switch. In any case, this kind of filtering can be done in the driver, if needed. When hitting a limit switch while doing retries or backlash, the filter is still used to stop (or not) the motor. (I think that it would be safer to stop the motor whenever any limit switch is hit, but that is a seperate discussion, don't change this now) Improve handling of ramp-down after stop Handle the case where the motor runs into a limit switch and stops: Once the limit switch is activated, the motor is ramped down to stop. (At least some controllers do this) While ramping down, the controller is not ready to receive new commands. Record recognizes motor stop while jogging The following situation came up while debugging soft limits in a motion controller which had different values then the record. The motor is at position 50mm (RBV=50), the low soft limit is 15 (LLM=15), jogging velocity is 10 mm/sec (JVEL=10). The motion controller has an internal soft limit which is 35 mm, which we want to test. Set JOGR to 1, the motor will move backwards. (Side note: it would be stopped by the record once it passed 25mm). Before that, the motion controller stops the motor and reports DONE. The state machine in the record is not prepared to handle this, JOGR stays 1. The expected behavior is that JOGR returns to 0. Because this is an unexpected stop, reset even pending home requests. In other words: call clear_buttons(pmr) Whether or not an alarm is raised may be another question. The natural thing would be to set LVIO to 1, but we don't know why the controller stopped the motion. Unless we add a bit in MSTA like "RA_LVIO"... But in any case this can and should go into a separate commit. Make "stop if driver returns RA_PROBLEM true" optional. Commit 303a920 introduced the feature to stop a motor when the driver sets the PROBLEM bit. This has been problematic for different reasons: - The commit message does not mention which controller/driver actually need this feature. - The driver itself could have been fixed to do the stop - Some controllers (like XPS) report a PROBLEM when the axis is not homed. - Other controllers report errors and stop the motor on their own. But as soon as the axis is stopped, the error disappears and there is no chance for the user to see it. (This happens e.g. when an axis is below the low soft limit and a TWF is done. The record allows this, but the controller does not, as the new set point is out of range) After some forth and back changes I come to the conclusion that this feature is worth to keep, but the driver must enable it. In other words, it does what versions of motorRecord < 6.9 did. Record: motor record DLY and STOP problem Fix the problem that the record gets stuck when STOP is pressed while the record is in MIP_DELAY (and the motor is standing still, so that there is no record processing). Currently the MIP_DELAY bits are set to 0, when a STOP is issued. As the motor already hase stopped, the DMOV field never goes to 1. There are 2 possible solutions here: a) STOP wins: pmr->dmov = FALSE; MARK(M_DMOV); b) DELAY wins Send a STOP to the controller (just to be sure), but wait for the DELAY. a) may cause probles later, whena new positionioning is done after the STOP and a new DELAY is triggered. As the old callback is still active, it may be executed before the new callback. And the time will be too short. For this reason go with b) http://www.aps.anl.gov/epics/tech-talk/2015/msg01786.php Make it possible to use encoder readback > 32 bit Some encoders use more than 32 bit and those are not handled very well: - The model 3 driver puts a C-double into the parameter library: setDoubleParam(pC_->motorEncoderPosition_, value) - The callback forwards the double into device support: update_values() in devAxisAsyn.c gets the value here: pPvt->status.encoderPosition - Now the value must go into a record field. The choice we have is the REP field, which is 32 bit integer: rawvalue = (epicsInt32)floor(pPvt->status.encoderPosition + 0.5); if (pmr->rep != rawvalue) { pmr->rep = rawvalue; db_post_events(pmr, &pmr->rep, DBE_VAL_LOG); } - After the value is stored here, the record later decides which value to use for the readback: Either it is based on REP, RMP or RDBL. Both REP and RMP are 32 bit integer, and are now multiplied with the respective resolution into DRBV, which is (again) a double. The old logic worked like this: Controller -> Driver -> devSupport -> .REP -> .DRBV (double or int) (double) (double) (int) (double) The new code allows to "by-pass" the double-int-double conversion: Controller -> Driver -> devSupport -> .REP (double or int) (double) (double) (int) devSupport -> "priv" -> .DRBV (double) (double) (double) The double value from the driver is stored in a "private" data structure and later used in the record. "private" means not exposed to EPICS, in other words, we don't add another field. but have a private data structure to communicate from device support to the record. Note1: There is a fallback in the record: When device support does not fill in pmr->priv->readBack.encoderPosition, the record will fall back to use RMP. Note2: A similar "double preventing" is done for REP Note3: Even the RDBL field is not crippled to int any more. Note4: We could have defined new fields in the record. I didn't do that for 2 reasons: - If there was a new field, then device support must update it - We try to reduce the number of fields - The REP and RMP using integer feel like legacy for external programs that need it - If there is a need to see the encoder value, it could easily be added as a "model 3" ai record. Add a "priv" field to contain local data So far all data in the record has been exposed as record fields. Some of them are simply private, like all the last fields. Prepare a new field holding the private data, but don't use it yet. This will be done in the next commit. motorRecord: Factor out functions. See motorDevSup.c Add SDBD field Add "Set point Dead Band" field: Movements smaller than SDBD are not send to the controller (But DMOV blinks once) When SDBD is 0, the value is copied from MRES. This allows 3 things: - avoid "small" movements, independent of MRES. Especially when the auto-power feature is used, we can skip a useless poweron - power off cycle. - Use a higer deadband value when an encoder is used which has a lower resolution than the motor. - Set MRES to 1.0 and send EGU from the record to the controller. (Today we often use a dummy MRES of 0.001 and compensate this in the driver by reverting the MRES scaling with another scaling) Respect "read only" soft limits from controller If the driver has reported that controller has "read only" soft limts for this motor, setting of DHLM and DLLM will respect these: Whenever DHLM is above the "read only" soft limit, it will be clipped to that value. Similar for DLLM. When changing HLM and LLM in user coordinates, they are converted into dial coordinates, clipped if needed, and converted back into user coords. Dial- and user values stay always synchronized. axisRecord: maybeRetry() needs the commanded position There was a possible race condition, when RTRY == 1 and the DVAL field was changed while the motor was moving. At the end of the move, the DRBV field was compared to DVAL, and this didn't work as expected. Because the DVAL had changed under the time, the record did set the "MISS" field. Steps to reproduce: Tweek the motor a couple of times fast after each other. Introduse a private variable last.commandedDval, and compare it with DRBV at the end of the move. motorRecord: Reset JOGF/JOGR when jogging stops When the motor is jogging and stopped by setting CNEN to 0, JOGF/JOGR may stay at 1. (This assumes that CNEN controls the amplifier, as it does in the simulator and test 141). Correct an over-critical check: pmr->mip may be either exactly MIP_JOGF or exactly MIP_JOGR. After this change the MIP_JOG_REQ bit may be 1 (or 0). The "Motor stopped while jogging and we didn't stop it" code is executed, the movement is done, no backlash. init_record() Controller offline error handling (part 1) This was changed in bbdce8ce077e44f63547779ee3e53f03844f: > When the record is initialized, the current postion of the axis is read > from the controller. If the position is 0 and if "auto save and restore" > for this axis is configured, the position will be set into the controller. > If the communication is not established (yet) this all fails and the > record should be put into an error state. Improve the situation, if "auto save and restore" is not needed: - Introduce load_pos_needed() in devAxisAsyn.c, break code out from init_controller_load_pos_if_needed() - Introduce initial_poll(), break out code from init_record() Look at the return value of process_reason = (*pdset->update_values) in axisrecord.cc and change the processing: If the initial poll fails and "load position" is not needed, put the record into UDF state. After the first poll, move it out of the UDF state. If the initial poll fails and "load position" -is- needed, put the record into UDF state and set PACT to 1, making the record unusable. The IOC must be restarted. This improves the situation when auto save & restore is not used. On the log run, all this initializion code should become more asyn-ish and be part of the poller. Stay tuned. axisRecord.cc: Reset MIP_EXTERNAL when motor has stopped When the motor has stopped, MIP_EXTERNAL must be reset. Otherwise maybeRetry() will be called and my set the MISS bit, which is wrong for external moves. Make it possible to compile under ESS EPICS Environment (EEE) Split the Makefile into Makefile.epics and Makefile.EEE This allows to compile the code both at ESS and outside.
- Loading branch information