I’m doing a project where I need to monitor several hall sensors for a position encoding. The logic is pretty simple, but the digital signal is fast: it may have up to 350 position changes per second.
I was hoping I could simply write a hall sensor monitor program watching the GPIOs but it appears that these programs consume quite a bit of CPU if I monitor at the necessary frequency. I had hoped suspending the CPU between every poll would help, but it doesn’t seem to make much difference.
Here’s the polling loop from what I’m currently doing. It “works”, but the CPU usage is far too high. I’m running this on a process that shares the “position” variable with other processes on a memory-mapped file.
REFRESH_RATE = .0005 while True: new_p1_state = GPIO.input(hall_p1) new_p2_state = GPIO.input(hall_p2) if new_p1_state != p1_state or new_p2_state != p2_state: if p1_state == GPIO.HIGH: if new_p2_state == GPIO.HIGH: position -= 1 else: position += 1 else: if new_p2_state == GPIO.LOW: position -= 1 else: position += 1 p1_state = new_p1_state p2_state = new_p2_state time.sleep(REFRESH_RATE)
Can anybody recommend a more efficient way to do this? Should I avoid python and use something faster? If so what?
I wanted to give a follow-up. I was able to rewrite this as an interrupt-based kernel driver. It works much better than the python version, but still isn’t good enough – the quadrature counter misses events and drifts when the device is pushed too hard.
I’m now trying to apply the PREEMPT-RT patch to enable full realtime preemption to the linux kernel. Hopefully this will get me what I need without a separate microcontroller.
You’re using wrong hardware & software for the job. Jetson Nano can be considered as a full featured PC. As I understand, it’s suitable for high level algorithms, image processing and neural network evaluation. Bare metal programming does not make much sense for this kind of devices, hence you have Linux running on it. You need to be aware that in the presence of a non real-time operating system, you can’t get reliable delay times.
Reading a quadrature encoder is low level task with strict hard real-time requirements. For this, you need microcontrollers (like PIC, AVR, ARM Cortex M), C/C++, bare-metal programming or an RTOS, and preferably dedicated hardware which is capable of reading quadrature encoders directly.
Polling input pins isn’t the correct way of interfacing encoders. Keep it in mind that you need to poll the pins much faster than the expected pulse frequency. In microcontrollers, you use interrupts instead which saves you from polling. Even interrupts can’t keep up with high resolution & fast turning encoders. When interrupts don’t suffice, you need dedicated encoder interfacing hardware which counts pulses automatically for you.
The best thing you can do is picking a microcontroller and outsourcing the encoder counting job to it. As your encoder resolution is low, you don’t need special quadrature interface hardware modules. You can just pick an Arduino and make it count pulses. Then your Jetson Nano can query Arduino using serial port, I2C or SPI to retrieve the up-to-date pulse count.