Safety commit

This commit is contained in:
2025-03-31 16:48:46 +02:00
parent 566e3c950e
commit e7a1b546c2
5 changed files with 30 additions and 46 deletions

View File

@ -1,5 +1,9 @@
# detectorTower
## <span style="color:red">Please read the documentation of sinqMotor first: https://git.psi.ch/sinq-epics-modules/sinqmotor</span>
## 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:
- `detectorTowerAxis`: This is a virtual axis which controls multiple physical motors in order to provide a synchronized movement.
- `detectorTowerController`: This is an expanded variant of `turboPmacController` provided by the Turbo PMAC library linked above.It is needed to operate a `detectorTowerAxis`, but it can also be used to operate a "normal" `turboPmacAxis`.
@ -68,12 +72,12 @@ dbLoadRecords("$(sinqMotor_DB)/asynRecord.db","P=$(INSTR)$(NAME),PORT=$(ASYN_POR
### Substitution file
From the perspective of EPICS, the main detector flight tube axis and the auxiliary axes are independent axes and therefore each axis needs its own parametrizatioin in the substitution file. If additional axes are used in the axis, they are parametrized as usual:
From the perspective of EPICS, the main detector flight tube axis and the auxiliary axes are independent axes and therefore each axis needs its own parametrization in the substitution file. If additional axes are used in the axis, they are parametrized as usual:
```
detectorTowerAxis("$(NAME)",1, 2, 3);
turboPmacAxis("$(NAME)",4);
turboPmacAxis("$(NAME)",5);
```
```
file "$(SINQDBPATH)"
{
@ -91,6 +95,8 @@ Note that the speed of the detector tower axes 1, 2 and 3 cannot be set. Setting
## Developer guide
### Code architecture
The code is designed around the `detectorTowerAxis`, 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 `detectorTowerAxis` has pointers to all associated auxiliary axes and (as described above) its IOC shell constructor also builds the associated auxiliary axes.
The `doPoll` implementation for `detectorTowerAxis` queries the status of both the `detectorTowerAxis` itself and all associated auxiliary axes. If any of the axes is moving, the `detectorTowerAxis` is set to "moving" as well. In turn, the `doPoll` implementation of a `auxiliaryAxis` checks if its associated `detectorTowerAxis` is moving and sets its own movement status accordingly.

View File

@ -55,10 +55,6 @@ auxiliaryAxis::auxiliaryAxis(detectorTowerController *pC, int axisNo)
exit(-1);
}
// Initialize all member variables
// Assumed to be not ready by default, this is overwritten in the next poll
targetPosition_ = 0.0;
// Register the hook function during construction of the first axis object
if (axes.empty()) {
initHookRegister(&epicsInithookFunction);
@ -241,3 +237,5 @@ asynStatus auxiliaryAxis::stop(double acceleration) {
return rw_status;
}
asynStatus auxiliaryAxis::reset() { return dTA_->reset(); };

View File

@ -63,10 +63,16 @@ class auxiliaryAxis : public turboPmacAxis {
asynStatus doMove(double position, int relative, double min_velocity,
double max_velocity, double acceleration);
/**
* @brief Call the reset function of the associated `detectorTowerAxis`.
*
* @return asynStatus
*/
asynStatus reset();
protected:
detectorTowerController *pC_;
detectorTowerAxis *dTA_;
double targetPosition_;
private:
friend class detectorTowerAxis;

View File

@ -78,7 +78,6 @@ detectorTowerAxis::detectorTowerAxis(detectorTowerController *pC, int axisNo,
// Initialize all member variables
// Assumed to be not ready by default, this is overwritten in the next poll
error_ = 0;
targetPosition_ = 0.0;
receivedTarget_ = false;
startingDeferredMovement_ = false;
deferredMovementWait_ = 0.1; // seconds
@ -191,17 +190,11 @@ asynStatus detectorTowerAxis::doPoll(bool *moving) {
}
// Read the previous motor position
pl_status = pC_->getDoubleParam(axisNo_, pC_->motorPosition(),
&previousBeamTiltAngle);
pl_status = motorPosition(&previousBeamTiltAngle);
if (pl_status != asynSuccess) {
return pC_->paramLibAccessFailed(pl_status, "motorPosition_", axisNo_,
__PRETTY_FUNCTION__, __LINE__);
return pl_status;
}
// Transform from EPICS to motor coordinates (see comment in
// turboPmacAxis::atFirstPoll)
previousBeamTiltAngle = previousBeamTiltAngle * motorRecResolution;
/*
Query the following information:
- In-position flag
@ -224,7 +217,7 @@ asynStatus detectorTowerAxis::doPoll(bool *moving) {
&liftOffsetHighLimit, &liftOffsetLowLimit, &tiltOffsetHighLimit,
&tiltOffsetLowLimit);
if (nvals != 10) {
return pC_->errMsgCouldNotParseResponse(command, response, axisNo_,
return pC_->couldNotParseResponse(command, response, axisNo_,
__PRETTY_FUNCTION__, __LINE__);
}
@ -712,12 +705,9 @@ asynStatus detectorTowerAxis::doPoll(bool *moving) {
double liftOffsetPosition =
detectorHeight + detectorRadius * sin(beamTiltAngle);
pl_status = pC_->setDoubleParam(liftAxisNo, pC_->motorPosition(),
liftOffsetPosition / motorRecResolution);
pl_status = setMotorPosition(liftOffsetPosition);
if (pl_status != asynSuccess) {
return pC_->paramLibAccessFailed(pl_status, "motorPosition_",
liftAxisNo, __PRETTY_FUNCTION__,
__LINE__);
return pl_status;
}
pl_status = pC_->setDoubleParam(liftAxisNo, pC_->motorHighLimitFromDriver(),
liftOffsetHighLimit);
@ -738,14 +728,9 @@ asynStatus detectorTowerAxis::doPoll(bool *moving) {
// There exists no readback value for tiltOffsetAxis_, hence we just set the
// current position to the target position.
pl_status = tiltOffsetAxis_->setDoubleParam(
pC_->motorPosition(),
tiltOffsetAxis_->targetPosition_ / motorRecResolution);
tiltOffsetAxis_->setMotorPosition(tiltOffsetAxis_->targetPosition_);
if (pl_status != asynSuccess) {
return pC_->paramLibAccessFailed(pl_status, "motorPosition_",
tiltAxisNo, __PRETTY_FUNCTION__,
__LINE__);
return pl_status;
}
pl_status = pC_->setDoubleParam(tiltAxisNo, pC_->motorHighLimitFromDriver(),
tiltOffsetHighLimit);
@ -764,11 +749,9 @@ asynStatus detectorTowerAxis::doPoll(bool *moving) {
// Transform from motor to EPICS coordinates (see comment in
// turboPmacAxis::init())
pl_status = setDoubleParam(pC_->motorPosition(),
beamTiltAngle / motorRecResolution);
pl_status = setMotorPosition(beamTiltAngle);
if (pl_status != asynSuccess) {
return pC_->paramLibAccessFailed(pl_status, "motorPosition_", axisNo_,
__PRETTY_FUNCTION__, __LINE__);
return pl_status;
}
pl_status = setIntegerParam(pC_->positionStateRBV(), positionState);
@ -988,7 +971,7 @@ detectorTowerAxis::toggleWorkingChangerState(bool toChangingPosition) {
return rw_status;
}
asynStatus detectorTowerAxis::reset() {
asynStatus detectorTowerAxis::doReset() {
char response[pC_->MAXBUF_];
asynStatus pl_status = asynSuccess;
@ -1106,10 +1089,6 @@ asynStatus detectorTowerCreateAxis(const char *portName, int axisDetectorTower,
return asynSuccess;
}
/*
Same procedure as for the CreateController function, but for the axis
itself.
*/
static const iocshArg CreateAxisArg0 = {"Controller name (e.g. mcu1)",
iocshArgString};
static const iocshArg CreateAxisArg1 = {"Number of the detector angle axis",

View File

@ -8,10 +8,6 @@
// https://en.cppreference.com/w/cpp/language/class.
class detectorTowerController;
/**
* @brief
*
*/
class detectorTowerAxis : public turboPmacAxis {
public:
/**
@ -97,12 +93,12 @@ class detectorTowerAxis : public turboPmacAxis {
asynStatus toggleWorkingChangerState(bool toChangingPosition);
/**
* @brief Reset the axis error
* @brief Implementation of the `doReset` method of sinqAxis
*
* @param on
* @return asynStatus
*/
asynStatus reset();
asynStatus doReset();
// If true, either this axis or one of the auxiliaryAxis attached to it
// received a movement command.
@ -121,7 +117,6 @@ class detectorTowerAxis : public turboPmacAxis {
protected:
detectorTowerController *pC_;
double targetPosition_;
int error_;
auxiliaryAxis *tiltOffsetAxis_;
auxiliaryAxis *liftOffsetAxis_;