EPICS Home

Experimental Physics and Industrial Control System


 
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  <20192020  2021  2022  2023  2024  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  <20192020  2021  2022  2023  2024 
<== Date ==> <== Thread ==>

Subject: RE: Multi-axis sequenced move using asynMotor pseudo axis
From: Mark Rivers via Tech-talk <[email protected]>
To: "'Pearson, Matthew R.'" <[email protected]>, David Vine <[email protected]>
Cc: "[email protected]" <[email protected]>
Date: Fri, 8 Mar 2019 19:15:04 +0000
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  <20192020  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  <20192020  2021  2022  2023  2024