beagleboard / librobotcontrol

Robotics Focused library for embedded Linux computers. Mirror of https://git.beagleboard.org/beagleboard/librobotcontrol
https://beagleboard.org/librobotcontrol
MIT License
199 stars 160 forks source link

low speed encoder readings #186

Open clarkbriggs opened 4 years ago

clarkbriggs commented 4 years ago

Is your feature request related to a problem? Please describe. For smallish ground vehicles, encoder counts at slow speeds are inaccurate. This makes forward speed control and steering rotational speed control very poor.

Describe the solution you'd like Several years ago, Nick Morozovsky at UCSD identified a dual mode approach where low speeds were measured by the time duration between encoder pulses. The Blue's EQEP encoder does a good job with position. It seems to have a mode for counting the period between pulses. It would probably be difficult to switch between the two modes and keep a hardware measure of distance or position. I suppose all that mode switching would need to be in the EQEP driver and would need TI support for figuring it out. The sign of the duration needs to be determined somehow, probably with an approach like the position counting uses. It might be enough to give the user access to the channel A and B GPIO edge changes, while not disrupting the EQEP position counting, so the user could time the duration between pulses. The OOTB Blue configuration doesn't seem to expose user access to the EQEP input GPIOs.

Describe alternatives you've considered This is readily implemented in a software encoder counter. At high enough speeds, the position is read or accumulated like usual. It is smooth enough to differentiate in time for speed and to difference left-right for rotation. At low speeds, the time between pulses is measured. The consumer can use the inverse of the duration for a speed measurement. I built this for the RaspberryPi which has a kernel driver for a software rotary encoder. I used the relative mode which delivers +1 or -1 counts which I then accumulate. I can measure the time between these readings and produce a duration. The sign of the event provides the sign of the duration.

Additional context Some consideration is needed to get a smooth transition between the two modes and perhaps hysteresis is needed to smooth bouncing back and forth across the boundary.

clarkbriggs commented 4 years ago

Subsequent discussions elsewhere lead to some clarifications. The need is really for a speed counter, an encoder click rate measurement. This is especially needed at low slow wheel speeds, such as at start up, when time differentiation and left-right differentiation is too noisy due to low click rates. Encoder position counting is just what is needed at speed. It provides long term position knowledge and has usable differences over small dts. At speed the hardware encoder can shield the CPU from the high interrupt rate. We size the drive mechanism for a variety of requirements. We pick a motor, its size, its RPM limits, its torque value. We pick a gear box ratio. We pick an encoder which we can place on the axle side or the motor side and can have multiple pick ups per revolution. We all know how our cars work: some are great at the low end, others are great at the high end, but are very many great at both ends? The current proposal is to provide a speed reading based on timing the duration between encoder clicks. This will provide a good working measurement at low speeds. At some high speed it could be onerous. Both its utility at low speeds and its cost at high speeds depend on the motor, gearing and senors counts.

dlech commented 4 years ago

What speeds (in terms of encoder counts per second - one "count" being rising edge of one GPIO) do you consider "high" speed and "low" speed?

clarkbriggs commented 4 years ago

I don't have any practical answer. This stuff is very low level from where I work on navigation. Some aspects of my world: Others have made the physical bots and all those sizing choices. Working in doors with turtle bots in a half room sized area. 1 m/sec is fast. My Pololu Romi has 1440 clicks per rev and a wheel diameter of 70 mm. Slow speed aka starting up results in single digit click counts at 20 sec dt and time differences of < 5 clicks. Surely every bot will have these "slow" zones. Another slow time is a turn-around-in-place maneuver with no forward velocity and a rotation of say half a turn in 4 seconds. I have an out door R/C 1/10th scale truck with an encoder on the drive wheels. Those guys go a lot faster and slow isn't an issue. They can't turn in place either. That would bound my "fast" regime. The truck has a clicks per rev of 160 and a wheel diameter of 108 mm. Good numeric answers for you would be helpful in deciding when a software encoder with its interrupt rate gets to be too hard on the CPU. I have been approaching this by try-it-and-see.

clarkbriggs commented 4 years ago

dlech etal: I have made progress with the proposed software encoder on Blue. This design puts copies of the encoder ch A and ch B inputs on user GPIOs as well as the encoder input GPIOs which feed the hardware encoders. Here now finally at last is my arithmetic for the click rate aka the GPIO interrupt rate. Wheel diameter is 70 mm. The encoders plus the gear box provide 1440 counts per rev. 1440/(3.140.07) 0.5 m/sec -> 3274 clicks /sec or .305 msec per click. This used 0.5 m /sec which is sorta quick for this little guy. For the earlier MIPS, we used 543 clicks /rev, which will clearly be slower, but... I found with my software encoder which poll'ed on the edge interrupt fds for the gpios, it was easy to get both ch A events and ch B events reported together. They had different time stamps (and physically can't happen together), so the kernel could not deliver Ch A to my routine before Ch B came along, is my interpretation. This happens at more modest speeds than the 0.5 m/sec and I can generate this error just turning the wheels by hand. There are a few things to consider to try to make this more livable. I run my routines at SCHED_FIFO priority, but this doesn't seem to help. The kernel can't deliver in time. (OBTW, I have starved the kernel before with too much load, but I don't believe that is the case here.) We have successfully gotten the kernel to wake up routines at 500 hz but that is about the fastest. The 0.5 m/sec appears to be faster than that. I built this parallel software encoder so that I could use the time between clicks at very low speeds for a click rate for use with speed control. With just the hardware position readings, low speeds produce very poor and noisy left/right and time differences. This software encoder implementation at low speeds seems to noticeably improve slow speed performance. I have been driving with this for a little while now. Of course, not much time is spent in this slow speed regime. For by current test runs, I drive out 2 meters from a standing start, stop, turn in place 180 degrees and drive back. There are lots of low speed events in this path. Clearly starting but also turning in place. These are performed much better. I think this little hint of success suggests starting to look at how to get the hardware encoder to do this is worthwhile. I think its clear the upper speed limit on the software encoder is too low. This also suggests the RPi kernel software encoder is going to have similar upper speed limits. The kernel implements the 4 state state machine that counts revs and reports +1 or -1 to my user poll routine. There has been no sign of errors with this implementation. But then, I don't know how it would complain.