EPICS Controls Argonne National Laboratory

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  2019  2020  2021  2022  2023  2024  2025  <2026 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  2025  <2026
<== Date ==> <== Thread ==>

Subject: Re: [Ext]RE: Help with continuous oscillation of a motor
From: Jesse Hopkins via Tech-talk <tech-talk at aps.anl.gov>
To: "Pearson, Matthew" <pearsonmr at ornl.gov>, Mark Rivers <rivers at cars.uchicago.edu>, EPICS Tech-Talk <tech-talk at aps.anl.gov>
Date: Mon, 9 Feb 2026 17:49:13 +0000
Hi Matt,

Thanks! Yes, for such a high duty cycle you may want to run the motor at lower than spec current to reduce heat.

In case it’s useful for anyone else in the community who stumbles on this thread, I ended up with a set of records for this that are:
record(ao, "$(P)Toast:$(D)High") {
  field(DESC, "Toast high limit")
  field(SCAN, "Passive")
}

record(ao, "$(P)Toast:$(D)Low") {
  field(DESC, "Toast low limit")
  field(SCAN, "Passive")
}

record(sseq, "$(P)Toast:$(D)Move") {
  field(DESC, "Toast motor")
  field(SCAN, "Passive")
  field(DOL1, "$(P)Toast:$(D)High.OVAL")
  field(WAIT1, "Wait")
  field(LNK1, "$(MOTOR).VAL CA")
  field(DOL2, "$(P)Toast:$(D)Low.OVAL")
  field(WAIT2, "Wait")
  field(LNK2, "$(MOTOR).VAL CA")
  field(LNK3, "$(P)Toast:$(D)Reset PP")
  field(DOL3, "1")
 }

 record(seq, "$(P)Toast:$(D)Reset") {
  field(DESC, "Reset toast")
  field(SCAN, "Passive")
  field(DOL0, "1")
  field(LNK0, "$(P)Toast:$(D)Move PP")
}

All the best.

- Jesse

 

----
Jesse Hopkins, PhD (he/him)
Director, BioCAT

Sector 18, Advanced Photon Source

Research Associate Professor, Illinois Tech

From: Pearson, Matthew <pearsonmr at ornl.gov>
Date: Friday, February 6, 2026 at 5:36 PM
To: Jesse Hopkins <jhopkins1 at illinoistech.edu>, Mark Rivers <rivers at cars.uchicago.edu>, EPICS Tech-Talk <tech-talk at aps.anl.gov>
Subject: RE: [Ext]RE: Help with continuous oscillation of a motor

Hi Jesse,

 

Great! Hopefully, the motor doesn’t end up toasted!

 

For the LNK1/2 fields, the link attribute should just be CA, like:

field(LNK1, "$(MOTOR).VAL CA")

 

I suspect the CA PP would evaluate to just CA internally, since it was the first one in the list.

 

Cheers,

Matt

 

From: Jesse Hopkins <jhopkins1 at illinoistech.edu>
Sent: Friday, February 6, 2026 5:57 PM
To: Pearson, Matthew <pearsonmr at ornl.gov>; Mark Rivers <rivers at cars.uchicago.edu>; EPICS Tech-Talk <tech-talk at aps.anl.gov>
Subject: [EXTERNAL] Re: [Ext]RE: Help with continuous oscillation of a motor

 

Hi Mark and Matt, Thanks for the suggestions! This is a bit easier, at least from a readability point of view, and more importantly doesn’t seem to be suffering from unexpected stops, at least in my limited testing so far. I’ll let it run for

Hi Mark and Matt,

 

Thanks for the suggestions! This is a bit easier, at least from a readability point of view, and more importantly doesn’t seem to be suffering from unexpected stops, at least in my limited testing so far. I’ll let it run for an hour or so and before declaring complete success.

 

I wanted to avoid even the 0.1 s delay of the scan if possible, but I wasn’t able to get the record to process itself, either with a LNK3 field or with a FLNK field pointing to itself. I also wanted to have the record passive on startup so that you can start it with a caput and stop it with the ABORT field. What I ended up with was a second helper record that it calls on LNK3 which then immediately calls the original record. Not sure if there’s a more elegant way of doing this, but this does seem to be working:

 

record(sseq, "$(P)Toast:$(D)Move") {

  field(DESC, "Toast motor")

  field(SCAN, "Passive")

  field(DOL1, "5")

  field(WAIT1, "Wait")

  field(LNK1, "$(MOTOR).VAL CA PP")

  field(DOL2, "-5")

  field(WAIT2, "Wait")

  field(LNK2, "$(MOTOR).VAL CA PP")

  field(LNK3, "$(P)Toast:$(D)Reset PP")

  field(DOL3, "1")

 }

 

 record(seq, "$(P)Toast:$(D)Reset") {

  field(DESC, "Reset toast")

  field(SCAN, "Passive")

  field(DOL0, "1")

  field(LNK0, "$(P)Toast:$(D)Move PP")

}

 

 

I’ll also just add a comment about acceleration profiles, in case it’s useful for someone who wants to do the same/similar thing later. We actually try to avoid any acceleration during the move. These moves are done at relatively slow speeds, and we use stages and motors that can handle a base speed equal to the target speed. We also don’t use backlash or encoder corrections to avoid any dithering at the end of the move, which might lead to a bit of drift over time but typically these are large samples so that’s okay. The goal is really to avoid hotspots (excess delivered dose) forming in any way shape or form.

 

All the best.

- Jesse

 

----
Jesse Hopkins, PhD (he/him)
Director, BioCAT

Sector 18, Advanced Photon Source

Research Associate Professor, Illinois Tech

From: Pearson, Matthew <pearsonmr at ornl.gov>
Date: Friday, February 6, 2026 at 4:41
PM
To: Mark Rivers <
rivers at cars.uchicago.edu>, EPICS Tech-Talk <tech-talk at aps.anl.gov>, Jesse Hopkins <jhopkins1 at illinoistech.edu>
Subject: [Ext]RE: Help with continuous oscillation of a motor

Hi,

 

For the ‘Wait’ to work, you’ll also need to use CA link attributes on LNK1 and LNK2 .

 

One reason for a controller based solution would be if you need a different acceleration profile from those supported for normal moves (for example Sin profile, instead of a standard S-curve or trapezoid). But if a standard profile works, it’s much easier via database logic.

 

Cheers,

Matt

 

From: Tech-talk <tech-talk-bounces at aps.anl.gov> On Behalf Of Mark Rivers via Tech-talk
Sent: Friday, February 6, 2026 5:01 PM
To: EPICS Tech-Talk <
tech-talk at aps.anl.gov>; Jesse Hopkins <jhopkins1 at illinoistech.edu>
Subject: [EXTERNAL] Re: Help with continuous oscillation of a motor

 

Also, this is a better link to the documentation: https://epics-modules.github.io/calc/sseqRecord.html Mark From: Mark Rivers <rivers@cars.uchicago.edu> Sent: Friday, February 6, 2026 3:59 PM To: EPICS Tech-Talk <tech-talk@aps.anl.gov>;

Also, this is a better link to the documentation:

 

https://epics-modules.github.io/calc/sseqRecord.html

 

Mark

 


From: Mark Rivers <rivers at cars.uchicago.edu>
Sent: Friday, February 6, 2026 3:59 PM
To: EPICS Tech-Talk <
tech-talk at aps.anl.gov>; Jesse Hopkins <jhopkins1 at illinoistech.edu>; Mark Rivers <rivers at cars.uchicago.edu>
Subject: Re: Help with continuous oscillation of a motor

 

Whoops, you need to delete this line:

 

  field(SCAN, "Passive")

 

Mark

 

 


From: Tech-talk <tech-talk-bounces at aps.anl.gov> on behalf of Mark Rivers via Tech-talk <tech-talk at aps.anl.gov>
Sent: Friday, February 6, 2026 3:56 PM
To: EPICS Tech-Talk <
tech-talk at aps.anl.gov>; Jesse Hopkins <jhopkins1 at illinoistech.edu>
Subject: Re: Help with continuous oscillation of a motor

 

Hi Jesse,

 

I think there is a simpler solution.  Use the sseq record rather than the seq record.  You then don't need the Check record at all.

 

https://www.slac.stanford.edu/grp/lcls/controls/global/doc/epics-modules/R3-14-12/std/std-R3-1_1-1/documentation/sseqRecord.html

 

The sseq record has WAIT fields that force the record to wait for one output link to complete before going to the next step.  You can just set WAIT1 and WAIT2 to "Wait".  Then it will first move one direction and then the other.  By setting SCAN=0.1 second it will then repeat the operation within 0.1 seconds.  You may be able to just FLNK to itself which would have no delay.

 

Here is a database that I think will work, though I have not tested it.

 

record(sseq, "$(P)Toast:$(D)Move") {

  field(DESC, "Toast motor")

  field(SCAN, "Passive")

  field(DOL1, "5")

  field(WAIT1, "Wait")

  field(LNK1, "$(MOTOR).VAL PP")

  field(DOL2, "-5")

  field(WAIT2, "Wait")

  field(LNK2, "$(MOTOR).VAL PP")

  field(SCAN, ".1 second")

 }

 

Mark

 


From: Tech-talk <tech-talk-bounces at aps.anl.gov> on behalf of Jesse Hopkins via Tech-talk <tech-talk at aps.anl.gov>
Sent: Friday, February 6, 2026 3:44 PM
To: EPICS Tech-Talk <
tech-talk at aps.anl.gov>
Subject: Help with continuous oscillation of a motor

 

Hi folks,

 

For certain experiments on our beamline we like to continuously oscillate the sample in the beam to spread out the x-ray dose and reduce radiation damage (we call this process “toasting”). For the past many years we’ve done this using control code specific to a (Parker) motor controller dedicated to these experiments. This controller is reaching end of life, and I’m hoping to get a more general solution to this that only depends on logic in an IOC, so that whenever we have to update controllers in the future we don’t have to rewrite this oscillation code.

 

I took a quick look through the archives of this list and some of the SynApps modules and didn’t see anything that would already do this for me, so I set out to make my own. My first attempt is to just use a combination of a calcout record and a seq record. The seq record uses a selection mask to either send the positive or negative endpoint to the motor record to start a move. The calcout record checks whether the motor is at the positive or negative endpoint and then sets the mask value for the seq and tells the seq to process. Then I set the motor FLNK to point to the calcout record PROC.

 

The problem that I’m running into is that the calcout seems to sometimes process a bit before the move is finished, or at least before the motor RBV has updated to the final position. You can start this process and it will run for a bit (5-10 cycles), and then it will stop. When it stops, if you check the calcout .A record, which gets its value from the motor RBV, it will say something like -4.9784, while the motor RBV at the end of the move is something like -5.00380 for a move to -5 (note: I haven’t yet thought about how to deal with deadband or step resolution in terms of determining which end the motor is at).

 

I’m wondering if there’s either another way to tell the calcout to process or if there’s a better way to do this that will create the desired effect. I should note that I don’t want to introduce any hardcoded delays anywhere because the point of this is a smooth turnaround so that the beam doesn’t linger and preferentially damage spots of the sample at the end of the scans (also, unreliable).

 

Here are my test seq and calcout records (with fixed values for positions for this test, but in the future could point to aouts that the user sets for each limit, for example):

 

record(seq, "$(P)Toast:$(D)Move") {

  field(DESC, "Toast motor")

  field(SCAN, "Passive")

  field(DOL0, "5")

  field(LNK0, "$(MOTOR).VAL PP")

  field(DOL1, "-5")

  field(LNK1, "$(MOTOR).VAL PP")

  field(SELM, "2")

  field(SHFT, "0")

  #field(SELN, "1")

  field(SELL, "$(P)Toast:$(D)Check.OVAL")

}

 

record(calcout, "$(P)Toast:$(D)Check") {

  field(DESC, "Check if toast motor moves")

  field(INPA, "$(MOTOR).RBV")

  #field(INPA, "0")

  field(INPB, "5")

  field(INPC, "-5")

  field(CALC, "((A >= B) || (A <= C)) ? 1: 0")

  field("OOPT", 3)

  field("DOPT", 1)

  field("OCAL", "(A >= B) ? 2 : 1")

  field("OUT", "$(P)Toast:$(D)Move PP")

}

 

 

If this issue is just a fundamental limitation of the motor record processing I was thinking the next thing to do would be to write a sequence record, but I haven’t messed with SNL before and it seemed a lot easier to try these standard EPICS records first.

 

Any advice would be appreciated.

 

All the best.

- Jesse

 

----
Jesse Hopkins, PhD (he/him)
Director, BioCAT

Sector 18, Advanced Photon Source

Research Associate Professor, Illinois Tech


Replies:
Re: [Ext]RE: Help with continuous oscillation of a motor Nariyoshi, Pedro via Tech-talk
References:
Help with continuous oscillation of a motor Jesse Hopkins via Tech-talk
Re: Help with continuous oscillation of a motor Mark Rivers via Tech-talk
Re: Help with continuous oscillation of a motor Mark Rivers via Tech-talk
Re: Help with continuous oscillation of a motor Mark Rivers via Tech-talk
RE: Help with continuous oscillation of a motor Pearson, Matthew via Tech-talk
Re: [Ext]RE: Help with continuous oscillation of a motor Jesse Hopkins via Tech-talk
RE: [Ext]RE: Help with continuous oscillation of a motor Pearson, Matthew via Tech-talk

Navigate by Date:
Prev: How to send caPutLog logs to Grafana Loki Afonso Haruo Carnielli Mukai via Tech-talk
Next: Re: Base 7.0.10 was released ? Han Lee 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  2025  <2026
Navigate by Thread:
Prev: RE: [Ext]RE: Help with continuous oscillation of a motor Pearson, Matthew via Tech-talk
Next: Re: [Ext]RE: Help with continuous oscillation of a motor Nariyoshi, Pedro 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  2025  <2026
ANJ, 19 Mar 2026 · Home · News · About · Talk · Base · Modules · Extensions ·
· Distributions · Download · Documents · Links · Licensing ·