forked from epics_driver_modules/motorBase
motorRecord.cc: Add ACCS field
The problem: When a user changes the velocity by writing to the VELO field, but forgets to write to the ACCL field, the acceleration will change and may be too high. (Note: Many users are not aware of this side-effect). Solution: Introduce a field called ACCS, "Acceleration in seconds^2". Once the field is written, the ACCL field is updated and the acceleration is "locked". It is locked for changes of VELO. It can be be unlocked by writing to ACCL. If the acceleration is locked (or not) is stored in the field ACCU, which can be either "motorACCSused_Accl" or "motorACCSused_Accs". And in this sense ACCU is not a lock, but just keeps track which of the accelation fields ACCL or ACCS has been updated last, and should be used in the next movement. In any case an update to ACCS updated ACCL and the other way around. Thanks to Mark Rivers for this nice idea.
This commit is contained in:
+11
-2
@@ -242,6 +242,14 @@ below.
|
||||
<td>DOUBLE</td>
|
||||
<td>acceleration time</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="#Fields_motion">ACCS</a></td>
|
||||
<td>R/W</td>
|
||||
<td>Acceleration (EGU/s^2)</td>
|
||||
<td>DOUBLE</td>
|
||||
<td><br>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="#Fields_status">ADEL</a></td>
|
||||
<td>R/W</td>
|
||||
@@ -1675,7 +1683,8 @@ below.
|
||||
<td colspan="5">The motor record expects the hardware to produce a trapezoidal
|
||||
speed profile. That is, the motor speed is expected to increase linearly with
|
||||
time from the base speed, VBAS, to the full speed, VELO, in ACCL seconds. At the
|
||||
end of a motion, the speed is expected to decrease similarly to VBAS. </td>
|
||||
end of a motion, the speed is expected to decrease similarly to VBAS.
|
||||
Note that the ACCS field can be use to specify the acceleration in EGU/s^2. </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>JVEL</td>
|
||||
@@ -2329,7 +2338,7 @@ below.
|
||||
<td colspan="5">When one of these fields is set to 1, the record will
|
||||
immediately reset it to 0, and the motor will move (with backlash takeout if
|
||||
BDST is nonzero) by a distance TWV (in user coordinates) at the acceleration
|
||||
specified by ACCL and at speed VELO.</td>
|
||||
specified by ACCL/ACCS and at speed VELO.</td>
|
||||
</tr>
|
||||
<tr valign="top">
|
||||
<td>TWV</td>
|
||||
|
||||
@@ -475,6 +475,83 @@ static void callbackFunc(struct callback *pcb)
|
||||
}
|
||||
|
||||
|
||||
static double accEGUfromVelo(motorRecord *pmr, double veloEGU)
|
||||
{
|
||||
double vmin = pmr->vbas;
|
||||
double vmax = fabs(veloEGU);
|
||||
double acc;
|
||||
/* ACCL or ACCS */
|
||||
if (pmr->accu == motorACCSused_Accs)
|
||||
acc = pmr->accs;
|
||||
else if (vmax > vmin)
|
||||
acc = (vmax - vmin) / pmr->accl;
|
||||
else
|
||||
acc = vmax / pmr->accl;
|
||||
|
||||
return acc;
|
||||
}
|
||||
|
||||
static void updateACCLfromACCS(motorRecord *pmr)
|
||||
{
|
||||
if (pmr->accu != motorACCSused_Accs)
|
||||
{
|
||||
pmr->accu = motorACCSused_Accs;
|
||||
db_post_events(pmr, &pmr->accu, DBE_VAL_LOG);
|
||||
}
|
||||
if (pmr->accs > 0.0)
|
||||
{
|
||||
double temp_dbl = pmr->velo / pmr->accs;
|
||||
if (pmr->accl != temp_dbl)
|
||||
{
|
||||
pmr->accl = temp_dbl;
|
||||
db_post_events(pmr, &pmr->accl, DBE_VAL_LOG);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void updateACCSfromACCL(motorRecord *pmr)
|
||||
{
|
||||
double temp_dbl;
|
||||
if (pmr->accu != motorACCSused_Accl)
|
||||
{
|
||||
pmr->accu = motorACCSused_Accl;
|
||||
db_post_events(pmr, &pmr->accu, DBE_VAL_LOG);
|
||||
}
|
||||
temp_dbl = pmr->velo / pmr->accl;
|
||||
if (pmr->accs != temp_dbl)
|
||||
{
|
||||
pmr->accs = temp_dbl;
|
||||
db_post_events(pmr, &pmr->accs, DBE_VAL_LOG);
|
||||
}
|
||||
}
|
||||
|
||||
static void updateACCL_ACCSfromVELO(motorRecord *pmr)
|
||||
{
|
||||
if (pmr->accu == motorACCSused_Accs)
|
||||
{
|
||||
if (pmr->accs > 0.0)
|
||||
{
|
||||
double temp_dbl = pmr->velo / pmr->accs;
|
||||
if (pmr->accl != temp_dbl)
|
||||
{
|
||||
pmr->accl = temp_dbl;
|
||||
db_post_events(pmr, &pmr->accl, DBE_VAL_LOG);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
double temp_dbl = pmr->velo / pmr->accl;
|
||||
if (pmr->accs != temp_dbl)
|
||||
{
|
||||
pmr->accs = temp_dbl;
|
||||
db_post_events(pmr, &pmr->accs, DBE_VAL_LOG);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
enforceMinRetryDeadband()
|
||||
|
||||
@@ -859,7 +936,7 @@ static long postProcess(motorRecord * pmr)
|
||||
|
||||
if (pmr->mip & MIP_JOG_STOP)
|
||||
{
|
||||
double acc = (vel - vbase) > 0 ? ((vel - vbase)/ pmr->accl) : (vel / pmr->accl);
|
||||
double acc = accEGUfromVelo(pmr, pmr->velo);
|
||||
|
||||
if (vel <= vbase)
|
||||
vel = vbase + 1;
|
||||
@@ -2190,7 +2267,7 @@ static RTN_STATUS do_work(motorRecord * pmr, CALLBACK_VALUE proc_ind)
|
||||
double newpos = pmr->dval / pmr->mres; /* where to go */
|
||||
double vbase = pmr->vbas / fabs(pmr->mres); /* base speed */
|
||||
double vel = pmr->velo / fabs(pmr->mres); /* normal speed */
|
||||
double acc = (vel - vbase) > 0 ? ((vel - vbase) / pmr->accl) : (vel / pmr->accl); /* normal accel. */
|
||||
double acc = accEGUfromVelo(pmr, pmr->velo);
|
||||
/*
|
||||
* 'bpos' is one backlash distance away from 'newpos'.
|
||||
*/
|
||||
@@ -2595,6 +2672,7 @@ static long special(DBADDR *paddr, int after)
|
||||
/* new velo: make s agree */
|
||||
case motorRecordVELO:
|
||||
range_check(pmr, &pmr->velo, pmr->vbas, pmr->vmax);
|
||||
updateACCL_ACCSfromVELO(pmr);
|
||||
|
||||
if ((pmr->urev != 0.0) && (pmr->s != (temp_dbl = pmr->velo / fabs_urev)))
|
||||
{
|
||||
@@ -2612,6 +2690,7 @@ static long special(DBADDR *paddr, int after)
|
||||
pmr->velo = temp_dbl;
|
||||
db_post_events(pmr, &pmr->velo, DBE_VAL_LOG);
|
||||
}
|
||||
updateACCL_ACCSfromVELO(pmr);
|
||||
break;
|
||||
|
||||
/* new bvel: make sbak agree */
|
||||
@@ -2643,6 +2722,13 @@ static long special(DBADDR *paddr, int after)
|
||||
pmr->accl = 0.1;
|
||||
db_post_events(pmr, &pmr->accl, DBE_VAL_LOG);
|
||||
}
|
||||
updateACCSfromACCL(pmr);
|
||||
break;
|
||||
|
||||
/* new accs */
|
||||
case motorRecordACCS:
|
||||
db_post_events(pmr, &pmr->accs, DBE_VAL_LOG);
|
||||
updateACCLfromACCS(pmr);
|
||||
break;
|
||||
|
||||
/* new bacc */
|
||||
|
||||
@@ -69,6 +69,11 @@ menu(motorRMOD) {
|
||||
choice(motorRMOD_I,"In-Position")
|
||||
}
|
||||
|
||||
menu(motorACCSused) {
|
||||
choice(motorACCSused_Accl, "Accl")
|
||||
choice(motorACCSused_Accs, "Accs")
|
||||
}
|
||||
|
||||
include "menuOmsl.dbd"
|
||||
|
||||
recordtype(motor) {
|
||||
@@ -173,6 +178,18 @@ recordtype(motor) {
|
||||
interest(1)
|
||||
initial("0.2")
|
||||
}
|
||||
field(ACCS,DBF_DOUBLE) {
|
||||
prompt("Move Accel. (EGU/s^2)")
|
||||
promptgroup(GUI_COMMON)
|
||||
special(SPC_MOD)
|
||||
interest(1)
|
||||
}
|
||||
field(ACCU,DBF_MENU) {
|
||||
initial("Default")
|
||||
prompt("ACCS used")
|
||||
special(SPC_NOMOD)
|
||||
menu(motorACCSused)
|
||||
}
|
||||
field(BDST,DBF_DOUBLE) {
|
||||
prompt("BL Distance (EGU)")
|
||||
asl(ASL0)
|
||||
|
||||
Reference in New Issue
Block a user