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  <20242025  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  <20242025 
<== Date ==> <== Thread ==>

Subject: Re: Re: Re: Re: RE: Re: autoConnect could not connect when reading a register by modbus relative addressing
From: Zhibang Shen via Tech-talk <tech-talk at aps.anl.gov>
To: "Mark Rivers" <rivers at cars.uchicago.edu>
Cc: "tech-talk at aps.anl.gov" <tech-talk at aps.anl.gov>
Date: Sun, 1 Dec 2024 09:53:13 +0800 (GMT+08:00)

Dear Mark,


It is exactly the problem of setting motorStatusDone_.


I set the motorStatusDone_ in my previous code. But the logic is wrong.


I read the register and get a bit indicating the motor is moving or not. The bit is 1 when it is moving, and 0 when it stops.


I should convert it into a status being 0 when it is moving, and then set it to motorStatusDone_.



// Read the moving status of this motor

//

status = pC_->readReg16(STATUS, &read_val, DEFAULT_CONTROLLER_TIMEOUT);

// Done logic

in_motion_from_the_register = ((read_val & 0x4) >> 2);  // bit 2 is set to 1 when the motor is in motion.

*moving =  done? true:false;

done = *moving? 0:1;

// motorStatusDone_ should be set 0 when the motor is moving

//                            and 1 when the moving is done

setIntegerParam(pC_->motorStatusDone_, done);

printf("done is %d\n", done);



Now it can work well.


I cannot make this without your advices and patient responses. Thank you so much for your suggestions and generous help!



Best regards,

Zhibang


--------------
发件人: "Mark Rivers" <rivers at cars.uchicago.edu>
发送时间: 2024-11-30 22:47:39 
收件人: "shenzb at ihep.ac.cn" <shenzb at ihep.ac.cn>
抄送: "tech-talk at aps.anl.gov" <tech-talk at aps.anl.gov>
主题: Re: Re: Re: RE: [SPAM] Re: autoConnect could not connect when reading a register by modbus relative addressing

Hi Zhibang,

You are making good progress!

What is happening to the .DMOV field when you move the motor the first time?  It should be 1 before you start the move, 0 during the move, and 1 again when the move is done. 

Can you send a screenshot of the motorx_all OPI screen when the first move is complete?

  • Or is there a method of the derived motor controller and motor axis class that has not been overrode, which makes the motor driver think the motion is not done yet and a new motion should not start?

I don't think there is another method to be overridden.  Perhaps your poller is not setting motorStatusDone_  to indicate that the move is complete.  Here are some examples:





Mark



From: shenzb at ihep.ac.cn <shenzb at ihep.ac.cn>
Sent: Saturday, November 30, 2024 7:00 AM
To: Mark Rivers <rivers at cars.uchicago.edu>
Cc: tech-talk at aps.anl.gov <tech-talk at aps.anl.gov>
Subject: Re: Re: Re: RE: [SPAM] Re: autoConnect could not connect when reading a register by modbus relative addressing
 

Dear Mark,


Thank you for your advice! I follow your suggestion to use doModbusIO and absolute addressing in my motor driver and it can read the registers and write now!


But there is still a problem that it can only communicate once after booting.


I create one motor driver that contains only one axis. The axis is linked to a standard motor record. I name it dm2c:m101.


I call caput to put a new position to dm2c:101.VAL after the IOC is booted, and the motor really moves to the position. The dm2c:101.RBV and dm2c:101.MOVN both shows desired information,


When I call caput to drive the motor to a new position for the second time, nothing will be done except dm2c:101.VAL is set. The motor does not move, dm2c:101.RBV does not refreshed, and the dm2c:101.MOVN remains to be 0.


At first I thought it would be an issue of the polling thread. But the printed messages showed that the polling thread was working well at the preset frequency.


Or is there a method of the derived motor controller and motor axis class that has not been overrode, which makes the motor driver think the motion is not done yet and a new motion should not start?




Best regards,

Zhibang


--------------
发件人: "Mark Rivers" <rivers at cars.uchicago.edu>
发送时间: 2024-11-30 02:00:39
收件人: "shenzb at ihep.ac.cn" <shenzb at ihep.ac.cn>
抄送: "tech-talk at aps.anl.gov" <tech-talk at aps.anl.gov>
主题: Re: Re: RE: [SPAM] Re: autoConnect could not connect when reading a register by modbus relative addressing

Hi Zhibang,


  • Since a polling thread of reading should be started in the motor driver, the absolute addressing cannot be used.

That is not true.  You can write the axis::poll function to use the doModbusIO with an absolute address.
  • And the registers are so far that exceed the maximum of modbusLength of function 3, one modbus port driver is not enough.
This is not a problem if you use absolute addresses and call doModbusIO.  You only need to create a single driver.  The function code you specify when creating the driver is not important, because you give the function code in each call to doModbusIO.
  • I have tried to establish 3 mobdus port drivers to read the registers, but only one can work correctly and the other two do not send messages.

That should not happen, so something is configured wrong.  But I don't recommend this approach.

  • I also tried using drvModbusAsyn::doModbus in the motor driver like done in modbusApp/testClient.cpp. But there is also a core dumped.

I see the problem with your driver, and why you are getting the error messages.
  • pModbus_ = new drvModbusAsyn(DM2CAsynPortName, "DM2C", 1, 3, -1, 256, dataTypeUInt16, 0, "DM2C_stepper");

You have the order of the first 2 arguments reversed.  It should be:

pModbus_ = new drvModbusAsyn("DM2C", DM2CAsynPortName, 1, 3, -1, 256, dataTypeUInt16, 0, "DM2C_stepper");


  • Do you think it is possible to use drvModbusAsyn::doModbus directly in the motor driver? Or should I focus on how to use multiple modbus read port in one driver?

Yes, it is definitely possible to use doModbusIO and I think this is what you should do.

Mark



From: shenzb at ihep.ac.cn <shenzb at ihep.ac.cn>
Sent: Thursday, November 28, 2024 9:15 PM
To: Mark Rivers <rivers at cars.uchicago.edu>
Cc: tech-talk at aps.anl.gov <tech-talk at aps.anl.gov>
Subject: Re: Re: RE: [SPAM] Re: autoConnect could not connect when reading a register by modbus relative addressing
 

Dear Mark,


Thank you for your enlightening advice!


I finally get the motor controller hardware. And I am told that the registers needed to be read locate at 0x0179, 0x1003 and 0x602C.


Since a polling thread of reading should be started in the motor driver, the absolute addressing cannot be used. And the registers are so far that exceed the maximum of modbusLength of function 3, one modbus port driver is not enough.


I have tried to establish 3 mobdus port drivers to read the registers, but only one can work correctly and the other two do not send messages.


I also tried using drvModbusAsyn::doModbus in the motor driver like done in modbusApp/testClient.cpp. But there is also a core dumped.





DM2CDriver.cpp


DM2CController::DM2CController(const char *portName, const char *DM2CAsynPortName, int numAxes, double movingPollPeriod, double idlePollPeriod):


asynMotorController(portName, numAxes, NUM_DM2C_PARAMS, 0, 0, ASYN_CANBLOCK | ASYN_MULTIDEVICE, 1, 0, 0)


{


asynStatus status;


DM2CAxis *pAxis;


static const char *functionName = "DM2CController::DM2CController";





/* Connect to DM2C controller */


modbusInterposeConfig(DM2CAsynPortName, modbusLinkRTU, 5000, 0);


pModbus_ = new drvModbusAsyn(DM2CAsynPortName, "DM2C", 1, 3, -1, 256, dataTypeUInt16, 0, "DM2C_stepper");




//startPoller(movingPollPeriod, idlePollPeriod, 2);

}


The output is as the followings.


#!../../bin/linuxx86_64/leadshine

< envPaths

epicsEnvSet("IOC","iocLeadshine")

epicsEnvSet("TOP","/home/specadm/epics/synApps_6_1/support/motor-R7-1/modules/motorLeadshine/iocs/leadshineIOC")

epicsEnvSet("MOTOR","/home/specadm/epics/synApps_6_1/support/motor-R7-1")

epicsEnvSet("ASYN","/home/specadm/epics/synApps_6_1/support/asyn-R4-36")

epicsEnvSet("SNCSEQ","/home/specadm/epics/synApps_6_1/support/seq-2-2-6")

epicsEnvSet("BUSY","/home/specadm/epics/synApps_6_1/support/busy-R1-7-2")

epicsEnvSet("IPAC","/home/specadm/epics/synApps_6_1/support/ipac-2-15")

epicsEnvSet("MODBUS","/home/specadm/epics/synApps_6_1/support/modbus-R3-0")

epicsEnvSet("EPICS_BASE","/home/specadm/epics/base-3.15.9")

cd "/home/specadm/epics/synApps_6_1/support/motor-R7-1/modules/motorLeadshine/iocs/leadshineIOC"

## Register all support components

dbLoadDatabase "dbd/leadshine.dbd"

leadshine_registerRecordDeviceDriver pdbbase

cd "/home/specadm/epics/synApps_6_1/support/motor-R7-1/modules/motorLeadshine/iocs/leadshineIOC/iocBoot/iocLeadshine"

## motorUtil (allstop & alldone)

asynSetAutoConnectTimeout(2)

drvAsynIPPortConfigure("L0","192.168.212.233:502",0,0,1)

asynWaitConnect("L0", 2)

asynSetTraceIOMask("L0",0,4)

asynSetTraceMask("L0",0,9)

DM2CCreateController(DM2C_1_1, L0, 1, 100, 0)

In function DM2CController::DM2CController

asynCommon:registerDriver L0 already registered

asynPortDriver:asynPortDriver ERROR: Can't register port: L0

terminate called after throwing an instance of 'std::runtime_error'

  what():  asynPortDriver:asynPortDriver ERROR: Can't register port: L0

Aborted (core dumped)



Do you think it is possible to use drvModbusAsyn::doModbus directly in the motor driver? Or should I focus on how to use multiple modbus read port in one driver?




Best regards,

Zhibang



------------------
发件人: "Mark Rivers" <rivers at cars.uchicago.edu>
发送时间: 2024-11-24 01:32:21
收件人: "shenzb at ihep.ac.cn" <shenzb at ihep.ac.cn>, "Mark Rivers" <rivers at cars.uchicago.edu>
抄送: "tech-talk at aps.anl.gov" <tech-talk at aps.anl.gov>
主题: Re: RE: [SPAM] Re: autoConnect could not connect when reading a register by modbus relative addressing

You should look at testClient.cpp:

You could use the main() function as a model for your constructor.  It will be passed just the IP address of the modbus server (ipAddr).  The constructor will then have lines like this:

     drvAsynIPPortConfigure("DMC2_IP", ipAddr, 0, 0, 0);
     modbusInterposeConfig("DMC2", modbusLinkTCP, 5000, 0);
    drvModbusAsyn *pModbus = new drvModbusAsyn("DMC2", "DMC2_IP",  0,  2,  -1,  256,  dataTypeUInt16, 0, "DMC2_stepper");

You now have a pointer to a modbus driver, and can call its public functions.

Your driver then just makes calls like this to do the actual Modbus IO:
     epicsInt16 data[45];
     pModbus->doModbusIO(0, MODBUS_READ_MULTIPLE_REGISTERS, 0x6000, data, 45);

I think this should be simpler than the model you are using now.

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: Saturday, November 23, 2024 10:01 AM
To: shenzb at ihep.ac.cn <shenzb at ihep.ac.cn>
Cc: tech-talk at aps.anl.gov <tech-talk at aps.anl.gov>
Subject: Re: RE: [SPAM] Re: autoConnect could not connect when reading a register by modbus relative addressing
 
  • In the ANG1Axis::poll method, the first step is to execute a forced read operation.


  • ANG1Driver.cpp: line 546

  • >> status = pasynInt32SyncIO->write(pasynUserForceRead_, 1, DEFAULT_CONTROLLER_TIMEOUT);


  • I would like to ask why this operation must be performed in order to start a new communication. What is the purpose of the member pasynUserForceRead_?

If you look at the startup script for the ANG1 example IOC, you will see that the poll time is set to 100 ms.

That means that the modbus driver has created a background thread that is polling those registers at 10 Hz.  I believe that the purpose of the pasynUserForceRead_ is to force an immediate read in case the 10 Hz poller data is too stale.

Note that around the time that this motor driver was written I added support for "absolute" addressing to the Modbus driver.  That is documented here:

You enable absolute addressing by passing -1 as the start address in the drvModbusAsynConfigure command.  In that case your driver can call this function in the driver:
    asynStatus doModbusIO(int slave, int function, int start, epicsUInt16 *data, int len);
 
In the mode you are currently using you need to create multiple modbus drivers in your startup script, each for a single function code and address range.  That is convenient when using Modbus with standard EPICS records (ai, ao, mbbi, mbbo, etc.).  However, in the case of a motor driver absolute addressing may be better.

In the absolute mode you can create a single driver and use if for any function code and any address.  That might make more sense for this application.  You can even create the modbus driver inside the constructor of your motor driver, hiding it from the user.  You just need to pass the asyn port name of the IP port to your constructor.

Mark



From: shenzb at ihep.ac.cn <shenzb at ihep.ac.cn>
Sent: Saturday, November 23, 2024 2:38 AM
To: Mark Rivers <rivers at cars.uchicago.edu>
Cc: tech-talk at aps.anl.gov <tech-talk at aps.anl.gov>
Subject: Re: RE: [SPAM] Re: autoConnect could not connect when reading a register by modbus relative addressing
 

Dear Mark,


In the ANG1Axis::poll method, the first step is to execute a forced read operation.


ANG1Driver.cpp: line 546

>> status = pasynInt32SyncIO->write(pasynUserForceRead_, 1, DEFAULT_CONTROLLER_TIMEOUT);


I would like to ask why this operation must be performed in order to start a new communication. What is the purpose of the member pasynUserForceRead_?


The comment in ANF2Driver.cpp at line 504 mentions it, but it also says not sure why this is necessary.


Could you help explain the principle behind it?


By the way, regarding the modbus slave simulator mentioned before, since I haven't received the motor controller yet, the simulator is quite useful for me to start coding. 


This is the simulator I am using:


https://modbustools.com/modbus_slave.html



Best regards,

Zhibang



-----原始邮件-----
发件人: "Mark Rivers" <rivers at cars.uchicago.edu>
发送时间: 2024-11-23 07:58:23 (星期六)
收件人: "shenzb at ihep.ac.cn" <shenzb at ihep.ac.cn>
抄送: "tech-talk at aps.anl.gov" <tech-talk at aps.anl.gov>
主题: RE: [SPAM] Re: autoConnect could not connect when reading a register by modbus relative addressing

  • I change the modbusLength to 4 as what is done in motorAMCI. And I continuously read the values of 5 neighbor registers, like:

 

If you set the length to 4 then you can’t read 5 registers, you can only read 4.  You need to increase the length to at least 5.

 

This is the first I heard that you are using a Modbus simulator, not the actual motor controller.  Is this correct?

 

  • The modbus slave simulator shows that the master and slave only communicated once. And the autoConnect issue is reported at the last time.

 

Looking back at your original message I understand why they only communicated once.  You set the poll time in this command to 0, which means it does not poll.

  • drvModbusAsynConfigure("DM2C_1_1_In_Word", "L0", 1, 3, 24576, 2, 0, 0, "DM2C_stepper")

You need to set a non-zero poll time.  For example, this will poll every 100 ms.

  • drvModbusAsynConfigure("DM2C_1_1_In_Word", "L0", 1, 3, 24576, 2, 0, 100, "DM2C_stepper")

Mark

 

 

 

 

Mark

 

 

From: shenzb at ihep.ac.cn <shenzb at ihep.ac.cn>
Sent: Friday, November 22, 2024 4:44 PM
To: Mark Rivers <rivers at cars.uchicago.edu>
Cc: tech-talk at aps.anl.gov
Subject: Re: [SPAM] Re: autoConnect could not connect when reading a register by modbus relative addressing

 

Dear Mark,

 

Thank you for your response. I can tell when will this issue happen with an example.

 

I change the modbusLength to 4 as what is done in motorAMCI. And I continuously read the values of 5 neighbor registers, like:

 

> status = pC_->readReg16(0, &read_val, DEFAULT_CONTROLLER_TIMEOUT);

> status = pC_->readReg16(1, &read_val, DEFAULT_CONTROLLER_TIMEOUT);

> status = pC_->readReg16(2, &read_val, DEFAULT_CONTROLLER_TIMEOUT);

> status = pC_->readReg16(3, &read_val, DEFAULT_CONTROLLER_TIMEOUT);

> status = pC_->readReg16(4, &read_val, DEFAULT_CONTROLLER_TIMEOUT);

 

The modbus slave simulator shows that the master and slave only communicated once. And the autoConnect issue is reported at the last time.

 

> readReg16: reg = 0, value= 2020

> readReg16: reg = 1, value= 2021

> readReg16: reg = 2, value= 2022

> readReg16: reg = 3, value= 2023

> 2024/11/23 06:24:07.881 DM2C_1_1_In_Word 4 autoConnect could not connect: 

> readReg16: reg = 4, value= 2023

 

I mean this autoConnect error occurs when I want to send message for the second time.

 

 

Best regards,

Zhibang

 

------------------
发件人: "Mark Rivers" <rivers at cars.uchicago.edu>
发送时间: 2024-11-22 23:03:21
收件人: "tech-talk at aps.anl.gov" <tech-talk at aps.anl.gov>, 沈治邦 <shenzb at ihep.ac.cn>
: [SPAM] Re: autoConnect could not connect when reading a register by modbus relative addressing

I think I see the problem.

 

  • drvModbusAsynConfigure("DM2C_1_1_In_Word", "L0", 1, 3, 24576, 2, 0, 0, "DM2C_stepper")

That creates a driver that will use function code 3 to read from register location  24576 (0x6000).  It will read 2 registers (the Modbus length argument), so it will read registers 0x6000 and 0x6001.

 

·               status = pC_->readReg16(44, &read_val, DEFAULT_CONTROLLER_TIMEOUT);

However, here you are telling it to read relative register 44 (0x2c) which is absolute register 0x602c. That is invalid because you only configured the driver to read 2 registers.  You need to increase the number of registers in the drvModbusAsynConfigure to include all registers you will be accessing.

 

Mark

 

 

 


From: Tech-talk <tech-talk-bounces at aps.anl.gov> on behalf of 沈治邦 via Tech-talk <tech-talk at aps.anl.gov>
Sent: Friday, November 22, 2024 4:31 AM
To: tech-talk at aps.anl.gov <tech-talk at aps.anl.gov>
Subject: autoConnect could not connect when reading a register by modbus relative addressing

 

Hi,

 

I am encountering an issue while developing a modbus communication-based motor controller program, similar to the module motorAMCI.

 

I am attempting to read the values in registers with function code 3 by relative address. For instance, if I want to read the value located in 0x602C, which represents the current position of the motor. I set the starting address to 0x6000 by the command in st.cmd

 

drvModbusAsynConfigure("DM2C_1_1_In_Word", "L0", 1, 3, 24576, 2, 0, 0, "DM2C_stepper")

 

Then to read the motor position, I called the function in driver.cpp with sentence

 

status = pC_->readReg16(44, &read_val, DEFAULT_CONTROLLER_TIMEOUT);

 

24657 is 0x6000 and 44 is 0x2C, then I believe that the value at 0x602c could be accessed.

 

The definition of the readReg16 is the same with the method ANG1Controller::readReg16()

 

Consequently, I am unable to retrieve the correct register value, and an error is showed:

 

2024/11/22 17:57:00.751 DM2C_1_1_In_Word 2 autoConnect could not connect:

 

Could someone please help me figure out what might be causing this issue? 

 

Thank you!

 

 

Best regards,

Shen Zhibang


References:
autoConnect could not connect when reading a register by modbus relative addressing 沈治邦 via Tech-talk
Re: autoConnect could not connect when reading a register by modbus relative addressing Mark Rivers via Tech-talk
Re: [SPAM] Re: autoConnect could not connect when reading a register by modbus relative addressing Zhibang Shen via Tech-talk
RE: [SPAM] Re: autoConnect could not connect when reading a register by modbus relative addressing Mark Rivers via Tech-talk
Re: RE: [SPAM] Re: autoConnect could not connect when reading a register by modbus relative addressing Zhibang Shen via Tech-talk
Re: RE: [SPAM] Re: autoConnect could not connect when reading a register by modbus relative addressing Mark Rivers via Tech-talk
Re: RE: [SPAM] Re: autoConnect could not connect when reading a register by modbus relative addressing Mark Rivers via Tech-talk
Re: Re: RE: [SPAM] Re: autoConnect could not connect when reading a register by modbus relative addressing Zhibang Shen via Tech-talk
Re: Re: RE: [SPAM] Re: autoConnect could not connect when reading a register by modbus relative addressing Mark Rivers via Tech-talk
Re: Re: Re: RE: [SPAM] Re: autoConnect could not connect when reading a register by modbus relative addressing Zhibang Shen via Tech-talk
Re: Re: Re: RE: [SPAM] Re: autoConnect could not connect when reading a register by modbus relative addressing Mark Rivers via Tech-talk

Navigate by Date:
Prev: Re: Re: Re: RE: [SPAM] Re: autoConnect could not connect when reading a register by modbus relative addressing Mark Rivers via Tech-talk
Next: Modbus R3-4 released Mark Rivers 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  <20242025 
Navigate by Thread:
Prev: Re: Re: Re: RE: [SPAM] Re: autoConnect could not connect when reading a register by modbus relative addressing Mark Rivers via Tech-talk
Next: Re: [SPAM] Re: autoConnect could not connect when reading a register by modbus relative addressing Zhibang Shen 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  <20242025 
ANJ, 01 Dec 2024 Valid HTML 4.01! · Home · News · About · Base · Modules · Extensions · Distributions ·
· Download · Search · IRMIS · Talk · Documents · Links · Licensing ·