Skip to content
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

921 tachometer odometer kinematics parts #1003

Closed
wants to merge 17 commits into from

Conversation

Ezward
Copy link
Contributor

@Ezward Ezward commented Mar 26, 2022

Add new encoder, tachometer, odometer and kinematics parts

  • the encoder/tachometer/odometer break up the these concerns into separate layers so we can avoid hoisting all that functionality into each separate encoder.
    • encoders simply count ticks
    • tachometers take ticks and output revolutions
    • odometers take revolutions and output distance and velocity
  • We support either one odometer for car-like vehicles or two encoders/odometers for differential robots.
  • the kinematics are used to estimate the vehicle pose (x, y, heading). This will eventually be used in two ways
    • we can use this as a source of pose in the path_follow template. TBD in a separate pull request.
    • we can use this, along with closed loop speed control, to implement a velocity based neural network model. TBD in a separate pull request.
  • car-like vehicles uses bicycle kinematics
  • differential drive vehicles uses unicycle kinematics

All of these parts have been run-tested for a few months in another branch using a highly modified path_follow.py. That branch has a lot of changes, so I've created this pull request just for the encoder/odometer/kinematics pipeline. Future pull requests will 1) add changes to path_follow to bring it up to snuff with the complete template 2) add closed-loop speed control and a velocity-based neural network model.

This is draft because I still need to test it on track.

@Ezward Ezward requested a review from DocGarbanzo March 26, 2022 21:36
@Ezward Ezward self-assigned this Mar 26, 2022
@Ezward Ezward changed the title 921 tachometer odometer parts 921 tachometer odometer kinematics parts Mar 28, 2022
Ezward and others added 12 commits April 10, 2022 21:25
- mono and quadrature encoder implementations
- both use the same serial protocol
 * Implements the r/p/c command protocol
 * for on-demand sending of encoder value
 * and continuous sending with provided delay.
-   Used by serial encoder
-   Wrapper for serial port connect/read/write.
    Use this rather than raw pyserial api.
    It provides a layer that automatically
    catches exceptions and encodes/decodes
    between bytes and str.
    It also provides a layer of indirection
    so that we can mock this for testing.
is_linux, is_mac, is_windows, is_jetson
- encoders support pin schemes, so the gpio
  encoder can use RPi.GPIO or PiGPIO
- The serial encoder using the arduino sketches which support mono-encoders and quadrature encoders
- The gpio encoders have been tested on RPi
- The serial encoders have been tested in RPi and jetson.
- The self test __main__ in tachometers is a simple way to test a given hardware setup and pin configuration without having to run full donkeycar.
- Fixed capacity circular buffer that can be used as a queue, stack or array
- Used by odometer to keep fixed-size history of tachometer readings so it can calculate a smoothed velocity.
- An Odometer takes the output of a Tachometer (revolutions) and turns those into a distance and velocity.  Velocity can be optionally smoothed across a given number of readings.
- This moves the calculation of distance and velocity, including smoothing, out of each separate encoder implementation.  Now we have a clean separation of encoders:ticks, tachometers:revolutions, odometers:distance&velocity
- use tachometer.py and odometer.py instead.
- Unicycle kinematics for differential drive
- Bicycle kinematics for car-like vehicles
- These are used to estimate pose (x,y,heading)
- Eventually these will be incorporated into path follow template.
- required by tachometer unit test.
- added get_ticks() to MockEncoder
@Ezward Ezward force-pushed the 921-tachometer-odometer-parts branch from 666151b to 072d4f6 Compare April 11, 2022 04:26
- update comment in limit_angle and fix tests to reflect that angle is limited betwee pi and -pi
- This allows us to add arbitrary logging of memory values without having to edit parts.
- 'steering' should be 'angle'.  this caused None values to be sent to the kinematics parts
- fix unterminated/merged string that caused off-by-one values in the Bicycle kinematics.
@Ezward
Copy link
Contributor Author

Ezward commented Jun 25, 2022

Status is that the kinematics are producing a repeatable path, but it is not accurate. so the strange results is that if you record a path and put it in path follow mode then it will looks like it is doing a great job. However, if you look at the path (I've added the ability to save path as .csv) in something like https://www.csvplot.com/ the path will not look anything like what your recorded. So the path looks totally wrong, but because it is repeatably and reliably wrong in the same way each time the PID path follow algorithm can still 'follow' the wrong path and get the correct real-world output.

We've added in support for odometry/kinematics in the simulator and it seems to produce a similar issue. NOTE that all of these tests are currently with a differential encoder setup.

I've checked and rechecked the math; it looks correct; same math as I have used in other projects and their paths look correct.

My current thinking is that we don't have a fast enough update loop. The encoders and kinematics are running in non-threaded mode, so locked in at 20hz, which may be too slow for good pose estimation. The kinematics formulas assume that vehicles has driven in a straight line between estimates; we may be build error very quickly because we break this assumption. This theory is supported by the behavior we see; the path look correct if you just go straight, but creates weird loops when attempting to turn. The other potential issue is the lag between getting an encoder update and making a pose estimate; because these are all separate parts and we may get interrupted by threaded tasks (we have a lot of those), we may have varying latency between when we get an update an when we apply it.

So I think the next thing to do is make sure the serial encoder and kinematics can run in threaded mode. We may also want to make those a single process so that we update the pose immediately after getting an encoder update.

Another potential way to handle this is to change the vehicle loop so that it runs as fast as it can. By default we will still only call non-threaded parts at 20hz. However, we can add a part as non-throttled so it will get called as fast as the loop can go. Doing that we could avoid a lot of issues with trying to coordinate a bunch of separate threaded parts.

This effectively what I do in the Esp32CameraRover project; it's update loop runs at full speed. Some things throttle themselves based on current time. Others greedily run as fast as they can. It can do pose estimation and line following and it is using a microcontroller (Esp32) not a full SBC.

@Ezward
Copy link
Contributor Author

Ezward commented Mar 6, 2023

Superceded by PR #1089

@Ezward Ezward closed this Mar 6, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant