-
Notifications
You must be signed in to change notification settings - Fork 1.3k
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 kinematics pose estimation #1089
Conversation
Two things worth noting
|
As a heads-up, there is are changes to path_follow.py and complete.py associated with changing some terminology from 'angle' to 'steering'. This is because angle has a specific meaning in the kinematics and pose estimate realm. The values we are calling 'angle' are more properly a steering input. |
@Ezward, TCIII |
Demo of @TCIII differential drive robot running path_follow autopilot on it's third lap; https://www.youtube.com/watch?v=c8VipGXt4kI It went 5 laps before accumulated error causes a collision. |
ba535c0
to
c743ca3
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Ezward - this looks good to me. Only minor questions / comments.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks good to me, I have only a minor comment in the vehicle loop. If you merge, please update the version number in setup.py
and please apply the new version format, i.e. it should go from '4.4.dev4' to '4.4.dev5'.
donkeycar/vehicle.py
Outdated
|
||
|
||
loop_total_time = time.time() - loop_start_time | ||
print(f"Vehicle executed {loop_count} steps in {loop_total_time} seconds.") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Optimally this should be a logger statement as well.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I updated that to a logger statement
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
updated to version="4.4.dev5"
- tachometer takes an encoder and returns revolutions - odometer coverts revolutions to distance and velocity - kinematics converts odometry to pose estimates - BicyclePose part implements the pose estimation pipeline for a car-like vehicle (fixed back wheels, turnable front wheels) - UnicyclePose part implements the pose estimation pipeline for differential drive vehicles.
- UnicyclePose handles encoder/tachometer/odometer/kinematics for differential drive. - BicyclePose handles encoder/tachometer/odomter/kinematics for car-like vehicle - add a mock encoder that is driven by throttle and steering input. This allows use to simulate the vehicle without a full-on simulator. - Fix the drawing of the path so that it handles the fact that Y increases going north.
- Interrupts mode can handle much higher tick rates, but does a poor job of debouncing. It is appropriate for high resolution optical encoders.
It was at the end of `#define ENCODER_OPTIMIZE_INTERRUPTS` and so could have been causing the #define to be unrecognized.
- there was a syntax error if only one pin was defined and it was being used in interrupt mode; that is fixed. - Add more documentation to the mono_encoder.ino sketch
- The sketch counts ticks on a quadrature encoder without using 3rd party libraries. - This is done 1) to make is simpler to compile and download the sketch; the user does not need to figure out what library to use. 2) the library that was in use only worked on AVR hardware and causes compilation errors on other hardware. - if USE_ENCODER_INTERRUPTS is defined when the sketch is compiled, then the interrupt driven tick counting will be used. This has no debounce logic, so it is not suitable for mechanical encoder, but is appropriate for optical or hall effect encoders. - if USE_ENCODER_INTERRUPTS is NOT defined, then this used polling mode with debouncing, which is suitable for mechanical encoders, but may be to slow for high resolution optical or hall effect encoders.
- it had literal 2 for size of encoders array, so when there was only one encoder we got memory overwrites.
- I used the wrong symbol for adding the #2 isr
- use array rather than pointer in readEncoders() argument.
- the library we used was only for AVR microcontrollers, so the code could not work on RPi Pico for instance. - I reimplemented the sketch to have explicit polling mode logic that is suitable for noisy mechanical encoders. - To that I added an interrupt driven mode that works if there is one interrupt capable pin available for each encoder. This is suitable for optical or hall effect encoders that do not need to be debounced.
- the constructor has a default for pin_scheme based on the GPIO object. The GPIO object will not be defined on a PC. - this change use None as a default and then checks for it and set the GPIO default if it is None. - This fixes a bug in the actuator unit test.
- The vehicle loop now counts frames accurately; prior to this change the counter would be one more than the actual number of executed frames - When the vehicle loop terminates the number of executed iterations and the total time are printed and returned to the caller. - This was used for the kinematics tests because we needed to know how long the vehicle drive loop executed so we could calculate the expected distance that the mock vehicle drove.
- We dramatically changed how a mock drivetrain handles odometry. Now is uses a velocity based on encoder ticks per second scaled by throttle. This is a more realistic mock, but it is harder to test. - The tests setup a vehicle with a mock encoder, then run the vehicle loop for a set number of iterations. The vehicle loop now returns how long the loop ran and this is used along with the configuration for ticks_per_second from the mock encoder to calculate how far the vehicle travelled. Then the kinematics model is applied to see if the resulting ending pose matches the expected pose.
- the code now uses the front wheels as the reference point for the calculations - this fixes the unit test, which were using the front wheels while the code used the back wheels.
- change print statement to a log
version="4.4.dev5"
0b9362d
to
78711a7
Compare
This PR adds a new capability; the ability to estimate pose using wheel encoders for differential drive robots and car-like robots.
Encoders
Encoders count ticks. They are not a Donkeycar 'part', but rather a Python object, subclassed from class AbstractEncoder, that must be passed to to the Tachometer constructor.
Tachometer
The Tachometer part takes an encoder and the encoder's pulses per revolution in it's constructor and outputs revolutions from it's run()/run_threaded() method.
tachometer.py includes a
__main__
that can be used is isolation from the full donkey framework to test the encoder setup.Odometer
The Odometer part takes the output of a Tachometer (revolutions) and turns revolutions into a distance and velocity. Velocity can be optionally smoothed across a given number of readings. Eventually we will use the velocity output for closed-loop speed control, but that will be in another branch and PR.
Kinematics
The kinematics parts take in the distance output of one or two Odometers and output an estimate of the vehicle's pose; (x,y) position and (angle) of orientation, as well as rate of change components for each of those. For car-like vehicles the distance from a single Odometer is combined with the steering angle to produce the estimate using a Bicycle kinematics part. For differential drive vehicles (or a car-like vehicle that uses two encoders in a differential layout) the distance output from two Odometers are used to produce a pose estimate using the Unicycle kinematics part.
Pose
The a fore mentioned parts are combined into a single part that creates a unitified pipeline that takes in ticks and produces pose and can be run in thread for maximum update rate.
This is a rework of the encoder - tachometer - odometer - kinematics pipeline from branch 921-gps-logger. Prior to this change the individual parts were added to the vehicle. This had several problems;
Templates
The path_follow.py template has been updated to use the kinematics pose estimate to train a path and follow the path in auto-pilot mode.
@TCIII has tested the path_follow template using a differential drive configuration and the mono_encoder.ino sketch to get ticks from an Arduino compatible board. He can successfully record and follow a path.