Compare commits

...

11 Commits

Author SHA1 Message Date
d90869cbca Added reminder comment
Some checks failed
Test And Build / Lint (push) Failing after 4s
Test And Build / Build (push) Successful in 7s
2026-02-10 13:18:43 +01:00
eadce0f594 Draft velocity mode
Some checks failed
Test And Build / Lint (push) Failing after 4s
Test And Build / Build (push) Successful in 7s
See TODO in src/masterMacsAxis.cpp, line 552. The velocity readback is
the only thing that doesn't work properly, everything else does work.
Once a solution has been found here, this can be a new minor release.
2026-02-10 12:31:01 +01:00
0e1f95a94b Updated sinqMotor and use setLimits 2026-02-10 09:04:04 +01:00
b01f398533 Set move flag correctly in velocity / jog mode 2026-02-10 09:00:58 +01:00
56d9d20c3a Simplified handling of velocity mode using standard EPICS motor record fields
Some checks failed
Test And Build / Lint (push) Failing after 4s
Test And Build / Build (push) Successful in 7s
2026-02-03 17:57:00 +01:00
4634609891 Rolled back to sinqMotor 1.5.7 2026-02-03 13:35:24 +01:00
fa4a20d83d Updated to sinqMotor 1.7 2026-01-22 11:33:45 +01:00
9a52a4b9ce Implemented velocity mode, but didn't test it yet
Some checks failed
Test And Build / Lint (push) Failing after 4s
Test And Build / Build (push) Successful in 7s
2026-01-20 16:52:52 +01:00
18e68b193a Updated to sinqMotor 1.6.1 2026-01-20 16:50:03 +01:00
fd41d4c9c0 PositionDeadband, dynamic limit detection, velocity mode
Some checks failed
Test And Build / Lint (push) Failing after 4s
Test And Build / Build (push) Failing after 6s
Integrated a readout function for the position deadband. Also read from
the controller if the axis has dynamic limits and only poll the limits
repeatedly if that is the case. Lastly, added support for the velocity
mode (untested!).
2026-01-20 15:09:51 +01:00
f3f0a77f10 Updated sinqMotor to 1.6 2026-01-20 14:16:27 +01:00
5 changed files with 409 additions and 146 deletions

View File

@@ -11,6 +11,11 @@
#include <string.h> #include <string.h>
#include <unistd.h> #include <unistd.h>
enum moveMode {
positionMode,
velocityMode,
};
struct masterMacsAxisImpl { struct masterMacsAxisImpl {
/* /*
The axis status and axis error of MasterMACS are given as an integer from The axis status and axis error of MasterMACS are given as an integer from
@@ -23,6 +28,10 @@ struct masterMacsAxisImpl {
time_t timeAtHandshake; time_t timeAtHandshake;
bool needInit = true; bool needInit = true;
bool targetReachedUninitialized; bool targetReachedUninitialized;
bool dynamicLimits;
bool canPositionMove;
bool canVelocityMove;
moveMode lastMoveCommand;
}; };
/* /*
@@ -92,6 +101,10 @@ masterMacsAxis::masterMacsAxis(masterMacsController *pC, int axisNo)
.waitForHandshake = false, .waitForHandshake = false,
.timeAtHandshake = 0, .timeAtHandshake = 0,
.targetReachedUninitialized = true, .targetReachedUninitialized = true,
.dynamicLimits = false,
.canPositionMove = true,
.canVelocityMove = false,
.lastMoveCommand = positionMode,
})) { })) {
asynStatus status = asynSuccess; asynStatus status = asynSuccess;
@@ -179,14 +192,17 @@ Read out the following values:
asynStatus masterMacsAxis::init() { asynStatus masterMacsAxis::init() {
// Local variable declaration // Local variable declaration
asynStatus pl_status = asynSuccess; asynStatus status = asynSuccess;
char response[pC_->MAXBUF_] = {0}; char response[pC_->MAXBUF_] = {0};
int nvals = 0; int nvals = 0;
double motorRecResolution = 0.0; double motRecResolution = 0.0;
double motorPosition = 0.0; double motPosition = 0.0;
double motorVelocity = 0.0; double motPositionDeadband = 0.0;
double motorVmax = 0.0; double motVelocity = 0.0;
double motorAccel = 0.0; double motVmax = 0.0;
double motAccel = 0.0;
int dynamicLimits = 0;
int possibleModes = 0;
// ========================================================================= // =========================================================================
@@ -195,9 +211,9 @@ asynStatus masterMacsAxis::init() {
time_t now = time(NULL); time_t now = time(NULL);
time_t maxInitTime = 60; time_t maxInitTime = 60;
while (1) { while (1) {
pl_status = pC_->getDoubleParam(axisNo_, pC_->motorRecResolution(), status = pC_->getDoubleParam(axisNo_, pC_->motorRecResolution(),
&motorRecResolution); &motRecResolution);
if (pl_status == asynParamUndefined) { if (status == asynParamUndefined) {
if (now + maxInitTime < time(NULL)) { if (now + maxInitTime < time(NULL)) {
asynPrint(pC_->pasynUser(), ASYN_TRACE_ERROR, asynPrint(pC_->pasynUser(), ASYN_TRACE_ERROR,
"Controller \"%s\", axis %d => %s, line " "Controller \"%s\", axis %d => %s, line "
@@ -206,10 +222,10 @@ asynStatus masterMacsAxis::init() {
__LINE__); __LINE__);
return asynError; return asynError;
} }
} else if (pl_status == asynSuccess) { } else if (status == asynSuccess) {
break; break;
} else if (pl_status != asynSuccess) { } else if (status != asynSuccess) {
return pC_->paramLibAccessFailed(pl_status, "motorRecResolution_", return pC_->paramLibAccessFailed(status, "motorRecResolution_",
axisNo_, __PRETTY_FUNCTION__, axisNo_, __PRETTY_FUNCTION__,
__LINE__); __LINE__);
} }
@@ -220,73 +236,133 @@ asynStatus masterMacsAxis::init() {
setAxisParamChecked(this, motorConnected, false); setAxisParamChecked(this, motorConnected, false);
// Read out the current position // Read out the current position
pl_status = pC_->read(axisNo_, 12, response); status = pC_->read(axisNo_, 12, response);
if (pl_status != asynSuccess) { if (status != asynSuccess) {
return pl_status; return status;
} }
nvals = sscanf(response, "%lf", &motorPosition); nvals = sscanf(response, "%lf", &motPosition);
if (nvals != 1) { if (nvals != 1) {
return pC_->couldNotParseResponse("R12", response, axisNo_, return pC_->couldNotParseResponse("R12", response, axisNo_,
__PRETTY_FUNCTION__, __LINE__); __PRETTY_FUNCTION__, __LINE__);
} }
status = setMotorPosition(motPosition);
if (status != asynSuccess) {
return status;
}
// Read out the current velocity // Read out the current velocity
pl_status = pC_->read(axisNo_, 05, response); status = pC_->read(axisNo_, 05, response);
if (pl_status != asynSuccess) { if (status != asynSuccess) {
return pl_status; return status;
} }
nvals = sscanf(response, "%lf", &motorVelocity); nvals = sscanf(response, "%lf", &motVelocity);
if (nvals != 1) { if (nvals != 1) {
return pC_->couldNotParseResponse("R05", response, axisNo_, return pC_->couldNotParseResponse("R05", response, axisNo_,
__PRETTY_FUNCTION__, __LINE__); __PRETTY_FUNCTION__, __LINE__);
} }
// Read out the maximum velocity // Read out the maximum velocity
pl_status = pC_->read(axisNo_, 26, response); status = pC_->read(axisNo_, 26, response);
if (pl_status != asynSuccess) { if (status != asynSuccess) {
return pl_status; return status;
} }
nvals = sscanf(response, "%lf", &motorVmax); nvals = sscanf(response, "%lf", &motVmax);
if (nvals != 1) { if (nvals != 1) {
return pC_->couldNotParseResponse("R26", response, axisNo_, return pC_->couldNotParseResponse("R26", response, axisNo_,
__PRETTY_FUNCTION__, __LINE__); __PRETTY_FUNCTION__, __LINE__);
} }
// Read out the acceleration status = setVeloFields(abs(motVelocity), 0.0, motVmax);
pl_status = pC_->read(axisNo_, 06, response); if (status != asynSuccess) {
if (pl_status != asynSuccess) { return status;
return pl_status;
} }
nvals = sscanf(response, "%lf", &motorAccel);
// Read out the acceleration
status = pC_->read(axisNo_, 06, response);
if (status != asynSuccess) {
return status;
}
nvals = sscanf(response, "%lf", &motAccel);
if (nvals != 1) { if (nvals != 1) {
return pC_->couldNotParseResponse("R06", response, axisNo_, return pC_->couldNotParseResponse("R06", response, axisNo_,
__PRETTY_FUNCTION__, __LINE__); __PRETTY_FUNCTION__, __LINE__);
} }
status = setAcclField(motAccel);
// Store the motor position in the parameter library if (status != asynSuccess) {
pl_status = setMotorPosition(motorPosition); return status;
if (pl_status != asynSuccess) {
return pl_status;
} }
// Write to the motor record fields // Read out the motor position deadband
pl_status = setVeloFields(motorVelocity, 0.0, motorVmax); status = pC_->read(axisNo_, 13, response);
if (pl_status != asynSuccess) { if (status != asynSuccess) {
return pl_status; return status;
} }
pl_status = setAcclField(motorAccel); nvals = sscanf(response, "%lf", &motPositionDeadband);
if (pl_status != asynSuccess) { if (nvals != 1) {
return pl_status; return pC_->couldNotParseResponse("R13", response, axisNo_,
__PRETTY_FUNCTION__, __LINE__);
}
setAxisParamChecked(this, motorPositionDeadband, motPositionDeadband);
// Check if the motor has dynamic limits
status = pC_->read(axisNo_, 32, response);
if (status != asynSuccess) {
return status;
}
nvals = sscanf(response, "%d", &dynamicLimits);
if (nvals != 1) {
return pC_->couldNotParseResponse("R32", response, axisNo_,
__PRETTY_FUNCTION__, __LINE__);
}
pMasterMacsA_->dynamicLimits = bool(dynamicLimits);
// Check if the motor can switch its mode
status = pC_->read(axisNo_, 31, response);
if (status != asynSuccess) {
return status;
}
nvals = sscanf(response, "%d", &possibleModes);
if (nvals != 1) {
return pC_->couldNotParseResponse("R31", response, axisNo_,
__PRETTY_FUNCTION__, __LINE__);
} }
pl_status = readEncoderType(); switch (possibleModes) {
if (pl_status != asynSuccess) { case 1:
return pl_status; pMasterMacsA_->canPositionMove = true;
pMasterMacsA_->canVelocityMove = false;
break;
case 2:
pMasterMacsA_->canPositionMove = false;
pMasterMacsA_->canVelocityMove = true;
break;
case 3:
pMasterMacsA_->canPositionMove = true;
pMasterMacsA_->canVelocityMove = true;
break;
default:
asynPrint(pC_->pasynUser(), ASYN_TRACE_ERROR,
"Controller \"%s\", axis %d => %s, line "
"%d:\nunexpected answer %d for R31 (possible operation "
"modes). Expected one of 1, 2 or 3.\n",
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__,
possibleModes);
}
status = readEncoderType();
if (status != asynSuccess) {
return status;
}
// Read the axis limits
status = readLimits();
if (status != asynSuccess) {
return status;
} }
// Update the parameter library immediately // Update the parameter library immediately
pl_status = callParamCallbacks(); status = callParamCallbacks();
if (pl_status != asynSuccess) { if (status != asynSuccess) {
// If we can't communicate with the parameter library, it doesn't // If we can't communicate with the parameter library, it doesn't
// make sense to try and upstream this to the user -> Just log the // make sense to try and upstream this to the user -> Just log the
// error // error
@@ -294,14 +370,68 @@ asynStatus masterMacsAxis::init() {
"Controller \"%s\", axis %d => %s, line " "Controller \"%s\", axis %d => %s, line "
"%d:\ncallParamCallbacks failed with %s.\n", "%d:\ncallParamCallbacks failed with %s.\n",
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__, pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__,
pC_->stringifyAsynStatus(pl_status)); pC_->stringifyAsynStatus(status));
return pl_status; return status;
} }
// Axis is fully initialized // Axis is fully initialized
setNeedInit(false); setNeedInit(false);
return pl_status; return status;
}
asynStatus masterMacsAxis::readLimits() {
asynStatus status = asynSuccess;
char response[pC_->MAXBUF_] = {0};
int nvals = 0;
double highLimit = 0.0;
double lowLimit = 0.0;
double limitsOffset = 0.0;
// =========================================================================
status = pC_->read(axisNo_, 34, response);
if (status != asynSuccess) {
return status;
}
nvals = sscanf(response, "%lf", &lowLimit);
if (nvals != 1) {
return pC_->couldNotParseResponse("R34", response, axisNo_,
__PRETTY_FUNCTION__, __LINE__);
}
status = pC_->read(axisNo_, 33, response);
if (status != asynSuccess) {
return status;
}
nvals = sscanf(response, "%lf", &highLimit);
if (nvals != 1) {
return pC_->couldNotParseResponse("R33", response, axisNo_,
__PRETTY_FUNCTION__, __LINE__);
}
/*
The axis limits are set as: ({[]})
where [] are the positive and negative limits set in EPICS/NICOS, {} are
the software limits set on the MCU and () are the hardware limit
switches. In other words, the EPICS/NICOS limits must be stricter than
the software limits on the MCU which in turn should be stricter than the
hardware limit switches. For example, if the hardware limit switches are
at [-10, 10], the software limits could be at [-9, 9] and the EPICS /
NICOS limits could be at
[-8, 8]. Therefore, we cannot use the software limits read from the MCU
directly, but need to shrink them a bit. In this case, we're shrinking
them by 0.1 mm or 0.1 degree (depending on the axis type) on both sides.
*/
getAxisParamChecked(this, motorLimitsOffset, &limitsOffset);
highLimit = highLimit - limitsOffset;
lowLimit = lowLimit + limitsOffset;
return setLimits(highLimit, lowLimit);
} }
// Perform the actual poll // Perform the actual poll
@@ -311,10 +441,10 @@ asynStatus masterMacsAxis::doPoll(bool *moving) {
asynStatus poll_status = asynSuccess; asynStatus poll_status = asynSuccess;
// Status of read-write-operations of ASCII commands to the controller // Status of read-write-operations of ASCII commands to the controller
asynStatus rw_status = asynSuccess; asynStatus rwStatus = asynSuccess;
// Status of parameter library operations // Status of parameter library operations
asynStatus pl_status = asynSuccess; asynStatus plStatus = asynSuccess;
char response[pC_->MAXBUF_] = {0}; char response[pC_->MAXBUF_] = {0};
int nvals = 0; int nvals = 0;
@@ -324,9 +454,6 @@ asynStatus masterMacsAxis::doPoll(bool *moving) {
double currentPosition = 0.0; double currentPosition = 0.0;
double previousPosition = 0.0; double previousPosition = 0.0;
double motorRecResolution = 0.0; double motorRecResolution = 0.0;
double highLimit = 0.0;
double lowLimit = 0.0;
double limitsOffset = 0.0;
double handshakePerformed = 0; double handshakePerformed = 0;
// ========================================================================= // =========================================================================
@@ -366,8 +493,8 @@ asynStatus masterMacsAxis::doPoll(bool *moving) {
} }
pC_->read(axisNo_, 86, response); pC_->read(axisNo_, 86, response);
if (rw_status != asynSuccess) { if (rwStatus != asynSuccess) {
return rw_status; return rwStatus;
} }
nvals = sscanf(response, "%lf", &handshakePerformed); nvals = sscanf(response, "%lf", &handshakePerformed);
@@ -393,38 +520,20 @@ asynStatus masterMacsAxis::doPoll(bool *moving) {
getAxisParamChecked(this, motorRecResolution, &motorRecResolution); getAxisParamChecked(this, motorRecResolution, &motorRecResolution);
// Read the previous motor position // Read the previous motor position
pl_status = motorPosition(&previousPosition); plStatus = motorPosition(&previousPosition);
if (pl_status != asynSuccess) { if (plStatus != asynSuccess) {
return pl_status; return plStatus;
} }
// Update the axis status // Update the axis status
rw_status = readAxisStatus(); rwStatus = readAxisStatus();
if (rw_status != asynSuccess) { if (rwStatus != asynSuccess) {
return rw_status; return rwStatus;
} }
// If we wait for a handshake, but the motor was moving in its last poll rwStatus = pC_->read(axisNo_, 12, response);
// cycle and has reached its target, it is not moving. Otherwise it is if (rwStatus != asynSuccess) {
// considered moving, even if we're still waiting for the handshake. return rwStatus;
if (pMasterMacsA_->targetReachedUninitialized) {
*moving = false;
} else {
if (targetReached() || !switchedOn()) {
*moving = false;
} else {
*moving = true;
}
}
if (targetReached()) {
pMasterMacsA_->targetReachedUninitialized = false;
}
// Read the current position
rw_status = pC_->read(axisNo_, 12, response);
if (rw_status != asynSuccess) {
return rw_status;
} }
nvals = sscanf(response, "%lf", &currentPosition); nvals = sscanf(response, "%lf", &currentPosition);
if (nvals != 1) { if (nvals != 1) {
@@ -432,12 +541,60 @@ asynStatus masterMacsAxis::doPoll(bool *moving) {
__PRETTY_FUNCTION__, __LINE__); __PRETTY_FUNCTION__, __LINE__);
} }
plStatus = setMotorPosition(currentPosition);
if (plStatus != asynSuccess) {
return plStatus;
}
setAxisParamChecked(this, motorEncoderPosition, currentPosition);
if (pMasterMacsA_->lastMoveCommand == velocityMode && !speedEqualZero()) {
// TODO: Not sure whether the RVEL field of the motor record does not
// work - has to be clarified
double actualVelocity = 0.0;
rwStatus = pC_->read(axisNo_, 14, response);
if (rwStatus != asynSuccess) {
return rwStatus;
}
nvals = sscanf(response, "%lf", &actualVelocity);
if (nvals != 1) {
return pC_->couldNotParseResponse("R14", response, axisNo_,
__PRETTY_FUNCTION__, __LINE__);
}
// Write the actual velocity to the paramLib (TODO: does it though?)
setAxisParamChecked(this, motorVelocity, actualVelocity);
// Motor is moving in velocity mode
*moving = true;
} else {
// If we wait for a handshake, but the motor was moving in its last poll
// cycle and has reached its target, it is not moving. Otherwise it is
// considered moving, even if we're still waiting for the handshake.
if (pMasterMacsA_->targetReachedUninitialized) {
*moving = false;
} else {
if (targetReached() || !switchedOn()) {
*moving = false;
} else {
*moving = true;
}
}
if (targetReached()) {
pMasterMacsA_->targetReachedUninitialized = false;
}
}
/* /*
Read out the error if either a fault condition status flag has been set or Read out the error if either a fault condition status flag has been set
if a movement has just ended. or if a movement has just ended.
*/ */
if (faultConditionSet() || !(*moving)) { if (faultConditionSet() || !(*moving)) {
rw_status = readAxisError(); rwStatus = readAxisError();
} }
msgPrintControlKey keyError = msgPrintControlKey( msgPrintControlKey keyError = msgPrintControlKey(
@@ -614,48 +771,13 @@ asynStatus masterMacsAxis::doPoll(bool *moving) {
pC_->getMsgPrintControl().resetCount(keyError, pC_->pasynUser()); pC_->getMsgPrintControl().resetCount(keyError, pC_->pasynUser());
} }
// Read out the limits, if the motor is not moving // Read out the limits, if the motor is not moving and if the limits are
if (!(*moving)) { // dynamic
rw_status = pC_->read(axisNo_, 34, response); if (pMasterMacsA_->dynamicLimits && !(*moving)) {
if (rw_status != asynSuccess) { rwStatus = readLimits();
return rw_status; if (rwStatus != asynSuccess) {
return rwStatus;
} }
nvals = sscanf(response, "%lf", &lowLimit);
if (nvals != 1) {
return pC_->couldNotParseResponse("R34", response, axisNo_,
__PRETTY_FUNCTION__, __LINE__);
}
rw_status = pC_->read(axisNo_, 33, response);
if (rw_status != asynSuccess) {
return rw_status;
}
nvals = sscanf(response, "%lf", &highLimit);
if (nvals != 1) {
return pC_->couldNotParseResponse("R33", response, axisNo_,
__PRETTY_FUNCTION__, __LINE__);
}
/*
The axis limits are set as: ({[]})
where [] are the positive and negative limits set in EPICS/NICOS, {} are
the software limits set on the MCU and () are the hardware limit
switches. In other words, the EPICS/NICOS limits must be stricter than
the software limits on the MCU which in turn should be stricter than the
hardware limit switches. For example, if the hardware limit switches are
at [-10, 10], the software limits could be at [-9, 9] and the EPICS /
NICOS limits could be at
[-8, 8]. Therefore, we cannot use the software limits read from the MCU
directly, but need to shrink them a bit. In this case, we're shrinking
them by 0.1 mm or 0.1 degree (depending on the axis type) on both sides.
*/
getAxisParamChecked(this, motorLimitsOffset, &limitsOffset);
highLimit = highLimit - limitsOffset;
lowLimit = lowLimit + limitsOffset;
setAxisParamChecked(this, motorHighLimitFromDriver, highLimit);
setAxisParamChecked(this, motorLowLimitFromDriver, lowLimit);
} }
// Update the enable PV // Update the enable PV
@@ -679,13 +801,83 @@ asynStatus masterMacsAxis::doPoll(bool *moving) {
setAxisParamChecked(this, motorStatusDone, !(*moving)); setAxisParamChecked(this, motorStatusDone, !(*moving));
setAxisParamChecked(this, motorStatusDirection, direction); setAxisParamChecked(this, motorStatusDirection, direction);
pl_status = setMotorPosition(currentPosition);
if (pl_status != asynSuccess) {
return pl_status;
}
return poll_status; return poll_status;
} }
asynStatus masterMacsAxis::moveVelocity(double minVelocity, double maxVelocity,
double acceleration) {
// Suppress unused variable warning
(void)minVelocity;
(void)acceleration;
// Status of read-write-operations of ASCII commands to the controller
asynStatus status = asynSuccess;
char command[pC_->MAXBUF_];
double motorRecResolution = 0.0;
double motorVelocity = 0.0;
int enabled = 0;
// =========================================================================
// Can the motor be operated in velocity mode?
if (!pMasterMacsA_->canVelocityMove) {
asynPrint(pC_->pasynUser(), ASYN_TRACE_ERROR,
"Controller \"%s\", axis %d => %s, line %d:\nAxis cannot "
"operate in velocity mode.\n",
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__);
setAxisParamChecked(this, motorStatusProblem, true);
setAxisParamChecked(this, motorMessageText,
"cannot operate in velocity mode");
return asynError;
}
getAxisParamChecked(this, motorEnableRBV, &enabled);
getAxisParamChecked(this, motorRecResolution, &motorRecResolution);
if (enabled == 0) {
asynPrint(pC_->pasynUser(), ASYN_TRACE_ERROR,
"Controller \"%s\", axis %d => %s, line %d:\nAxis is "
"disabled.\n",
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__);
return asynSuccess;
}
// Convert from EPICS to user / motor units
motorVelocity = maxVelocity * motorRecResolution;
snprintf(command, sizeof(command), "%lf", motorVelocity);
status = pC_->write(axisNo_, 05, command);
if (status != asynSuccess) {
setAxisParamChecked(this, motorStatusProblem, true);
return status;
}
asynPrint(pC_->pasynUser(), ASYN_TRACE_FLOW,
"Controller \"%s\", axis %d => %s, line %d:\nSetting speed "
"to %lf.\n",
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__,
motorVelocity);
double timeout = pC_->comTimeout();
if (pMasterMacsA_->targetReachedUninitialized &&
timeout < PowerCycleTimeout) {
timeout = PowerCycleTimeout;
}
// Start the move. We do not use the MovTimeout watchdog here, because the
// motor can move for any time in velocity mode.
status = pC_->write(axisNo_, 00, "3", timeout);
if (status != asynSuccess) {
return status;
}
// Cache the information that the current movement is in velocity mode
pMasterMacsA_->lastMoveCommand = velocityMode;
return status;
}
asynStatus masterMacsAxis::doMove(double position, int relative, asynStatus masterMacsAxis::doMove(double position, int relative,
double minVelocity, double maxVelocity, double minVelocity, double maxVelocity,
double acceleration) { double acceleration) {
@@ -697,7 +889,7 @@ asynStatus masterMacsAxis::doMove(double position, int relative,
// Status of read-write-operations of ASCII commands to the controller // Status of read-write-operations of ASCII commands to the controller
asynStatus status = asynSuccess; asynStatus status = asynSuccess;
char value[pC_->MAXBUF_]; char command[pC_->MAXBUF_];
double motorCoordinatesPosition = 0.0; double motorCoordinatesPosition = 0.0;
double motorRecResolution = 0.0; double motorRecResolution = 0.0;
double motorVelocity = 0.0; double motorVelocity = 0.0;
@@ -706,6 +898,18 @@ asynStatus masterMacsAxis::doMove(double position, int relative,
// ========================================================================= // =========================================================================
// Can the motor be operated in position mode?
if (!pMasterMacsA_->canPositionMove) {
asynPrint(pC_->pasynUser(), ASYN_TRACE_ERROR,
"Controller \"%s\", axis %d => %s, line %d:\nAxis cannot "
"operate in position mode.\n",
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__);
setAxisParamChecked(this, motorStatusProblem, true);
setAxisParamChecked(this, motorMessageText,
"cannot operate in position mode");
return asynError;
}
getAxisParamChecked(this, motorEnableRBV, &enabled); getAxisParamChecked(this, motorEnableRBV, &enabled);
getAxisParamChecked(this, motorRecResolution, &motorRecResolution); getAxisParamChecked(this, motorRecResolution, &motorRecResolution);
@@ -740,8 +944,8 @@ asynStatus masterMacsAxis::doMove(double position, int relative,
// motor speed changed since the last move command. // motor speed changed since the last move command.
if (motorCanSetSpeed != 0) { if (motorCanSetSpeed != 0) {
snprintf(value, sizeof(value), "%lf", motorVelocity); snprintf(command, sizeof(command), "%lf", motorVelocity);
status = pC_->write(axisNo_, 05, value); status = pC_->write(axisNo_, 05, command);
if (status != asynSuccess) { if (status != asynSuccess) {
setAxisParamChecked(this, motorStatusProblem, true); setAxisParamChecked(this, motorStatusProblem, true);
return status; return status;
@@ -755,14 +959,14 @@ asynStatus masterMacsAxis::doMove(double position, int relative,
} }
// Set the target position // Set the target position
snprintf(value, sizeof(value), "%lf", motorCoordinatesPosition); snprintf(command, sizeof(command), "%lf", motorCoordinatesPosition);
status = pC_->write(axisNo_, 02, value); status = pC_->write(axisNo_, 02, command);
if (status != asynSuccess) { if (status != asynSuccess) {
setAxisParamChecked(this, motorStatusProblem, true); setAxisParamChecked(this, motorStatusProblem, true);
return status; return status;
} }
// If the motor has just been enabled, use Enable // If the motor has just been enabled, use a longer timeout for starting
double timeout = pC_->comTimeout(); double timeout = pC_->comTimeout();
if (pMasterMacsA_->targetReachedUninitialized && if (pMasterMacsA_->targetReachedUninitialized &&
timeout < PowerCycleTimeout) { timeout < PowerCycleTimeout) {
@@ -791,6 +995,8 @@ asynStatus masterMacsAxis::doMove(double position, int relative,
return asynError; return asynError;
} }
// Cache the information that the current movement is in position mode
pMasterMacsA_->lastMoveCommand = positionMode;
return status; return status;
} }
@@ -1039,6 +1245,28 @@ asynStatus masterMacsAxis::enable(bool on) {
return asynError; return asynError;
} }
asynStatus masterMacsAxis::setMode(int mode) {
char command[pC_->MAXBUF_] = {0};
// Map the EPICS value to MasterMACS values (see
// MasterMACS_manual.pdf).
int adjustedMode = 0;
if (mode == 0) {
adjustedMode = 1;
} else if (mode == 1) {
adjustedMode = 3;
} else {
// This branch is unreachable, as it is is already checked
// within sinqController::writeInt32 that value is either 0
// or 1.
return asynError;
}
snprintf(command, sizeof(command), "%d", adjustedMode);
return pC_->write(axisNo(), 07, command);
}
bool masterMacsAxis::needInit() { return pMasterMacsA_->needInit; } bool masterMacsAxis::needInit() { return pMasterMacsA_->needInit; }
/** /**
@@ -1069,8 +1297,8 @@ asynStatus masterMacsAxis::readAxisStatus() {
// ========================================================================= // =========================================================================
asynStatus rw_status = pC_->read(axisNo_, 10, response); asynStatus rwStatus = pC_->read(axisNo_, 10, response);
if (rw_status == asynSuccess) { if (rwStatus == asynSuccess) {
float axisStatus = 0; float axisStatus = 0;
int nvals = sscanf(response, "%f", &axisStatus); int nvals = sscanf(response, "%f", &axisStatus);
@@ -1082,7 +1310,7 @@ asynStatus masterMacsAxis::readAxisStatus() {
pMasterMacsA_->axisStatus = toBitset(axisStatus); pMasterMacsA_->axisStatus = toBitset(axisStatus);
} }
return rw_status; return rwStatus;
} }
asynStatus masterMacsAxis::readAxisError() { asynStatus masterMacsAxis::readAxisError() {
@@ -1090,8 +1318,8 @@ asynStatus masterMacsAxis::readAxisError() {
// ========================================================================= // =========================================================================
asynStatus rw_status = pC_->read(axisNo_, 11, response); asynStatus rwStatus = pC_->read(axisNo_, 11, response);
if (rw_status == asynSuccess) { if (rwStatus == asynSuccess) {
float axisError = 0; float axisError = 0;
int nvals = sscanf(response, "%f", &axisError); int nvals = sscanf(response, "%f", &axisError);
@@ -1101,7 +1329,7 @@ asynStatus masterMacsAxis::readAxisError() {
} }
pMasterMacsA_->axisError = toBitset(axisError); pMasterMacsA_->axisError = toBitset(axisError);
} }
return rw_status; return rwStatus;
} }
bool masterMacsAxis::readyToBeSwitchedOn() { bool masterMacsAxis::readyToBeSwitchedOn() {
@@ -1128,6 +1356,8 @@ bool masterMacsAxis::remoteMode() { return pMasterMacsA_->axisStatus[9]; }
bool masterMacsAxis::targetReached() { return pMasterMacsA_->axisStatus[10]; } bool masterMacsAxis::targetReached() { return pMasterMacsA_->axisStatus[10]; }
bool masterMacsAxis::speedEqualZero() { return pMasterMacsA_->axisStatus[12]; }
bool masterMacsAxis::internalLimitActive() { bool masterMacsAxis::internalLimitActive() {
return pMasterMacsA_->axisStatus[11]; return pMasterMacsA_->axisStatus[11];
} }

View File

@@ -51,6 +51,17 @@ class HIDDEN masterMacsAxis : public sinqAxis {
*/ */
asynStatus doPoll(bool *moving); asynStatus doPoll(bool *moving);
/**
* @brief TODO
*
* @param minVelocity
* @param maxVelocity
* @param acceleration
* @return asynStatus
*/
asynStatus moveVelocity(double minVelocity, double maxVelocity,
double acceleration);
/** /**
* @brief Implementation of the `doMove` function from sinqAxis. The * @brief Implementation of the `doMove` function from sinqAxis. The
* parameters are described in the documentation of `sinqAxis::doMove`. * parameters are described in the documentation of `sinqAxis::doMove`.
@@ -117,6 +128,15 @@ class HIDDEN masterMacsAxis : public sinqAxis {
*/ */
asynStatus enable(bool on); asynStatus enable(bool on);
/**
* @brief Write the new operation mode (position or velocity) to the
* MasterMACS controller.
*
* @param mode
* @return asynStatus
*/
asynStatus setMode(int mode);
/** /**
* @brief Read the encoder type (incremental or absolute) for this axis * @brief Read the encoder type (incremental or absolute) for this axis
* from the MCU and store the information in the PV ENCODER_TYPE. * from the MCU and store the information in the PV ENCODER_TYPE.
@@ -154,6 +174,12 @@ class HIDDEN masterMacsAxis : public sinqAxis {
*/ */
asynStatus readAxisStatus(); asynStatus readAxisStatus();
/**
* @brief Read the upper and lower limits and store them in the parameter
* library.
*/
asynStatus readLimits();
/* /*
The functions below read the specified status bit from the axisStatus (see The functions below read the specified status bit from the axisStatus (see
masterMacsAxisImpl redefinition in masterMacsAxis.cpp) bitset. Since a bit masterMacsAxisImpl redefinition in masterMacsAxis.cpp) bitset. Since a bit
@@ -224,6 +250,12 @@ class HIDDEN masterMacsAxis : public sinqAxis {
*/ */
bool internalLimitActive(); bool internalLimitActive();
/**
* @brief Read the property from axisStatus (see masterMacsAxisImpl
* redefinition in masterMacsAxis.cpp)
*/
bool speedEqualZero();
// Bits 12 and 13 are unused // Bits 12 and 13 are unused
/** /**

View File

@@ -570,7 +570,7 @@ asynStatus masterMacsController::readInt32(asynUser *pasynUser,
*value = 1; *value = 1;
return asynSuccess; return asynSuccess;
} else { } else {
return asynMotorController::readInt32(pasynUser, value); return sinqController::readInt32(pasynUser, value);
} }
} }

View File

@@ -75,7 +75,8 @@ class HIDDEN masterMacsController : public sinqController {
/** /**
* @brief Overloaded function of sinqController * @brief Overloaded function of sinqController
* *
* The function is overloaded to allow resetting the node * The function is overloaded to allow resetting the node and changing the
* operation mode.
* *
* @param pasynUser Specify the axis via the asynUser * @param pasynUser Specify the axis via the asynUser
* @param value New value * @param value New value