Updated README.md
This commit is contained in:
68
README.md
68
README.md
@ -4,33 +4,50 @@
|
||||
|
||||
## Overview
|
||||
|
||||
This is a driver for the detector tower which is based on the Turbo PMAC driver (https://git.psi.ch/sinq-epics-modules/turboPmac). It consists of the following three objects:
|
||||
- `detectorTowerAngleAxis`: This is a virtual axis which controls multiple physical motors in order to provide a synchronized movement.
|
||||

|
||||
|
||||
This is a driver for the detector tower which is based on the Turbo PMAC driver (https://git.psi.ch/sinq-epics-modules/turboPmac). It consists of the following four objects:
|
||||
- `detectorTowerController`: This is an expanded variant of `turboPmacController` provided by the Turbo PMAC library linked above.It is needed to operate a `detectorTowerAngleAxis`, but it can also be used to operate a "normal" `turboPmacAxis`.
|
||||
- `detectorTowerLiftAxis`: This is an auxiliary axis type attached to the main detector axis. Multiple instances of these axes are constructed automatically when creating a `detectorTowerAngleAxis`.
|
||||
The header files contain detailed documentation for all public functions. The headers themselves are exported when building the library to allow other drivers to depend on this one.
|
||||
- `detectorTowerAngleAxis`: This is a virtual axis which controls multiple physical motors in order to provide a combined movement. Moving it results in a rotation of the entire beam around the support axis position.
|
||||
- `detectorTowerLiftAxis`: This is a virtual axis which controls multiple physical motors in order to provide a combined movement. Moving it results in a vertical lift.
|
||||
- `detectorTowerSupportAxis`: This is an axis at the rotation center of the beam which is part of the combined movements. Its origin can be shifted manually for small adjustments, resulting in a corresponding movement. Other than that, it is not meant to move on its own, hence setting a new value to the `VAL` field of the motor record won't cause it to move.
|
||||
|
||||
## User guide
|
||||
|
||||
The centerpiece of this driver is the `detectorTowerAngleAxis`, which controls the angle of the detector flight tube. Creating an instance of this axis type also creates multiple so-called `detectorTowerLiftAxis`, which are used to perform secondary movements.
|
||||
The centerpiece of this driver is the `detectorTowerAngleAxis`, which controls the angle of the detector flight tube. It is supported by two secondary axes, `detectorTowerLiftAxis` and `detectorTowerSupportAxis`. All three axes are created by a single IOC shell command `detectorTowerAxis` (see [Usage in IOC shell](#usage-in-ioc-shell)). All three axes use absolute encoders and therefore cannot perform a reference / home drive.
|
||||
|
||||
The utilities provided in the `utils` folder of https://git.psi.ch/sinq-epics-modules/turboPmac work with this driver as well.
|
||||
The first two axes can be moved independently from each other or together as a combined movement by issuing both move orders within a certain time span. This time span can be configured via the IOC shell function `setDeferredMovementWait` and defaults to 100 ms. This allows the user to start a combined movement e.g. via caput:
|
||||
|
||||
TODO: How to start combined movement
|
||||
```
|
||||
caput $(ControllerPV):angle 2 & $(ControllerPV):caput lift 10
|
||||
```
|
||||
which moves the angle to 2 degree and shifts the entire beam vertically by 10 mm. When using the axis from NICOS, using the `maw` or `move` command with multiple devices has the same effect:
|
||||
|
||||
```
|
||||
move("angle", 2, "lift", 10)
|
||||
```
|
||||
|
||||
If one axis is already moving, no new move command can be issued until the movement is finished. The `detectorTowerSupportAxis` cannot be moved directly.
|
||||
|
||||
It is possible to shift the origin of all three axes (and therefore also moving the `detectorTowerSupportAxis`) for small adjustments. The current origin position in the axis unit (degree for `detectorTowerAngleAxis`, mm for `detectorTowerLiftAxis` and encoder steps for `detectorTowerSupportAxis`) can be read from the PV `$(INSTR)$(M):Origin`. The origin can be shifted by the amount of axis units written to `$(INSTR)$(M):AdjustOrigin`. Since this is a relative movement, writing "10" two times to `$(INSTR)$(M):AdjustOrigin` shifts the origin by 20 axis units. Therefore, the limits are only there to prevent too large shifts during a single write (since the origin can be shifted to any position by writing to `$(INSTR)$(M):AdjustOrigin` repeatedly).
|
||||
|
||||
The detector tower can be moved into a so-called "changer position" by writing "1" to the PV `$(INSTR)$(M):ChangeState`. This causes the entire tower to move vertically down. When it is in the changer position, the axes cannot be moved at all. In order to go back to the "working state" where the axes can be moved again, write "0" to `$(INSTR)$(M):ChangeState`. The current state of the axis can be read out from `$(INSTR)$(M):ChangingStateRBV`. In case starting a change movement succeeds, `$(INSTR)$(M):ChangeStateRBV` changes its value accordingly, otherwise it stays at its current value.
|
||||
|
||||
The utilities provided in the `utils` folder in `turboPmac/utils` work with this driver as well.
|
||||
|
||||
### Usage in IOC shell
|
||||
|
||||
detectorTower exports the following IOC shell functions:
|
||||
- `detectorTowerController`: Create a new controller object.
|
||||
- `detectorTowerAngleAxis`: Create a new axis object.
|
||||
- `detectorTowerAxis`: Create a `detectorTowerAngleAxis`, a `detectorTowerLiftAxis` and a `detectorTowerSupportAxis` object and link them to each other
|
||||
|
||||
The constructor function for `detectorTowerAngleAxis` has the following syntax:
|
||||
The constructor function for `detectorTowerAxis` has the following syntax:
|
||||
|
||||
```
|
||||
detectorTowerAngleAxis("$(NAME)",1, 2, 3)
|
||||
```
|
||||
|
||||
with 1 being the axis number / index of the detector flight tube angle axis, 2 being the lift offset axis and 3 being the tilt offset axis. These axes are parametrized in the same way as any "normal" axes via a substitution file (see corresponding section below).
|
||||
with 1 being the axis number / index of the `detectorTowerAngleAxis`, 2 being the `detectorTowerLiftAxis` and 3 being the `detectorTowerSupportAxis`. These axes are parametrized in the same way as any "normal" axes via a substitution file (see corresponding section below).
|
||||
|
||||
"Normal" `turboPmacAxis` may be used together with this controller:
|
||||
|
||||
@ -50,7 +67,7 @@ drvAsynIPPortConfigure("$(ASYN_PORT)","172.28.101.24:1025")
|
||||
# 1: Socket communication timeout in seconds
|
||||
detectorTowerController("$(NAME)", "$(ASYN_PORT)", 8, 0.05, 1, 1);
|
||||
|
||||
# Slot 1, 2 and 3 are occupied by a detector tower axis and its attached auxiliary axes, while the slots 4 and 5 are "normal" Turbo PMAC axes.
|
||||
# Slot 1, 2 and 3 are occupied by the three detector tower axis, while the slots 4 and 5 are "normal" Turbo PMAC axes.
|
||||
detectorTowerAngleAxis("$(NAME)",1, 2, 3);
|
||||
turboPmacAxis("$(NAME)",4);
|
||||
turboPmacAxis("$(NAME)",5);
|
||||
@ -63,9 +80,9 @@ setThresholdComTimeout("$(NAME)", 100, 1);
|
||||
|
||||
# Parametrize the EPICS record database with the substitution file named after the MCU.
|
||||
# Since this driver is based on Turbo PMAC, we need to parametrize turboPmac.db in addition to sinqMotor.db and detectorTower.db.
|
||||
epicsEnvSet("SINQDBPATH","$(sinqMotor_DB)/sinqMotor.db")
|
||||
epicsEnvSet("SINQDBPATH","$(detectorTower_DB)/sinqMotor.db")
|
||||
dbLoadTemplate("$(TOP)/$(NAME).substitutions", "INSTR=$(INSTR)$(NAME):,CONTROLLER=$(NAME)")
|
||||
epicsEnvSet("SINQDBPATH","$(turboPmac_DB)/turboPmac.db")
|
||||
epicsEnvSet("SINQDBPATH","$(detectorTower_DB)/turboPmac.db")
|
||||
dbLoadTemplate("$(TOP)/$(NAME).substitutions", "INSTR=$(INSTR)$(NAME):,CONTROLLER=$(NAME)")
|
||||
epicsEnvSet("SINQDBPATH","$(detectorTower_DB)/detectorTower.db")
|
||||
dbLoadTemplate("$(TOP)/$(NAME).substitutions", "INSTR=$(INSTR)$(NAME):,CONTROLLER=$(NAME)")
|
||||
@ -85,9 +102,9 @@ file "$(SINQDBPATH)"
|
||||
{
|
||||
pattern
|
||||
{ AXIS, M, DESC, EGU, DIR, MRES, MSGTEXTSIZE, ENABLEMOVWATCHDOG, LIMITSOFFSET, CANSETSPEED }
|
||||
{ 1, "tower", "Angle of the beam guide", degree, Pos, 0.001, 200, 0, 1.0, 0 }
|
||||
{ 2, "liftZeroCorr", "Detector vertical lift offset", mm, Pos, 0.001, 200, 0, 1.0, 0 }
|
||||
{ 3, "tiltZeroCorr", "Detector tilt offset", degree, Pos, 0.001, 200, 0, 1.0, 0 }
|
||||
{ 1, "angle", "Angle of the beam guide", degree, Pos, 0.001, 200, 0, 1.0, 0 }
|
||||
{ 2, "lift", "Detector vertical lift offset", mm, Pos, 0.001, 200, 0, 1.0, 0 }
|
||||
{ 3, "suppoer", "Support axis", mm, Pos, 0.001, 200, 0, 1.0, 0 }
|
||||
{ 4, "other axis A", "A normal axis", degree, Pos, 0.001, 200, 1, 2.0, 1 }
|
||||
{ 5, "other axis B", "Another normal axis", degree, Pos, 0.001, 200, 1, 2.0, 0 }
|
||||
}
|
||||
@ -99,24 +116,11 @@ Note that the speed of the detector tower axes 1, 2 and 3 cannot be set. Setting
|
||||
|
||||
### Code architecture
|
||||
|
||||
The code is designed around the `detectorTowerAngleAxis`, which controls the angle of the beam guide and acts as a "master" axis. Other movements are realized as auxiliary axes (e.g. for the vertical lift offset and the tilt offset). The `detectorTowerAngleAxis` has pointers to all associated auxiliary axes and (as described above) its IOC shell constructor also builds the associated auxiliary axes.
|
||||
The code is designed around the `detectorTowerAngleAxis`, which controls the angle of the beam guide and acts as a "master" axis which contains pointers to its attached `detectorTowerLiftAxis` and `detectorTowerSupportAxis`. All three axes are polled at once via the function `detectorTowerController::pollDetectorAxes`, which is called from the individual `poll` functions of the axes (the `doPoll` mechanism from `sinqMotor` is not used). To avoid polling the axes multiple times during one controller cycle, the function `detectorTowerController::pollDetectorAxes` is only executed for the axis with the smallest index. Since this axis is polled first, the other two axes are therefore already up-to-date when they execute their own poll function. If one of the axes is moving, all three axes are marked as moving. The same is true for errors.
|
||||
|
||||
TODO
|
||||
The `doPoll` implementation for `detectorTowerAngleAxis` queries the status of both the `detectorTowerAngleAxis` itself and all associated auxiliary axes. If any of the axes is moving, the `detectorTowerAngleAxis` is set to "moving" as well. In turn, the `doPoll` implementation of a `detectorTowerLiftAxis` checks if its associated `detectorTowerAngleAxis` is moving and sets its own movement status accordingly.
|
||||
In order to save on movement time, movement commands to auxiliary axes and the `detectorTowerAngleAxis` are collected and then send as a single resulting movement command to the MCU. In order to do so, a "collector" thread is running which checks if a movement request has been send to one of the axes. If that is the case, it waits for `detectorTowerAngleAxis->deferredMovementWait_` seconds and checks if commands for other axes are given as well. Then, it calls `detectorTowerAngleAxis::startCombinedMove` which combines all commands to a single request which is sent to the MCU. `detectorTowerAngleAxis->deferredMovementWait_` can be set with the IOC shell function `setDeferredMovementWait` and defaults to 100 ms.
|
||||
|
||||
The `detectorTowerController` is a thin wrapper around a `turboPmacController` which overwrites the `readInt32` and `writeInt32` in order to support the PVs "$(INSTR)$(M):ChangeState", "$(INSTR)$(M):PositionStateRBV" and "$(INSTR)$(M):ChangingStateRBV". Any calls to these two methods not concerning the aforementioned PVs are directly forwarded to `turboPmacController::readInt32` / `turboPmacController::writeInt32`.
|
||||
|
||||
In order to save on movement time, movement commands to auxiliary axes and the `detectorTowerAngleAxis` are collected and then send as a single resulting movement command to the MCU. In order to do so, a "collector" thread is running which checks if a movement request has been send to one of the axes. If that is the case, it waits for some time and checks if commands for other axes are given as well. Then, it calls `detectorTowerAngleAxis::startCombinedMove` which combines all commands to a single request which is sent to the MCU. This allows the user to start a combined movement e.g. via caput:
|
||||
|
||||
```
|
||||
caput tower 2 & caput liftZeroCorr 10
|
||||
```
|
||||
|
||||
When using the axis from NICOS, using the `maw` or `move` command with multiple devices has the same effect:
|
||||
|
||||
```
|
||||
move("tower", 2, "liftZeroCorr", 10)
|
||||
```
|
||||
The `detectorTowerController` is a thin wrapper around a `turboPmacController` which overwrites the `readInt32`, `writeInt32` and `writeFloat64` methods in order to support the additional PVs defined in `db/detectorTower.db`. Any calls to these two methods not concerning the aforementioned PVs are directly forwarded to `turboPmacController::readInt32` / `turboPmacController::writeInt32`.
|
||||
|
||||
### Versioning
|
||||
|
||||
|
Reference in New Issue
Block a user