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 kinematics pose estimation #1089

Merged
merged 29 commits into from
Feb 16, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
1ce5b00
Add tachometer, odometer and kinematics part
Ezward Jan 1, 2023
deeb6fc
refactor pose estimation into a single part
Ezward Jan 8, 2023
d31b163
comment out logging of pose to quiet the console
Ezward Jan 8, 2023
9710c16
add arduino encoder sketches
Ezward Jan 16, 2023
6d66d2c
remove unicode characters that prevent compilation of arduino sketch
Ezward Jan 17, 2023
ff95fdf
clean up comments a little
Ezward Jan 17, 2023
e2a9a54
Add more documentation to the quadrature_encoder.ino sketch
Ezward Jan 18, 2023
325e89b
Add interrupt mode to the mono encoder
Ezward Jan 24, 2023
a5c6a44
Remove spurious unicode beta character
Ezward Jan 24, 2023
ae4ab8f
removed digital write high in mono encoder
Ezward Jan 24, 2023
8f2f859
Fix syntax error if only using one channel in int mode
Ezward Jan 26, 2023
e6eb5cf
Added a quadrature encoder sketch with no libraries
Ezward Jan 28, 2023
162ff35
Fix bug in mono encoder sketch
Ezward Jan 28, 2023
5d05b11
Fix bug in quadrature nolib sketch
Ezward Jan 28, 2023
a4ede0a
minor change to quadrature nolib
Ezward Jan 28, 2023
896cc26
Updated quadrature_encoder.ino to not require library
Ezward Jan 31, 2023
1cf569d
fix merge error in path_follow.py
Ezward Feb 4, 2023
a90421d
Fix RPi_GPIO_Servo part so it does not need GPIO in constructor
Ezward Feb 5, 2023
92af322
added non-threaded run() to UnicyclePose and BicyclePose for testing
Ezward Feb 8, 2023
4e6c371
Improved accuracy of MockEncoder by propagating fractional ticks
Ezward Feb 8, 2023
6d4f506
Updated add_odometry() so we could add as non-threaded for testing.
Ezward Feb 8, 2023
9f2ab20
Vehicle loop prints out number of iterations and total time
Ezward Feb 8, 2023
e9cac78
Rewrite of the kinematics unit tests
Ezward Feb 8, 2023
0cda9b0
Adjust bicycle kinematics to use front wheel reference
Ezward Feb 9, 2023
a1d4f78
relax orientation test to 3% accuracy
Ezward Feb 9, 2023
024fc0f
updated based on PR feedback
Ezward Feb 9, 2023
0ae8db9
removed hard-coded logging level
Ezward Feb 12, 2023
ee22a1b
Update vehicle.py
Ezward Feb 13, 2023
78711a7
Update setup.py version="4.4.dev5"
Ezward Feb 13, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Rewrite of the kinematics unit tests
- 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.
  • Loading branch information
Ezward committed Feb 14, 2023
commit e9cac78f557d9ad49a2616692105ce281e0dbc8c
127 changes: 127 additions & 0 deletions donkeycar/parts/velocity.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
import math
from donkeycar.utils import map_frange, sign

class VelocityNormalize:
"""
Normalize a velocity into to range 0..1.0
given the measured minimum and maximum speeds.
@param min_speed: speed below which car stalls
@param max_speed: car's top speed (may be a target, not a limit)
@param min_normal_speed: the normalized throttle corresponding to min_speed
"""
def __init__(self, min_speed:float, max_speed:float, min_normal_speed:float=0.1) -> None:
self.min_speed = min_speed
self.max_speed = max_speed
self.min_normal_speed = min_normal_speed

def run(self, speed:float) -> float:
s = sign(speed)
speed = abs(speed)
if speed < self.min_speed:
return 0.0
if speed >= self.max_speed:
return s * 1.0
return s * map_frange(
speed,
self.min_speed, self.max_speed,
self.min_normal_speed, 1.0)

def shutdown(self):
pass


class VelocityUnnormalize:
"""
Map normalized speed (0 to 1) to actual speed
"""
def __init__(self, min_speed:float, max_speed:float, min_normal_speed:float=0.1) -> None:
self.min_speed = min_speed
self.max_speed = max_speed
self.min_normal_speed = min_normal_speed

def run(self, speed:float) -> float:
s = sign(speed)
speed = abs(speed)
if speed < self.min_normal_speed:
return 0.0
if speed >= 1.0:
return s * 1.0
return s * map_frange(
speed,
self.min_normal_speed, 1.0,
self.min_speed, self.max_speed)

def shutdown(self):
pass


class StepSpeedController:
"""
Simplistic constant step controller.
Just increases speed if we are too slow
or decreases speed if we are too fast.
Includes feed-forward when reversing direction
or starting from stopped.
"""
def __init__(self, min_speed:float, max_speed:float, throttle_step:float=1/255, min_throttle:float=0) -> None:
"""
@param min_speed is speed below which vehicle stalls (so slowest stable working speed)
@param max_speed is speed at maximum throttle
@param throttle_steps is number of steps in working range of throttle (min_throttle to 1.0)
@param min_throttle is throttle that corresponds to min_speed; the throttle below which the vehicle stalls.
"""
self.min_speed = min_speed
self.max_speed = max_speed
self.min_throttle = min_throttle
self.step_size = throttle_step

def run(self, throttle:float, speed:float, target_speed:float) -> float:
"""
Given current throttle and speed and a target speed,
calculate a new throttle to attain target speed
@param throttle is current throttle (-1 to 1)
@param speed is current speed where reverse speeds are negative
@param throttle_steps number of steps between min_throttle and max_throttle=1.0
@param min_throttle is throttle that corresponds to min_speed
max_throttle is assumed to be 1.0
"""
if speed is None or target_speed is None:
# no speed to control, just return throttle
return throttle

target_direction = sign(target_speed)
direction = sign(speed)

target_speed = abs(target_speed)
speed = abs(speed)

#
# treat speed below minimum as zero
#
if target_speed < self.min_speed:
return 0

#
# when changing direction or starting from stopped,
# calculate a feed-forward throttle estimate
# so we jump into a working range quickly
#
if direction != target_direction:
# if we are going too fast to just reverse, then slow down first
if speed > self.min_speed:
return 0

# calculate first estimate of throttle to achieve target speed
return target_direction * map_frange(target_speed, self.min_speed, self.max_speed, self.min_throttle, 1.0)

#
# modify throttle
#
if speed > target_speed:
# too fast, slow down
throttle -= self.step_size
elif speed > target_speed:
# too slow, speed up
throttle += self.step_size

return target_direction * throttle
Loading