Yes or not much. For a 16-tick GoPiGo3 the raw encoder counts are 5.33 times per degree of wheel rotation, and for a 6-tick GoPiGo3 the raw encoder counts are 2 times per degree of wheel.
The raw encoder counts are obtainable using the GoPiGo3 class method spi_read_32:
l = gpg.spi_read_32(gpg.SPI_MESSAGE_TYPE.GET_MOTOR_ENCODER_LEFT)
r = gpg.spi_read_32(gpg.SPI_MESSAGE_TYPE.GET_MOTOR_ENCODER_RIGHT)
(and adjusting for values in the negative range.)
def get_raw_LR_encoders(gpg):
"""
Read left and right raw encoder values (in ticks)
For 16-tick GoPiGo3: 1920 ticks per 360 degree wheel revolution
(For 6-tick GoPiGo3: 720 ticks per 360 degree wheel rev)
"""
l = gpg.spi_read_32(gpg.SPI_MESSAGE_TYPE.GET_MOTOR_ENCODER_LEFT)
if DEBUG:
print("left value read: {}".format(l))
if l & 0x80000000:
l = int(l - 0x100000000)
r = gpg.spi_read_32(gpg.SPI_MESSAGE_TYPE.GET_MOTOR_ENCODER_RIGHT)
if DEBUG:
print("right value read: {}".format(r))
if r & 0x80000000:
r = int(r - 0x100000000)
return l,r
The GoPiGo3 API “cleans up” the round-off issue of half tick uncertainty for the 6-tick GoPiGo3s by requiring two ticks before reporting a “one degree encoder tick”. Indeed the 16-tick GoPiGo3s can do better BUT I think we end up with less variability around a poor estimate, rather than a more accurate estimate.
Here is a version of my raw_encoders.py file for reporting the difference between raw encoder readings and the GoPiGo3 API for:
- Drive forward 1m
- Turn clockwise 180 degrees
- Turn counter-clockwise 180 degrees
- Drive backward 1m
with 60 seconds between the actions to allow measuring and resetting to “straight”:
raw_encoders.py
#!/bin/env python3
from easygopigo3 import EasyGoPiGo3
import time
import math
DEBUG = True
rad_to_deg = 180.0/math.pi
def get_raw_LR_encoders(gpg):
"""
Read left and right raw encoder values (in ticks)
For 16-tick GoPiGo3: 1920 ticks per 360 degree wheel revolution
(For 6-tick GoPiGo3: 720 ticks per 360 degree wheel rev)
"""
l = gpg.spi_read_32(gpg.SPI_MESSAGE_TYPE.GET_MOTOR_ENCODER_LEFT)
if DEBUG:
print("left value read: {}".format(l))
if l & 0x80000000:
l = int(l - 0x100000000)
r = gpg.spi_read_32(gpg.SPI_MESSAGE_TYPE.GET_MOTOR_ENCODER_RIGHT)
if DEBUG:
print("right value read: {}".format(r))
if r & 0x80000000:
r = int(r - 0x100000000)
return l,r
def get_LR_encoders_in_degrees(gpg):
"""
Read left and right gopigo3 API encoder values (in degrees)
"""
l = gpg.get_motor_encoder(gpg.MOTOR_LEFT)
r = gpg.get_motor_encoder(gpg.MOTOR_RIGHT)
return l,r
def dHeading_API_in_degrees(end_l, end_r, start_l, start_r, gpg):
dl = (end_l - start_l) / 360 * gpg.WHEEL_CIRCUMFERENCE
dr = (end_r - start_r) / 360 * gpg.WHEEL_CIRCUMFERENCE
dHeading_rad = (dr-dl) / gpg.WHEEL_BASE_WIDTH
dHeading_deg = dHeading_rad * 180.0 / math.pi
return dHeading_deg
def dHeading_raw_in_radians(end_l, end_r, start_l, start_r, gpg):
dl = (end_l - start_l) / gpg.ENCODER_TICKS_PER_ROTATION * gpg.MOTOR_GEAR_RATIO * gpg.WHEEL_CIRCUMFERENCE
dr = (end_r - start_r) / gpg.ENCODER_TICKS_PER_ROTATION * gpg.MOTOR_GEAR_RATIO * gpg.WHEEL_CIRCUMFERENCE
dHeading_rad = (dr-dl) / gpg.WHEEL_BASE_WIDTH
return dHeading_rad
def main():
egpg = EasyGoPiGo3(use_mutex=True)
egpg.set_speed(150)
test_distance_cm = 100 # 1m
test_turn_deg = 180
print("Reset Encoders")
egpg.reset_encoders()
raw_heading = 0
api_heading = 0
start_raw_lenc, start_raw_renc = get_raw_LR_encoders(egpg)
print("Raw Encoders (l,r) ({},{})".format(start_raw_lenc, start_raw_renc))
start_deg_lenc, start_deg_renc = get_LR_encoders_in_degrees(egpg)
print("API Encoders (l,r) ({},{} degrees)".format(start_deg_lenc, start_deg_renc))
print("raw_heading {:.2f} rad {:.1f} deg api_heading {:.1f} deg".format(raw_heading, raw_heading*rad_to_deg, api_heading))
print("\nDrive {}cm".format(test_distance_cm))
egpg.drive_cm(test_distance_cm)
end_raw_lenc, end_raw_renc = get_raw_LR_encoders(egpg)
print("Raw Encoders (l,r) ({},{})".format(end_raw_lenc, end_raw_renc))
end_deg_lenc, end_deg_renc = get_LR_encoders_in_degrees(egpg)
print("API Encoders (l,r) ({},{} degrees)".format(end_deg_lenc, end_deg_renc))
raw_heading = dHeading_raw_in_radians(end_raw_lenc, end_raw_renc, start_raw_lenc, start_raw_renc, egpg)
api_heading = dHeading_API_in_degrees(end_deg_lenc, end_deg_renc, start_deg_lenc, start_deg_renc, egpg)
print("raw_heading {:.2f} rad {:.1f} deg api_heading {:.1f} deg".format(raw_heading, raw_heading*rad_to_deg, api_heading))
print("\nSleeping 60s ...")
time.sleep(60)
print("\nReset Encoders")
egpg.reset_encoders()
raw_heading = 0
api_heading = 0
start_raw_lenc, start_raw_renc = get_raw_LR_encoders(egpg)
print("Raw Encoders (l,r) ({},{})".format(start_raw_lenc, start_raw_renc))
start_deg_lenc, start_deg_renc = get_LR_encoders_in_degrees(egpg)
print("API Encoders (l,r) ({},{} degrees)".format(start_deg_lenc, start_deg_renc))
print("raw_heading {:.2f} rad {:.1f} deg api_heading {:.1f} deg".format(raw_heading, raw_heading*rad_to_deg, api_heading))
print("\nTurn {} deg".format(test_turn_deg))
egpg.turn_degrees(test_turn_deg)
end_raw_lenc, end_raw_renc = get_raw_LR_encoders(egpg)
print("Raw Encoders (l,r) ({},{})".format(end_raw_lenc, end_raw_renc))
end_deg_lenc, end_deg_renc = get_LR_encoders_in_degrees(egpg)
print("API Encoders (l,r) ({},{} degrees)".format(end_deg_lenc, end_deg_renc))
raw_heading = dHeading_raw_in_radians(end_raw_lenc, end_raw_renc, start_raw_lenc, start_raw_renc, egpg)
api_heading = dHeading_API_in_degrees(end_deg_lenc, end_deg_renc, start_deg_lenc, start_deg_renc, egpg)
print("raw_heading {:.2f} rad {:.1f} deg api_heading {:.1f} deg".format(raw_heading, raw_heading*rad_to_deg, api_heading))
print("\nSleeping 60s ...")
time.sleep(60)
print("\nReset Encoders")
egpg.reset_encoders()
raw_heading = 0
api_heading = 0
start_raw_lenc, start_raw_renc = get_raw_LR_encoders(egpg)
print("Raw Encoders (l,r) ({},{})".format(start_raw_lenc, start_raw_renc))
start_deg_lenc, start_deg_renc = get_LR_encoders_in_degrees(egpg)
print("API Encoders (l,r) ({},{} degrees)".format(start_deg_lenc, start_deg_renc))
print("raw_heading {:.2f} rad {:.1f} deg api_heading {:.1f} deg".format(raw_heading, raw_heading*rad_to_deg, api_heading))
print("\nTurn back {} deg".format(-test_turn_deg))
egpg.turn_degrees(-test_turn_deg)
end_raw_lenc, end_raw_renc = get_raw_LR_encoders(egpg)
print("Raw Encoders (l,r) ({},{})".format(end_raw_lenc, end_raw_renc))
end_deg_lenc, end_deg_renc = get_LR_encoders_in_degrees(egpg)
print("API Encoders (l,r) ({},{} degrees)".format(end_deg_lenc, end_deg_renc))
raw_heading = dHeading_raw_in_radians(end_raw_lenc, end_raw_renc, start_raw_lenc, start_raw_renc, egpg)
api_heading = dHeading_API_in_degrees(end_deg_lenc, end_deg_renc, start_deg_lenc, start_deg_renc, egpg)
print("raw_heading {:.2f} rad {:.1f} deg api_heading {:.1f} deg".format(raw_heading, raw_heading*rad_to_deg, api_heading))
print("\nSleeping 60s ...")
time.sleep(60)
print("\nReset Encoders")
egpg.reset_encoders()
raw_heading = 0
api_heading = 0
start_raw_lenc, start_raw_renc = get_raw_LR_encoders(egpg)
print("Raw Encoders (l,r) ({},{})".format(start_raw_lenc, start_raw_renc))
start_deg_lenc, start_deg_renc = get_LR_encoders_in_degrees(egpg)
print("API Encoders (l,r) ({},{} degrees)".format(start_deg_lenc, start_deg_renc))
print("raw_heading {:.2f} rad {:.1f} deg api_heading {:.1f} deg".format(raw_heading, raw_heading*rad_to_deg, api_heading))
print("\nDrive backward {}cm".format(-test_distance_cm))
egpg.drive_cm(-test_distance_cm)
end_raw_lenc, end_raw_renc = get_raw_LR_encoders(egpg)
print("Raw Encoders (l,r) ({},{})".format(end_raw_lenc, end_raw_renc))
end_deg_lenc, end_deg_renc = get_LR_encoders_in_degrees(egpg)
print("API Encoders (l,r) ({},{} degrees)".format(end_deg_lenc, end_deg_renc))
raw_heading = dHeading_raw_in_radians(end_raw_lenc, end_raw_renc, start_raw_lenc, start_raw_renc, egpg)
api_heading = dHeading_API_in_degrees(end_deg_lenc, end_deg_renc, start_deg_lenc, start_deg_renc, egpg)
print("raw_heading {:.2f} rad {:.1f} deg api_heading {:.1f} deg".format(raw_heading, raw_heading*rad_to_deg, api_heading))
if __name__ =='__main__':
main()
It would be interesting to hear your bots’ results.
Carl drove “straight 1m” to within 2mm off to the right , and turned just short of 180, back exactly to his original heading, then returned to within 3mm off of straight back to his original position and heading - That is like super impressive, no?
pi@Carl:~/Carl/systests/encoders $ ./raw_encoders.py
Reset Encoders
left value read: 0
right value read: 0
Raw Encoders (l,r) (0,0)
API Encoders (l,r) (0,0 degrees)
raw_heading 0.00 rad 0.0 deg api_heading 0.0 deg
Drive 100cm
left value read: 3561
right value read: 3557
Raw Encoders (l,r) (3561,3557)
API Encoders (l,r) (1781,1778 degrees)
raw_heading -0.00 rad -0.2 deg api_heading -0.8 deg
Sleeping 60s ...
Reset Encoders
left value read: 0
right value read: 0
Raw Encoders (l,r) (0,0)
API Encoders (l,r) (0,0 degrees)
raw_heading 0.00 rad 0.0 deg api_heading 0.0 deg
Turn 180 deg
left value read: 645
right value read: 4294966655
Raw Encoders (l,r) (645,-641)
API Encoders (l,r) (322,-320 degrees)
raw_heading -1.17 rad -67.2 deg api_heading -178.8 deg
Sleeping 60s ...
Reset Encoders
left value read: 1
right value read: 4294967295
Raw Encoders (l,r) (1,-1)
API Encoders (l,r) (0,0 degrees)
raw_heading 0.00 rad 0.0 deg api_heading 0.0 deg
Turn back -180 deg
left value read: 4294966651
right value read: 640
Raw Encoders (l,r) (-645,640)
API Encoders (l,r) (-322,320 degrees)
raw_heading 1.17 rad 67.2 deg api_heading 178.8 deg
Sleeping 60s ...
Reset Encoders
left value read: 4294967295
right value read: 0
Raw Encoders (l,r) (-1,0)
API Encoders (l,r) (0,0 degrees)
raw_heading 0.00 rad 0.0 deg api_heading 0.0 deg
Drive backward -100cm
left value read: 4294963735
right value read: 4294963739
Raw Encoders (l,r) (-3561,-3557)
API Encoders (l,r) (-1780,-1778 degrees)
raw_heading 0.00 rad 0.2 deg api_heading 0.6 deg
pi@Carl:~/Carl/systests/encoders $
(There’s was math error on the raw encoder heading values - I hardcoded 1920 ticks per rev instead of reading from the GoPiGo3 config, so wrong for Carl. I fixed it in the code above.)
Dave drove “1m straight” and ended up 2cm to the right and headed 2-3 degrees off clockwise, while his encoders claimed a heading of 0.0 deg using the raw readings, and -0.3 deg using the GoPiGo3 API.
Drive 100cm
left value read: 9254
right value read: 9253
Raw Encoders (l,r) (9254,9253)
API Encoders (l,r) (1735,1734 degrees)
raw_heading 0.00 rad 0.0 deg api_heading -0.3 deg