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: Support for piezo controller nanoFAKTUR EBD-060310
From: LiangChih Chiang via Tech-talk <tech-talk at aps.anl.gov>
To: Torsten Bögershausen <tboegi at edom.se>
Cc: "tech-talk at aps.anl.gov" <tech-talk at aps.anl.gov>
Date: Wed, 11 Feb 2026 10:47:30 +0800
Hi, thank you Torsten for replying.

>> But in the CNEN field of motor record is 0(Disable).
>CNEN is updated from the status of the controller.
>Does the code in the poll() function update the
>"motorClosedLoop_" parameter ?
You're right.
I added the code to update "motorClosedLoop_" parameter in poll(),
and I added the member function setClosedLoop(bool closedLoop).
Basically, it works.
However, everytime I move the motor(piezo stage),
the CNEN of motor record will be switched to 0(Disable).


>> I got value 0 from  motorResolution_ parameter. why?
>motorRecResolution_ is your friend. 
Getting resolution from motorRecResolution_ parameter works. 

>myStatus = c_p_->getDoubleParam(channel_, c_p_->motorResolution_, &res);
>And see that myStatus is not asynSuccess,right ?
myStatus is 10. Very strange. It's outside the valid values of asynStatus.
res value is 0.

>> There is no "home" concept in this piezo controller.
>> So I have no way to implement the asynMotorAxis::home function, am I right?
>Is it called reference ?
>Then that can be mapped to "home()"
No such things.

The piezo system(controller and stage) uses SGS(Strain Gauge Sensor) to tell the position.
In some sense, it's like an absolute encoder.


On Tue, Feb 10, 2026 at 4:44 PM Torsten Bögershausen <tboegi at edom.se> wrote:


On 2026-02-10 08:51, LiangChih Chiang wrote:
> Hello, EPICS mates, thanks for the help.
>
> The Model 3 driver implementation of nanoFaktur EBD-060310 piezo
> controller is kind of working now.
> The attachment files include source code.and IOC startup files.
>
> I still have some questions. Hope you can provide suggestions.
>
>
> 1.
> I thought motorClosedLoop_ is mapped to CNEN, isn't it?
>

Yes, that is what most (all ?) model 3 driver do
> I set motorClosedLoop_ to 1 in code, as following:
> setIntegerParam(c_p_->motorClosedLoop_, 1);
>
> But in the CNEN field of motor record is 0(Disable).
CNEN is updated from the status of the controller.
Does the code in the poll() function update the
"motorClosedLoop_" parameter ?

>
>
> 2.
> Can I set UEIP field of motor record in driver code?
>
> If UEIP is 0, the RRBV won't update even REP is updated continuously.
 > > I use the asyn_motor.db in motor-R6-11.
That's pretty old.

> The motor record in this .db doesn't have UEIP field.
> So I set it in a .doAfterIocInit file.
>
>
> 3.
> The MRES field of motor record to 0.000001 in ioc startup file.
>
> When I set VAL of motor record to 1.234,
> I will get "position" value 1234000
> in asynMotorAxis::move(double position, int relative, double
> minVelocity, double maxVelocity, double acceleration);
>
> Then I need the MRES value to do the conversion,
> because I need to send the value "1.234" to the controller.
>
> Why the following code returns the value 0 instead the wanted 0.000001?
>      double res = 0.000001;  // resolution
>      c_p_->getDoubleParam(channel_, c_p_->motorResolution_, &res);
We can call that on ol' bug.
See even
<https://github.com/epics-modules/motor/blob/master/motorApp/Db/asyn_motor.db>
.... follow the flow .... and
motorRecResolution_
is your friend. However, since that is processed through records,
be prepared to read 0.0 a couple of times.
myStatus = c_p_->getDoubleParam(channel_, c_p_->motorResolution_, &res);
And see that myStatus is not asynSuccess,right ?

>
>
> 4.
> There is no "home" concept in this piezo controller.
> So I have no way to implement the asynMotorAxis::home function, am I right?

Is it called reference ?
Then that can be mapped to "home()"
>
>
>
>
>
> On Sat, Feb 7, 2026 at 12:08 AM Torsten Bögershausen <tboegi at edom.se
> <mailto:tboegi at edom.se>> wrote:
>
>     Hej again,
>
>     Why are the RMP and REP fields integer ?
>     The "real world encoders" typically count in integer,
>     and so far the int32 had been enough.
>     Even if we today have encoders with more bits,
>     these are typically attached to the motor controller
>     and handled there.
>
>     The RMP field counts steps.
>     It was designed for a stepper motor, and even here
>     32 bit where both enough
>     (and that is what we have before int64 became available)
>     The motorRecord itself uses the step in RMP to prevent
>     commanding a motion the will end up on the same step.
>     Moving from 0.050 to 0.051 is prevented, when MRES is 0.05
>
>     For a piezo (or other modern controllers) we don't need this
>     step-size, so that the motorRecord has  got the SPDB field,
>     Set Point Dead Band.
>
>     For the controllers which are in use here, most of them
>     communicate in EGU.
>
>     For that reason I made a patch, where the value
>     "motorPosition_" from the driver is copied into
>     the DRBV field without conversion through integers.
>
>     The driver needs this patch:
>     <https://github.com/EuropeanSpallationSource/m-epics-ethercatmc/
>     blob/master/ethercatmcApp/src/ethercatmcIndexerAxis.cpp#L81..#L83
>     <https://github.com/EuropeanSpallationSource/m-epics-ethercatmc/
>     blob/master/ethercatmcApp/src/ethercatmcIndexerAxis.cpp#L81..%23L83>>
>
>
>     The motor package itself is here:
>     <https://github.com/EuropeanSpallationSource/motor/releases/tag/
>     v7.2.8.1-ESS <https://github.com/EuropeanSpallationSource/motor/
>     releases/tag/v7.2.8.1-ESS>>
>
>     BR
>     /Torsten
>
>
>     On 2026-02-06 14:20, LiangChih Chiang wrote:
>      > Hi, Torsten, thanks for replying.
>      >
>      >  >Using epicsPrintf (or even printf) should be forbidden in
>      >  >these kind of driver code.
>      > ok. I'll fix it.
>      >
>      >  >>1.
>      >  > pC_->motorPosition_ is an int, used as an index
>      >  > motorPosition is a double
>      > You're right. My mistake.
>      >
>      > Another question follows:
>      > "cainfo <motor_record>.REP and .RMP" will get DBF_LONG.
>      > Why aren't they DBF_DOUBLE?
>      >
>      >
>      >  >>3.
>      >  >>The values of position and voltage from the controller are
>     float values.
>      >  >>When setting, say 2.123456, to motorEncoderPosition, it will
>     become 2
>      > (which is an int).
>      >  >This is depending on MRES in the motorRecord.
>      >  >If you set it to 1.0 (or not at all, the the fallback is 1.0)
>      >  >all values are rounded into integer.
>      >  >The trick is to set MRES to 0.000001 or so and compensate
>      >  >this in the driver (multipy with 1000000)
>      >
>      > Yes. You're right.
>      > I'll try.
>      >
>      >
>      >  >For the open-loop-voltage:
>      >  >You probably want an own asyn-parameter for this.
>      > I'll consider it.
>      > However, the chance of this piezo controller in open-loop mode is
>      > extremely slim.
>      >
>      > How to support two modes(closed-loop and open-loop) in Model 3
>     driver?
>      > In closed-loop mode, VAL and RBV mean position(unit um)?
>      > In open-loop mode, VAL and RBV mean voltage?
>      >
>      > On Fri, Feb 6, 2026 at 5:51 PM Torsten Bögershausen
>     <tboegi at edom.se <mailto:tboegi at edom.se>
>      > <mailto:tboegi at edom.se <mailto:tboegi at edom.se>>> wrote:
>      >
>      >     Hej LiangChih Chiang,
>      >     thanks for asking.
>      >
>      >     Before going into your questions, please allow one comment:
>      >     Using epicsPrintf (or even printf) should be forbidden in
>      >     these kind of driver code.
>      >     Please consider to us asynPrint instead.
>      >     Especially things like
>      >     #ifdef DEBUG
>      >                 printf("Warning: un-handled param data format:
>      >     #endif
>      >     Could be better coded as
>      >         asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
>      >             "%s: Warning....\n",
>      >             __FUNCTION__);
>      >         }
>      >
>      >     (If you write Warning or Err: or something is more a matter
>     of taste)
>      >     But in any way you want to know if things go bad much later,
>      >     after firmware updates, changes in the IOC, glitches here and
>     the )
>      >     Having said that, finishing my review, which may read
>     unintentionally
>      >     hard, lets digg into the questions.
>      >
>      >        1.
>      >       > In asynMotorController.h, the data type of motorPosition_
>      >       > and motorEncoderPosition_ are ints.
>      >
>      >     A call inside the axis class looks like this:
>      >
>      >     asynMotorAxis::setDoubleParam(pC_->motorPosition_,
>     motorPosition);
>      >
>      >     pC_->motorPosition_ is an int,
>      >     saying which asynparameter we ar writing to.
>      >
>      >     motorPosition is a double, saying where the motor should be,
>      >     according to the controller.
>      >
>      >     motorEncoderPosition_ is the value coming from the sensor
>     inside the
>      >     controller.
>      >
>      >     Example:
>      >     the MCS2 from Smaract reads motorPosition like this:
>      >        // Read the target position
>      >         snprintf(pC_->outString_,sizeof(pC_->outString_)-1,
>      >           ":CHAN%d:POS:TARG?", axisNo_);
>      >
>      >     And encoderPosition like this:
>      >            // read the actual position as measured by the sensor
>      >             snprintf(pC_->outString_,sizeof(pC_->outString_)-1,
>      >             ":CHAN%d:POS?", axisNo_);
>      >
>      >     3.
>      >       > The values of position and voltage from the controller
>     are float
>      >     values.
>      >       > When setting, say 2.1234...
>      >     This is depending on MRES in the motorRecord.
>      >     If you set it to 1.0 (or not at all, the the fallback is 1.0)
>      >     all values are rounded into integer.
>      >     The trick is to set MRES to 0.000001 or so and compensate
>      >     this in the driver (multipy with 1000000)
>      >
>      >
>      >     For the open-loop-voltage:
>      >     You probably want an own asyn-parameter for this.
>      >
>      >     /BR Torsten
>      >
>      >
>      >
>      >     On 2026-02-06 08:48, LiangChih Chiang via Tech-talk wrote:
>      >      > Hello, EPICS mates,
>      >      >
>      >      > I started to implement the “Model 3” driver for nanoFaktur
>      >     EBD-060310
>      >      > piezo controller.
>      >      > The attached files(.cpp and .h) are the work-in-progress
>     source
>      >     code.
>      >      > Not finished yet.
>      >      >
>      >      > I have some questions.
>      >      >
>      >      > 1.
>      >      > In asynMotorController.h, the data type of motorPosition_
>      >      > and motorEncoderPosition_ are ints.
>      >      >
>      >      > But in derived class of asynMotorcontroller(like
>      >      > smarActMCSMotorDriver.cpp and ACRMotorDriver.cpp),
>      >      > the function setDoubleParam is used to set the above
>     parameters.
>      >      >
>      >      > Why is that?
>      >      >
>      >      > 2.
>      >      > I can read the position(unit um, range 0 to 40) and
>     voltage(unit
>      >     volts,
>      >      > range -30 to 130) from the controller.
>      >      > But which one should I set to motorPosition_and
>      >     motorEncoderPosition_?
>      >      > I don't quite understand.
>      >      >
>      >      > 3.
>      >      > The values of position and voltage from the controller are
>     float
>      >     values.
>      >      > When setting, say 2.123456, to motorEncoderPosition, it will
>      >     become 2
>      >      > (which is an int).
>      >      >
>      >      > How to handle this situation?
>      >      > Should I do some kind of transformation? For example,
>     multiply by
>      >     1000,000?
>      >      >
>      >      > 4.
>      >      > In the member function: asynStatus poll(bool* moving_p),
>      >      > I need to set the moving/done status of the stage to moving_p
>      >      > and motorStatusDone_.
>      >      >
>      >      > But there is no such exact suitable command provided by thhe
>      >     controller.
>      >      > A possible candidate is "get on-target status" meaning in
>     closed-
>      >     loop
>      >      > mode(servo ON),
>      >      > whether the position(from sensor) approached the set
>     target or not.
>      >      >
>      >      > 5.
>      >      > The controller has two modes:
>      >      > closed-loop mode(servo ON), users set the desired
>     potion(unit um).
>      >      > open-loop mode(servo OFF), uses set the voltage(unit volts).
>      >      >
>      >      > What should I set to motorPosition_?
>      >      > I think it should be something like "motor pulse".
>      >      >
>      >      > what should I set to motorEncoderPosition_.?
>      >      > I think it should be something like "encoder value".
>      >      >
>      >      >
>      >      > ps
>      >      >
>      >      > The controller uses binary communication protocol.
>      >      > The following example is to read the position(in um) of
>     channel 0:
>      >      > hexadecimal bytes in little-endian:
>      >      > 10 00 01 20 02 00 20 00 00 ac 01 00 00 00 00 fe
>      >      >
>      >      > 10 00: total length, 16 bytes
>      >      > 01 20: command ID, 0x2001 means "get position"
>      >      > 02 00: custom ID, used to distinguish different client
>     programs.
>      >      > 20: option, 0x20 means "read"
>      >      > 00: sequence number, Used in very long responses. Not used in
>      >     commands.
>      >      > 00: interface id, RS-232 or USB or Ethernet. Not used in
>     commands.
>      >      > ac: header checksum
>      >      > 01: data format, 01 means 32-bit unsigned int
>      >      > 00 00 00 00: data, channel 0
>      >      > fe: checksum
>      >      >
>      >      > The  response:
>      >      > 13 00 01 20 02 00 10 00 01 b8 00 00 02 70 74 6a 3e
>      >      >
>      >      > 13 00: total length, 19 bytes
>      >      > 01 20: command ID, 0x2001 means "get position"
>      >      > 02 00: custom ID, used to distinguish different client
>     programs.
>      >      > 10: option, 0x10 means "final, no more".
>      >      > 00: sequence number,
>      >      > 01: interface id, 0x01 means RS-232.
>      >      > b8: header checksum
>      >      > 00: data format, 00 means 8-bit unsigned int
>      >      > 00: data, channel 0
>      >      > 02: data format, 02 means float
>      >      > 70 74 6a 3e: data, 0.228960 (position in um)
>      >      > 3e: checksum
>      >      >
>      >      >
>      >      > Any suggestions and responses are appreciated.
>      >      > Thank you.
>      >      >
>      >      >
>      >      > On Thu, Apr 24, 2025 at 5:31 AM Mark Rivers
>      >     <rivers at cars.uchicago.edu <mailto:rivers at cars.uchicago.edu>
>     <mailto:rivers at cars.uchicago.edu <mailto:rivers at cars.uchicago.edu>>
>      >      > <mailto:rivers at cars.uchicago.edu
>     <mailto:rivers at cars.uchicago.edu>
>      >     <mailto:rivers at cars.uchicago.edu
>     <mailto:rivers at cars.uchicago.edu>>>> wrote:
>      >      >
>      >      >       * I think I would need to write the EPICS motor driver
>      >     module for
>      >      >         it.____
>      >      >
>      >      >     __ __
>      >      >
>      >      >     That is correct.  You should write a “Model 3” driver,
>      >     meaning it is
>      >      >     a C++ driver derived from the base classes
>      >     asynMotorController and
>      >      >     asynMotorAxis.____
>      >      >
>      >      >     __ __
>      >      >
>      >      >     I just looked at the manual for the nanoFAKTUR
>     EBD-060310.
>      >     It uses
>      >      >     a non-standard binary communications protocol, not ASCII
>      >     strings.
>      >      >     That is unusual, most controllers use ASCII
>     communication.____
>      >      >
>      >      >     __ __
>      >      >
>      >      >     The driver you suggested as a model, https://
>     github.com/ <https://github.com/>
>      >     epics-motor/ <https://github.com/epics-motor/ <https://
>     github.com/epics-motor/>>
>      >      >     motorPIGCS2 <https://urldefense.us/v3/__https:/
>     github.com/ <https://urldefense.us/v3/__https:/github.com/>
>      >     epics- <https://urldefense.us/v3/__https:/github.com/epics-
>     <https://urldefense.us/v3/__https:/github.com/epics->>
>      >      >     motor/motorPIGCS2__;!!G_uCfscf7eWS!
>      >      >
>      >     
>       YgABnMrr4ouWf_GcXAuVe7LU-96lfvWFNG96utdBA3mgcrk9dBsWVY7JQtxclFMQQYwD2Zz0RmrbQGad8OJXFPc$>  is fairly complex because of the class hierarchy, so you might want to start with something simpler as your example. ____
>      >      >
>      >      >     __ __
>      >      >
>      >      > https://github.com/epics-motor/motorSmarAct/blob/master/
>     <https://github.com/epics-motor/motorSmarAct/blob/master/>
>      >     smarActApp/ <https://github.com/epics-motor/motorSmarAct/
>     blob/ <https://github.com/epics-motor/motorSmarAct/blob/>
>      >     master/smarActApp/>
>      >      >     src/smarActMCSMotorDriver.cpp <https://urldefense.us/
>     v3/ <https://urldefense.us/v3/>
>      >     __https:// <https://urldefense.us/v3/__https:// <https://
>     urldefense.us/v3/__https://>>
>      >      > github.com/epics-motor/motorSmarAct/blob/master/
>     smarActApp/src/ <http://github.com/epics-motor/motorSmarAct/blob/
>     master/smarActApp/src/>
>      >     <http://github.com/epics-motor/motorSmarAct/blob/master/
>     smarActApp/src/ <http://github.com/epics-motor/motorSmarAct/blob/
>     master/smarActApp/src/>>
>      >      >     smarActMCSMotorDriver.cpp__;!!G_uCfscf7eWS!YLctRUSDiyz4K-
>      >      >
>      >     
>       t8_BzT33ew7q6EOnMR2oSaoEqf7fY5hpd5mII4cyq4pP6Gt3vwMPp1s38VSS7kXyY4shD2qrU$>____
>      >      >
>      >      >     __ __
>      >      >
>      >      >     That uses ASCII communication, but it should not be
>     too hard
>      >     to take
>      >      >     the concepts and use binary communication.____
>      >      >
>      >      >     __ __
>      >      >
>      >      >     Mark____
>      >      >
>      >      >     __ __
>      >      >
>      >      >     __ __
>      >      >
>      >      >     __ __
>      >      >
>      >      >     __ __
>      >      >
>      >      >     __ __
>      >      >
>      >      >     *From:*Tech-talk <tech-talk-bounces at aps.anl.gov
>     <mailto:tech-talk-bounces at aps.anl.gov> <mailto:tech- <mailto:tech->
>      > talk-bounces at aps.anl.gov <mailto:talk-bounces at aps.anl.gov>>
>     <mailto:tech-talk- <mailto:tech-talk-> <mailto:tech-talk-
>     <mailto:tech-talk->>
>      >      > bounces at aps.anl.gov <mailto:bounces at aps.anl.gov>
>     <mailto:bounces at aps.anl.gov <mailto:bounces at aps.anl.gov>>>> *On
>     Behalf Of
>      >     *LiangChih Chiang via Tech-talk
>      >      >     *Sent:* Wednesday, April 23, 2025 1:41 AM
>      >      >     *To:* tech-talk at aps.anl.gov <mailto:tech-
>     talk at aps.anl.gov> <mailto:tech-talk at aps.anl.gov <mailto:tech-
>     talk at aps.anl.gov>>
>      >     <mailto:tech-talk at aps.anl.gov <mailto:tech-talk at aps.anl.gov>
>     <mailto:tech-talk at aps.anl.gov <mailto:tech-talk at aps.anl.gov>>>
>      >      >     *Subject:* Support for piezo controller nanoFAKTUR
>     EBD-060310____
>      >      >
>      >      >     __ __
>      >      >
>      >      >     Hello, EPICS mates,____
>      >      >
>      >      >     __ __
>      >      >
>      >      >     I need to control a piezo sage with the controller
>     nanoFAKTUR
>      >      >     EBD-060310.____
>      >      >
>      >      >     This is my first time using this controller.____
>      >      >
>      >      >     I searched and couldn't find the EPICS support module
>     for it.____
>      >      >
>      >      >     __ __
>      >      >
>      >      >     I think I would need to write the EPICS motor driver
>     module
>      >     for it.____
>      >      >
>      >      >     __ __
>      >      >
>      >      >     What module code would you recommend me to use as a
>     starter
>      >      >     reference?____
>      >      >
>      >      >     For example, something like ____
>      >      >
>      >      >     EPICS motor drivers for Physik Instrumente GCS2
>     (General Command
>      >      >     Set) compatible controllers____
>      >      >
>      >      > https://github.com/epics-motor/motorPIGCS2 <https://
>     github.com/epics-motor/motorPIGCS2> <https://github.com/ <https://
>     github.com/>
>      >     epics-motor/motorPIGCS2> <https://urldefense.us/ <https://
>     urldefense.us/> <https://
>      > urldefense.us/ <http://urldefense.us/>>
>      >      >     v3/__https:/github.com/epics-motor/motorPIGCS2__;
>     <http://github.com/epics-motor/motorPIGCS2__;>!!
>      >     G_uCfscf7eWS <http://github.com/epics-motor/motorPIGCS2__;
>     <http://github.com/epics-motor/motorPIGCS2__;>!!
>      >     G_uCfscf7eWS>!
>      >      >
>      >     
>       YgABnMrr4ouWf_GcXAuVe7LU-96lfvWFNG96utdBA3mgcrk9dBsWVY7JQtxclFMQQYwD2Zz0RmrbQGad8OJXFPc$> ____
>      >      >
>      >      >     __ __
>      >      >
>      >      >     __ __
>      >      >
>      >
>


Replies:
Re: Support for piezo controller nanoFAKTUR EBD-060310 Torsten Bögershausen via Tech-talk
References:
Re: Support for piezo controller nanoFAKTUR EBD-060310 LiangChih Chiang via Tech-talk
Re: Support for piezo controller nanoFAKTUR EBD-060310 Torsten Bögershausen via Tech-talk
Re: Support for piezo controller nanoFAKTUR EBD-060310 LiangChih Chiang via Tech-talk
Re: Support for piezo controller nanoFAKTUR EBD-060310 Torsten Bögershausen via Tech-talk
Re: Support for piezo controller nanoFAKTUR EBD-060310 LiangChih Chiang via Tech-talk
Re: Support for piezo controller nanoFAKTUR EBD-060310 Torsten Bögershausen via Tech-talk

Navigate by Date:
Prev: Re: Question: CA monitor event and timestamp handling on compress record reset Kim, Kukhee via Tech-talk
Next: How to use the RVEL field of the motor record Mathis, Stefan 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: Support for piezo controller nanoFAKTUR EBD-060310 Torsten Bögershausen via Tech-talk
Next: Re: Support for piezo controller nanoFAKTUR EBD-060310 Torsten Bögershausen 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 ·