-
Notifications
You must be signed in to change notification settings - Fork 197
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
read write frequency #231
Comments
You might be able to achieve a higher frequency with When you set AdsNotificationAttrib.nCycleTime=0 and use ADSTRANS_SERVERCYCLE you should get the maximum amount of events. A simple example for notifications is here: https://github.com/Beckhoff/ADS/blob/master/example/example.cpp#L30-L42 |
Thank you for your response! I took your advice and had a try. Now please correct me or point me in the right direction. Original LoopThis is how I had one of my loops: (some parameters are written, some are read. In the future, I will separate read and write to different arrays.) // Initialize
AdsVariable<std::array<bool, machine_control_bool_len>> machine_control_bool{route, idx_group, idx_offset_BOOL};
// Pass to node as pointer
// -------- Start loop -----------------
std::array<bool, machine_control_bool_len> machine_control_b = static_cast<std::array<bool, machine_control_bool_len>>(machine_control_bool_);
// ---- Stay alive, ROS to Beckhoff
machine_control_b[0] = true;
// Do other stuff
// Write using the operator overloading of ADS template
machine_control_bool_ = machine_control_b;
// ---- End loop ---------------------- New Approach with CallbackWith the new approach you suggested, would I be callback-based? So Beckhoff would define the frequency through PLC timers, or how? I implemented this: // Initialize
long nErr;
AmsAddr Addr;
// Set remote AmsNetId
Addr.netId = remoteNetId;
// Set remote AMS port (commonly 851 for the first PLC runtime system)
Addr.port = AMSPORT_R0_PLC_TC3;
// Index group and index offset
uint32_t indexGroup = idx_group;
uint32_t indexOffset = idx_offset_BOOL;
AdsNotificationAttrib NotificationAttrib;
NotificationAttrib.cbLength = sizeof(std::array<bool, machine_control_bool_len>);
NotificationAttrib.nTransMode = ADSTRANS_SERVERCYCLE;
NotificationAttrib.nMaxDelay = 1000; // 0.001 second
NotificationAttrib.nCycleTime = 0; // 100 ms
uint32_t hNotification;
uint32_t hUser = 0;
nErr = AdsSyncAddDeviceNotificationReqEx(AdsPort, &Addr, indexGroup, indexOffset, &NotificationAttrib, AdsNotificationCallback, hUser, &hNotification);
if (nErr) {
std::cerr << "Error: AdsSyncAddDeviceNotificationReqEx failed with error code " << nErr << std::endl;
return -1;
} else {
std::cerr << "Success on New callback method with: code " << nErr << std::endl;
}
void AdsNotificationCallback(const AmsAddr* pAddr, const AdsNotificationHeader* pNotification, uint32_t hUser) {
// Suppress unused parameter warnings
(void)pAddr;
(void)hUser;
const std::array<bool, machine_control_bool_len>& data = *reinterpret_cast<const std::array<bool, machine_control_bool_len>*>(pNotification + 1);
std::cout << "First element: " << data[0] << std::endl;
} Questions and Considerations
|
EDIT: We seem to have one dispatcher thread per Notification, however to be able to receive the next one while processing another you should either process fast or relay the data to another thread |
Great. I have implemented this and it works amazing. I am in the nanosecond range for receiving data (much faster than expected). However, there is still one issue. Writing using the overload of the ads function such as before: std::array<bool, machine_control_bool_len> machine_control_b = static_cast<std::array<bool, machine_control_bool_len>>(machine_control_bool_); // Do other stuff // Write using the operator overloading of ADS template This operation delays the callbacks and creates gaps in the streamed data. Is there a more efficient way to writing data back to beckhoff? also with defining some sort of callback on the beckhoff side? This operation takes around 200 to 1200 microseconds which is extremely slow compared to the 10-30 nanoseconds i measure on the callback. |
You can try to use a different "AmsPort" for sending than receiving. I don't know about the "TwinCAT receiving end" so I am sorry I cant help you with that. Do you run TwinCAT and your ros2 node on the same CPU? Or is there a real network physical layer between them? |
Yea. okay. Do you know that using another port is nonblocking? I was thinking of adding another remoteNetId but the port would be more convenient i guess.
I physically divide the system. I have the beckhoff plc on a their classical windows and a 32 core linux server to do the heavy lifting. The software is multi-threaded and the bottleneck the ads tcp i think (also udp seems impossible with the current state of beckhoff). The callback seems almost unreasonably fast while writing is slow at 1ms. |
Okay with (virtually) two separate hosts maybe EtherCAT Automation Protocol (EAP) is a better solution. Did you considere that: |
Yes, Two considerations, one we are planning to switch beckhoff to linux for shipping later, which they claim to "release in the future". Whatever that means. But its important to have this option to move to one "pc" unit. I have seen the advantage of Ethercat but no route that would allow me to use the current hardware C6030-0070 without a lot of extra work and without the guarantee it will greatly improve the performance. If there is an efficient way we will do it, if there is not i will live with the limitation. I saw a few things but do you know some reliable library? Is there a way in this library to limit or define the write time? switch to udp? or i guess changing the port could solve the issue? Given i am 90% at where i want to be i am inclined to stay with this solution here. |
Yeah, I totally understand your reasoning. I have zero experience with EAP myself, so I can't tell you how much effort it is to port your current solution to EAP. And I can't tell about any libraries either. I simply don't know. What I know is the EtherCAT Technology Group has some excellent support guys. Not sure if you have to be ETG member (free of charge) to ask them for support. If you get EAP working I think you should make it work on localhost too, with virtual network interfaces or UDP. Another hack you can try is |
Okay. Thank you for the update and the details. I will live with the limitation for now and maybe update to TwinCat someday. What I hope to understand at some point is why i can receive information within nanoseconds while writing takes microseconds and this somewhat randomly between 200 to 1200 us. I will try and contact them directly. We do get support. |
I don't believe you really get updates within nanoseconds. What I believe is you measure the time between two calls of your callback.The difference is the tcp stack can buffer incoming packets for you so while your initial receive is delayed a bit. future receives are already on the host when you process the first one. So your callback gets called much rapidly. For writing it is much harder because when you "send()" you have to wait for the ACK response. |
Yes, that makes sense, this is what i expected but didn't understand why. Thank you for the clarification. So its basically two different mechanisms, one is a callback i am waiting for, which executes at the set loop time or max frequency of the beckhoff system part which is writing the variable. Its good enough for now. |
Im running a ros2 node reading and writing in parallel (optimized for minimal data) on four loops. However, the data transmission speed of the fastest loop is limited to 1000hz (also if the plc is running faster) and less if i am running everything at the speed i need (around 600hz for the fastest loop). Is there a way to speed up the beckhoff side? or change from tcp to udp? The general limitation seems to be around 800-1000 microseconds for one read or write process of a variable or list of variables.
The text was updated successfully, but these errors were encountered: