User component: Event-based rather than polling?

More
25 May 2023 05:19 - 25 May 2023 05:39 #272138 by swarren
I am writing a custom user component that will detect changes to a HAL pin (which are in turn triggered by a custom M code that sets the pin to 1 or 0), and send messages to a different system to control my dust extractor. I have a couple of questions about how to implement the component:
  1. All the component examples that I've found run a "forever/while True" loop that reads the pin, processes the value, then sleeps and repeats. This is polling. Is there a way to have an event-based component instead, i.e. block on a pipe/signal/... rather than polling?
  2. How efficient is the polling; is reading a pin implemented behind-the-scenes in some efficient way such as reading shared memory, or does it involve actively sending messages to HAL and making it do work to process them and respond? I'm wondering how fast/often a pin value can be polled by a component before it has impacts (on other software) beyond plain CPU usage in the component itself.

    Thanks!
Edit: If it makes a difference, I'm planning on writing the component in Python rather than C, and structurally it'd thus be something like the followin example: (see code in the first post of page 2): forum.linuxcnc.org/10-advanced-configura...serial-port?start=10
Last edit: 25 May 2023 05:39 by swarren. Reason: Add link to example I've looked at.

Please Log in or Create an account to join the conversation.

More
25 May 2023 06:22 #272140 by rodw
If you used M62/M63 You could turn a motion.digital-out.nn pin off in real time. If you need to do anything fancy, you can write a custom components In C and use halcompile to compile and install it..

Please Log in or Create an account to join the conversation.

More
27 May 2023 05:21 - 27 May 2023 05:38 #272246 by zdenek
Your intuition and observation is spot on, polling appears to be the only way stuff is done in the existing examples. I think it's time to change that :-). Event based handling is clearly missing and would be quite useful in more than one place within linuxcnc. So far my first solution is an RT component that watches arbitrary HAL signals and sends events to the user space via a SYSV IPC queue to an arbitrary linux program.

Caveat Emptor: The code below uses a kernel communication mechanism that, to my knowledge, no other linuxcnc component utilizes. It should work fine, and I have been running it on a couple of machines without any problem. Please let me know if you see any issues.

The python code is obviously just to get an idea; all you need is:
import sysv_ipc
q = sysv_ipc.MessageQueue(...)
while True:
   data = q.receive() # sleep until you get an event


 
Attachments:
Last edit: 27 May 2023 05:38 by zdenek. Reason: learning how to use the forum platform
The following user(s) said Thank You: tommylight, Aciera

Please Log in or Create an account to join the conversation.

More
28 May 2023 07:11 #272320 by swarren
Thanks, that looks neat. From what I can tell, the RT component is still polling/recalculating all the time? I'm not familiar with RT components yet; is the model for RT that it's a big super-loop that always recalculates every value all the time anyway? At least this avoids the need for the user-space component to poll too, which is great.

In the end, it turns out that my user-space component does need to send status to the dust extractor periodically anyway, so the polling worked out OK (albeit the signal is polled far more often than the periodic updates to avoid delays, an update is sent on change or if no update has been sent in 10s), That said, maybe I could combine the SysV IPC read with a 10s timeout to make sure the periodic messages are sent but without the need for rapid polling to quickly detect changes.

Please Log in or Create an account to join the conversation.

More
28 May 2023 07:58 #272322 by rodw

Thanks, that looks neat. From what I can tell, the RT component is still polling/recalculating all the time? I'm not familiar with RT components yet; is the model for RT that it's a big super-loop that always recalculates every value all the time anyway? At least this avoids the need for the user-space component to poll too, which is great.

 

Think of the servo thread as being triggered by a timer interrupt that happens every 1 millisecond (1000 usec).
RT Components either from the linuxcnc core or ones you write are called in turn when that thread fires. Say it takes 200 usecs to service all the components and the linuxcnc core, the thread will sleep for 800 usec until it's scheduled to fire again. That's roughly what we observed with a kernel trace. While it sleeps, it's not consuming any resources.

I have never bothered with Python user space components. I just write them in C and run them in real time... I'm not fond of Python...

Please Log in or Create an account to join the conversation.

More
29 May 2023 06:55 #272406 by zdenek
Yes, the HAL thread is pretty analogous to the concept of a super-loop, only the former does it to implement a discrete DSP-like algorithm with the loop period implementing the dt, whereas the latter is usually deployed due to the lack of proper OS/scheduler.

Your solution is right -- suspend until either a change or a timeout.
Implementing timeouts like that in python threads is not always easy, I often generate dummy events to work around the python limitations.

Please Log in or Create an account to join the conversation.

Time to create page: 0.085 seconds
Powered by Kunena Forum