Tuning GoPiGo3 WHEEL_DIAMETER and making it more precise?

After hundreds of turn_degrees() to spin 360 degrees, and of drive_inches() to travel 21 inches forward and backwards, I think I am seeing a consistent variance for movement commands with my GoPiGo3.

To consistently spin 360 degrees [with set_speed(120)], I need to issue turn_degrees(373.5). This amounts to an under-turn of 3.75%. I was even able to repeatably issue ten sequential turns of 373.5 degrees (with 2 second stop delays), and the total directional error after the final turn was the intended direction +/- 2 degrees.

To consistently drive 21 inches, I need to issue a drive_inches(21.8). This amounts to an under-drive of 3.8%

I understand nothing is simple here. Every wheel has a slightly different WHEEL_DIAMETER, and a different contact angle with the floor, Every robot has a slightly different WHEEL_BASE_WIDTH, and toe-in-out. Every motor has a slightly different load response curve. Then there is gear backlash, and start/stop differences between motors that affect consistency.

I also have not measured the error across full to drained battery, other than set_speed(120), and wood floor (with small joints) versus tile floor (with half inch wide, 1/8 inch deep mortared joints - obvious the joints are going to reek havoc).

(My bot is not allowed out of the office onto the tiled and carpeted areas until it is house-broken, but that is for the next post.)

To be seeing a nearly non-variant error of less than 4% is actually quite remarkable, and perhaps is favorable to tuning.

My question: Is it possible to play around with decreasing the WHEEL_DIAMETER by 3.8% (63.98mm) , or will I need to apply my correction factor when issuing commands and when interpreting read_encoder() values (during non-blocking operation or separate threads)?

Will this work?

egpg = easygopigo3.EasyGoPiGo3(use_mutex=True)

# adjust instance "constants" to my particular bot
egpg.WHEEL_DIAMETER = 63.98
egpg.WHEEL_CIRCUMFERENCE = egpg.WHEEL_DIAMETER * math.pi

Example test turns and drives:

===== Spin 373.5 Degrees ========
Encoder Values: 0 0
Turn Processor Time:15.6ms Wall Time:5.5s
Encoder Value: 654 -654
Delta Value: 654 654
Delta Degrees: 371.7 371.7
Accuracy: 99.5% 99.5%
Spin Rate:67.3 dps Wheel Rate:117.9 dps (includes start/stop effect)
=============
 ^^^^ Turn 1 ^^^^

===== Spin 373.5 Degrees ========
Encoder Values: 654 -654
Turn Processor Time:16.2ms Wall Time:5.5s
Encoder Value: 1308 -1309
Delta Value: 654 655
Delta Degrees: 371.7 372.3
Accuracy: 99.5% 99.7%
Spin Rate:67.3 dps Wheel Rate:117.9 dps (includes start/stop effect)
=============
 ^^^^ Turn 2 ^^^^

Drive (21.8 inches)?  (0=reset, +/- change default_dist by 0.1)
x4

===== Drive 21.8 Inches ========
Encoder Values: 1892 1890
Drive 21.8 inches: Processor Time:20.5ms,  Wall Time:8.1s
Encoder Value: 2845 2842
Delta Value: 953 952
Delta Distance: 21.8 21.8
Accuracy: 99.9% 99.8%
Wheel Rate:118.0 dps   (includes start/stop effect)
=============
 ^^^^ Drive 1 ^^^^

===== Drive -21.8 Inches ========
Encoder Values: 2845 2842
Drive -21.8 inches: Processor Time:20.6ms,  Wall Time:8.1s
Encoder Value: 1891 1889
Delta Value: 954 953
Delta Distance: 21.8 21.8
Accuracy: -100.0% -99.9%
Wheel Rate:118.2 dps   (includes start/stop effect)
=============
 ^^^^ Drive 2 ^^^^

This is probably an example of wasteful “thinking small, obsessing over little things”. When I “close my eyes and turn 360”, I have +/- 10 degree variance. Using my eyes, I can move with much greater precision.

Tolerance for error, through recognition, correction, and adaptation is the Little robot, “Think big!” solution.

Perhaps this investigation will identify a tool for adaptation.

Indeed, this works as desired. Today the “magic” number is 64.4 mm to correct a 3.2% under-turn on 360 degree spins.

This is the code I used for testing: wheelDiaRotateTest.py

Moderators: OK to mark this [Solved] now

Hi @cyclicalobsessive,

Let me have my 2 cents here.

I think the question you are raising has a point and the answer you have given yourself partially works.

The problem with the approach of adjusting this WHEEL_DIAMETER variable works - to everyone’s distress, not every time. What if you want to spin the robot 100 times in the same spot? I doubt at the end of this crazy-spinning action the robot will end up in the exact same direction, no matter how precise this variable is or how well-tuned the code is.
I think a solution would be to aggregate multiple sensors that would counterbalance this ever increasing error (drift error). I’m thinking of a compass. I would not go as far as integrating other sensors, because that would put a burden on the CPU and thus reduce the battery life of the robot and because it can get a bit more complex, even though it can make it more precise.

The good thing is that we have a compass and that’s our DI IMU + library - unfortunately we haven’t got an algorithm for that. I’m gonna throw an idea here. Maybe MSF-EKF (Multi-Sensor-Fusion Extended Kalman Filter) is a solution to this kind of problem. I read a paper on this a while back and I found it to be very interesting - maybe you will find it too. Here it is:

Now, to be honest, I’m don’t think this sort of stuff should go in our library because it would make it far too complex for many of our users, thus pointless.

And for all intents and purposes, adding a sensor fusion algorithm in a project of this kind can prove to be useful. Maybe others have experimented with this algorithm presented above, so if any of you have any more information or experience with it, I encourage you to showcase what you have done.

Thank you!

1 Like

It is also possible that you’re hitting the tolerance value of target_reached().

Because there’s so much variance out there, the robot will determine if the target has been reached within a specific tolerance. While we did not offer a way for the end user to change this tolerance, you could do it manually, and see if it works for you.
The code is here. Tolerance is set to 5 “encoder beats”. Since you control your own environment, you can probably lower that to 2, possibly even 0.

Cleo

Doesn’t the target_reached() only control when blocking returns? I thought the board is setting the target and performing the actual stop?

I agree on both sentiments.

I expect to revisit tuning 360 degree spins when I begin working with the camera. I contemplated adding the IMU for my bot, but want to elevate tolerance and adaptation over chasing elusive precision and accuracy.