Experimental Physics and Industrial Control System
I agree with Matt. What David wants is specific to a site-specific configuration and I don't think this belongs in the asyn motor driver, which is intended to be the general purpose driver for all sites.
• the motor record has many of the PVs that I would need to connect to and monitor with SNL already,
Your asyn motor driver does NOT have access to the motor record PVs! You would need to make new connections between the record and the driver.
• i don't need to define states and all the overhead that goes with
There is very little overhead associated with defining stages.
Here is a 160 line SNL program that implements a complicated coordinate transformation for one of our detector mounts. It only has 3 states, including init.
program IDD_LVP_Detector("P=13IDD:,PMT=pm1,PMR=pm2,PMC=pm3,X=m1,Y=m2,Z=m3,TZ=m4,TX=m5")
/* This sequencer program works with IDD_LVP_Detector.db. It implements the
* Large Volume Press detector system, where the detector has 2 rotation
* stages mounted on an X-Y-Z translation stage, and we want to treat it as a
* 2-theta circle centered on the sample. The pseudomotors are
* 2-Theta', and R, where R is the radius of the 2-theta circle.
* 2-Theta' can have both a vertical and horizontal component when using the
* T-cup geometry.
*
* Mark Rivers
* April 18, 2000
*/
%% #include <math.h>
/* The real motors */
double x_drive; assign x_drive to "{P}{X}.VAL"; monitor x_drive;
double y_drive; assign y_drive to "{P}{Y}.VAL"; monitor y_drive;
double z_drive; assign z_drive to "{P}{Z}.VAL"; monitor z_drive;
double x_rbv; assign x_rbv to "{P}{X}.RBV"; monitor x_rbv;
double y_rbv; assign y_rbv to "{P}{Y}.RBV"; monitor y_rbv;
double z_rbv; assign z_rbv to "{P}{Z}.RBV"; monitor z_rbv;
double tx_drive; assign tx_drive to "{P}{TX}.VAL"; monitor tx_drive;
double tx_rbv; assign tx_rbv to "{P}{TX}.RBV"; monitor tx_rbv;
double tz_drive; assign tz_drive to "{P}{TZ}.VAL"; monitor tz_drive;
double tz_rbv; assign tz_rbv to "{P}{TZ}.RBV"; monitor tz_rbv;
evflag x_drive_mon; sync x_drive x_drive_mon;
evflag x_rbv_mon; sync x_rbv x_rbv_mon;
evflag y_drive_mon; sync y_drive y_drive_mon;
evflag y_rbv_mon; sync y_rbv y_rbv_mon;
evflag z_drive_mon; sync z_drive z_drive_mon;
evflag z_rbv_mon; sync z_rbv z_rbv_mon;
evflag tx_drive_mon; sync tx_drive tx_drive_mon;
evflag tx_rbv_mon; sync tx_rbv tx_rbv_mon;
evflag tz_drive_mon; sync tz_drive tz_drive_mon;
evflag tz_rbv_mon; sync tz_rbv tz_rbv_mon;
/* Pseudomotors */
/* Pseudomotor theta = compound 2-theta */
double pmt_drive; assign pmt_drive to "{P}{PMT}.VAL"; monitor pmt_drive;
double pmt_move; assign pmt_move to "{P}{PMT}Move"; monitor pmt_move;
double pmt_rbv; assign pmt_rbv to "{P}{PMT}Readback";
/* Pseudomotor chi = compound chi */
double pmc_drive; assign pmc_drive to "{P}{PMC}.VAL"; monitor pmc_drive;
double pmc_move; assign pmc_move to "{P}{PMC}Move"; monitor pmc_move;
double pmc_rbv; assign pmc_rbv to "{P}{PMC}Readback";
/* Pseudomotor radius */
double pmr_drive; assign pmr_drive to "{P}{PMR}.VAL"; monitor pmr_drive;
double pmr_move; assign pmr_move to "{P}{PMR}Move"; monitor pmr_move;
double pmr_rbv; assign pmr_rbv to "{P}{PMR}Readback";
evflag pmt_move_mon; sync pmt_move pmt_move_mon;
evflag pmc_move_mon; sync pmc_move pmc_move_mon;
evflag pmr_move_mon; sync pmr_move pmr_move_mon;
/* Geometry offsets */
double xzero; assign xzero to "{P}{PMR}C1"; monitor xzero;
double yzero; assign yzero to "{P}{PMR}C2"; monitor yzero;
double zzero; assign zzero to "{P}{PMR}C3"; monitor zzero;
double a; assign a to "{P}{PMT}C1"; monitor a;
evflag xzero_mon; sync xzero xzero_mon;
evflag yzero_mon; sync yzero yzero_mon;
evflag zzero_mon; sync zzero zzero_mon;
evflag a_mon; sync a a_mon;
int synch; assign synch to "{P}{PMR}synch"; monitor synch;
int motors_stopped; assign motors_stopped to "{P}{PMR}Done";
monitor motors_stopped;
evflag motors_stopped_mon; sync motors_stopped motors_stopped_mon;
double dtor; /* Degrees to radians */
double tz;
double tx;
double b;
double c;
ss LVPdetector {
state init {
when() {
dtor = 4. * atan(1.) / 180.;
efSet(tx_rbv_mon); /* Force calculation first time through */
efClear(pmt_move_mon); /* Don't move motors on initialization */
efClear(pmc_move_mon);
efClear(pmr_move_mon);
} state monitor_changes
}
state monitor_changes {
when(efTestAndClear(pmt_move_mon) ||
efTestAndClear(pmc_move_mon) ||
efTestAndClear(pmr_move_mon)) {
/* 2-theta', chi' or R been driven, drive real motors */
tx = pmt_drive*dtor;
tz = pmc_drive*dtor;
x_drive = -pmr_drive*sin(tx)*sin(tz) - a*(1.-cos(tz)) - xzero;
pvPut(x_drive);
y_drive = pmr_drive*sin(tx)*cos(tz) + a*sin(tz) - yzero;
pvPut(y_drive);
z_drive = pmr_drive*cos(tx) - zzero;
pvPut(z_drive);
tx_drive = tx/dtor; pvPut(tx_drive);
tz_drive = tz/dtor; pvPut(tz_drive);
} state monitor_changes
when(efTestAndClear(xzero_mon) ||
efTestAndClear(yzero_mon) ||
efTestAndClear(zzero_mon) ||
efTestAndClear(a_mon)) {
/* A geometry constant has changed, update the readbacks */
} state update_readbacks
when(efTestAndClear(x_rbv_mon) ||
efTestAndClear(y_rbv_mon) ||
efTestAndClear(z_rbv_mon) ||
efTestAndClear(tx_rbv_mon)||
efTestAndClear(tz_rbv_mon)) {
/* The motor readbacks have changed, update R, 2-theta' readbacks */
} state update_readbacks
when(synch == 1) {
/* Assume that 2-theta, R are correct, and that we are in
* the diffraction condition. Compute X0, Y0, Z0 */
tx = pmt_drive*dtor;
tz = pmc_drive*dtor;
xzero = -pmr_drive * sin(tx) * sin(tz) - a * (1. - cos(tz)) - x_drive;
yzero = pmr_drive * sin(tx) * cos(tx) + a * sin(tz) - y_drive;
zzero = pmr_drive * cos(tx) - z_drive;
pvPut(xzero);
pvPut(yzero);
pvPut(zzero);
synch = 0; pvPut(synch);
} state monitor_changes
}
state update_readbacks {
when () {
/* Something has changed which requires recomputing readback
* positions */
pmt_rbv = tx_rbv;
pvPut(pmt_rbv);
pmc_rbv = tz_rbv;
pvPut(pmc_rbv);
tx = pmt_rbv*dtor;
tz = pmc_rbv*dtor;
c = (x_rbv + xzero) * (x_rbv + xzero) +
(y_rbv + yzero) * (y_rbv + yzero) +
(z_rbv + zzero) * (z_rbv + zzero) -
2. * a * a * (1. - cos(tz));
b = 2. * a * sin(tx) * sin(tz);
pmr_rbv = (-b + sqrt(b*b + 4.*c)) / 2.;
pvPut(pmr_rbv);
} state monitor_changes
}
}
I don't think you could do this logic in an asyn driver with significantly fewer lines of code.
Mark
-----Original Message-----
From: [email protected] <[email protected]> On Behalf Of Pearson, Matthew R. via Tech-talk
Sent: Friday, March 8, 2019 12:39 PM
To: David Vine <[email protected]>
Cc: [email protected]
Subject: Re: Multi-axis sequenced move using asynMotor pseudo axis
Hi David,
The asyn motor driver functions are really designed to work within the scope of one controller. If all the axes were on one controller then I suppose it could be done within the axis::home() function, but then you’re turning a general purpose motor driver into an application specific driver. I’m not sure how it would work across multiple controllers, unless you created a new asyn driver that connected to each of the asyn ports for each controller, and a special homing function that dealt with the required logic.
Using the database or SNL method would be a much easier approach. For the SNL approach you needn't have to have many states, just a ‘Idle’ and ‘Run’ state (and possibly an ‘Error’ state), with everything happening in the ‘Run’ state. Although, it would work better to have more states, such as ‘PreMove’ (that moves XYZ all in one go) and a ‘PostMove’ (moves XYZ back).
Cheers,
Matt
> On Mar 8, 2019, at 1:04 PM, David Vine via Tech-talk <[email protected]> wrote:
>
> Thanks Matthew and Kevin for your input, much appreciated.
>
> I find the database implementation difficult to read and maintain. The SNL is more readable but there's a lot of boilerplate in setting up the states and connecting to PVs.
>
> Implementing the logic from within asynMotor has the following advantages:
> • readable and commented code,
> • the motor record has many of the PVs that I would need to connect to and monitor with SNL already,
> • i don't need to define states and all the overhead that goes with
> it because the axis::move and axis::home can implement all the logic I don't know if it makes sense but if asyn could implement an asynChannelAccessPort I think it would simplify this problem a lot.
>
> On Fri, Mar 8, 2019 at 8:28 AM Peterson, Kevin M. <[email protected]> wrote:
> David,
>
> I find SNL programs to be cleaner than pure database implementations
> for situations like this. The SNL program might be more work
> initially, but it is often easier to maintain, especially if the
> sequenced move procedure needs to become more complicated in the
> future. Breaking the implementation into well-defined states makes it
> easier for others to understand, troubleshoot, and modify the code.
>
> Kevin
>
> On 3/7/19 10:49 AM, David Vine via Tech-talk wrote:
> > Hi all,
> >
> > I'm looking for the cleanest way to implement a sequence of moves of
> > between different physical axes but hide it from the user so it
> > appears as just a single pseudo motor axis.
> >
> > For example, I want to home axis A but to avoid a collision I need
> > to move axes XYZ to a particular location first, then home A, and
> > then move XYZ back to their original position at the end of the homing procedure.
> > And that sequence should occur just clicking the home PV of A.
> >
> > I would like to set up a pseudo motor driver using an asynMotor
> > driver and implement the logic there. Is it possible to do channel
> > access calls from within an asynMotor driver? I couldn't find any
> > examples. The physical axes are connected across three galil controllers.
> >
> > Implementing the logic within an SNL program would work but it
> > seemed simpler to do it within the motor driver.
> >
> > Thanks,
> > David
> > --
> > Best regards,
> > David Vine
> > (925) 326 7503
> > [email protected] <mailto:[email protected]>
> >
> > 5750 Imhoff Drive, Suite I | Concord, CA 94520 | USA
> > <https://maps.google.com/?q=5750+Imhoff+Drive,+Suite+I%C2%A0+%7C%C2%
> > A0+Concord,+CA+94520%C2%A0+%7C%C2%A0+USA&entry=gmail&source=g>
> >
> > http://www.Sigray.com <http://www.sigray.com/>
> >
> > This e-mail and any attachments are provided for the sole use of the
> > intended recipient(s), and may contain information that is
> > confidential, privileged, proprietary or otherwise protected by law.
> > If you are not the intended recipient of this message, you are not
> > authorized to read, print, retain, copy, forward or otherwise
> > disseminate this message or any part of it. If you have received
> > this e-mail in error, please notify the sender immediately by reply
> > e-mail and delete the original message from your mail system. Thank you.
> >
> >
>
>
>
> --
> Best regards,
> David Vine
> (925) 326 7503
> [email protected]
>
>
> 5750 Imhoff Drive, Suite I | Concord, CA 94520 | USA
>
> http://www.Sigray.com
>
>
> This e-mail and any attachments are provided for the sole use of the intended recipient(s), and may contain information that is confidential, privileged, proprietary or otherwise protected by law. If you are not the intended recipient of this message, you are not authorized to read, print, retain, copy, forward or otherwise disseminate this message or any part of it. If you have received this e-mail in error, please notify the sender immediately by reply e-mail and delete the original message from your mail system. Thank you.
>
>
> <image001.png>
- References:
- Multi-axis sequenced move using asynMotor pseudo axis David Vine via Tech-talk
- Re: Multi-axis sequenced move using asynMotor pseudo axis Peterson, Kevin M. via Tech-talk
- Re: Multi-axis sequenced move using asynMotor pseudo axis David Vine via Tech-talk
- Re: Multi-axis sequenced move using asynMotor pseudo axis Pearson, Matthew R. via Tech-talk
- Navigate by Date:
- Prev:
Re: CANbus EPICS support Dr. Bastian Löher via Tech-talk
- Next:
generalTime/epicsTimeGetCurrent and casr questions Layne (US), William C via Tech-talk
- Index:
1994
1995
1996
1997
1998
1999
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
<2019>
2020
2021
2022
2023
2024
- Navigate by Thread:
- Prev:
Re: Multi-axis sequenced move using asynMotor pseudo axis Pearson, Matthew R. via Tech-talk
- Next:
CANbus EPICS support Gofron, Kazimierz via Tech-talk
- Index:
1994
1995
1996
1997
1998
1999
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
<2019>
2020
2021
2022
2023
2024