Driving distance and turning angle still don't work right

With library release 1.0.5.4b, Sparki still does not drive the distance I specify or turn the angle I want: distances and angles both fall short, although angles are closer than distance.

When I unleash Sparki on a group of middle school students, I want to start by having them draw some geometric shapes (e.g. a square or a five-pointed star). Once that’s accomplished, I may want them to navigate a maze by hard-coding the required distances and angles. (Solving the maze with sensors will come later.) Obviously, none of this will work if Sparki does not drive distances or turn angles as advertised.

I’m disappointed that this basic function is not working correctly, especially after the 1.0.5.4 release, which includes the release note “turning by degrees is now accurate”. How was this tested? Just have Sparki draw a 10cm-per-side square, and it will be obvious that it’s not working.

All right… Now that I’ve complained, here’s the solution:

The magic numbers in moveForward(), moveBackward(), moveRight() and moveLeft() within the Sparki.cpp library need to be changed.

The 222.222222 in this code (and moveBackward):

void SparkiClass::moveForward(float cm) { float run = 222.222222*cm; if( (cm == -1) || (cm == 0) ){ moveForward(); } else{ moveForward(); delay(run); moveStop(); } }

needs to be 306.775834.

Similarly the 21.38888 here (and in moveLeft):

void SparkiClass::moveRight(float deg) { float turn = 21.388888*deg; if( (deg == -1) || (deg == 0) ){ moveRight(); } else{ moveRight(); delay(long(turn)); moveStop(); } }

needs to be 22.755556.

With these numbers, my 10cm by 10cm square start to look pretty good. It’s still off a little bit, in part, I think, due to the error I wrote about in this post: [url]Stepper Motor Spec: Steps per Revolution?]

If you’re wondering where the numbers are coming from:

[code]wheel_diameter = 51 mm (my measured value)

wheel_circumference = 51 mm * pi = 160.2212 mm

distance_per_wheel_revolution = wheel_circumference = 160.2212 mm / rev

target_distance = 10 mm
(10mm or 1 cm is the baseline distance of the move functions)

target_revolutions = target_distance / distance_per_wheel_revolution
= 10 mm / ( 160.2212 mm / rev )
= 0.06241 rev

motor_steps_per_revolution = 4096 steps / rev
(again, see this post: Stepper Motor Spec: Steps per Revolution?)

target_steps = motor_steps_per_revolution * target_revolutions
= 4096 steps / rev * 0.06241 rev
= 255.6465 steps

base_time_per_step = 200 us = 0.2 ms
(see this post: Interrupt rate is not as advertised)

speed_scalar = 6
(another magic number; see below)

target_run_time = target_steps * base_time_per_step * speed_scalar
= 255.6465 steps * 0.2 ms * 6
= 306.7758 ms[/code]

Or, by carrying a few more digits with the help of Microsoft Excel, I get 306.775834 ms per centimer.

After I did the above calculation with my measured wheel diameter of 51mm, I saw in the Sparki.h file that the wheel diameter is defined there as 51.5mm. If I plug that in, the new answer is 303.7974277 ms per centimeter (and 22.534628 ms per degree).

The scale factor for angles is a continuation of this math, given that the wheel-to-wheel spacing is 85mm. That 85mm seems to be a good number, but your mileage may vary. I’ve measured two Sparkis, and the spacing actually varies around the 85mm. For folks who really need accurate angles, maybe the library could implement a function that takes the actual wheel separation (as measured by the Sparki owner) and then applies an appropriate scale factor?

With regard to the magic speed_scalar of 6, this number comes from

in motorRotate() and from this code

if( speedCounter[motor] == 0) { // step_index[motor] += step_dir[motor]; remainingSteps[motor]--; speedCounter[motor] = speedCount[motor]; } else{ speedCounter[motor] = speedCounter[motor]-1; }

in the interrupt service routine. I suspect that the speed_scalar was actually supposed to be 5, but it works out to 6. I find this code unnecessarily confusing.

Overall, I have to ask: Why use this time or delay-based approach to moving specific distances or angles?

The distance-to-delay and angle-to-delay scale factors for the moveForward/Backward and moveLeft/Right functions are dependent on the interrupt rate and the speed setting. If either of those changes, then the scale factors need to be fixed again. Why not convert the target distance into required motor steps and then just drive that number of steps??? In other words, I think the moveForward/Backward and moveLeft/Right functions should be leveraging motorsRotateSteps() instead of doing this delay-based stuff.

From the numbers you give to correct the angles, it seems like you’re seeing 6% error - right?

From my experience, I don’t think I’m seeing anywhere near that, but I’ll check again next time I have sparki out.

I’m wondering, is there any difference between the original and ‘blue’ ones? I got mine from Makershed.

Only difference is the color, electronics are all the same.

@jle:

I’d be curious to learn how your Sparki performs with the 1.0.5.4b library. If you get a chance, can you try drawing a 10cm x 10cm square and report back?

@roboalchemist:

I take it that means that the physical dimensions of Sparki, specifically wheel diameter and separation, have also not changed?

The magic scale factors for distance and angle depend on:

  1. wheel diameter (hardware)
  2. wheel separation (hardware)
  3. steps-per-revolution of the stepper motors (hardware)
  4. frequency of the interrupt routine that updates the motors (library software)
  5. the magic speed scalar (library software)

What was the original math that produced the 222.222222 and 21.388888 that are in the current library code?

Apparently, the angles didn’t seem that bad before because I wasn’t trying to draw squares.

You are absolutely right about the correction factors.

I drew a square using 90 and it’s way off.
Using 95 was just about dead on - and that matches with your corrected value
22.755556/21.38888 = 1.063896
95/90 = 1.0555

So, I went ahead an modified sparki.cpp with your numbers. It’s really close, but I drew 5 squares on top of each other and the cumulative error is a couple of degrees.

The version I’m using is the feb 24th version off of github. No changes had been made to the turn stuff as far as I can tell.

Thanks for trying the square. It’s good to know I’m not completely crazy.

Yeah, it’s still a little bit off even with the new numbers. Part of that could be that I took the wheel diameter to be 51.0mm, but maybe the 51.5mm from the Sparki library header file is more correct. If you want to give that a try, use 303.7974277 ms per centimeter and 22.534628 ms per degree. I’ll try that also but probably won’t have time for that until the weekend.

I also noticed that 4096 steps turn a wheel a little bit more than one full revolution. 4096 stepper motor steps should be exactly one revolution, so somewhere there’s another source of error. So far, I don’t know what’s going on. There may be a software bug I have not found, or maybe the gear ratio in the stepper motor is not exactly 64:1?

Its known to be off, I’ll be figuring out how much for the next update. I got caught up doing some business-side things the last couple of weeks, but the next update should be coming next week.

Thanks for the response.

It was off by a lot, and I hoped that issues like this wouldn’t end up in a release, especially when the release notes include the statement “turning by degrees is now accurate”.

Anyhow… If you want to take it, I fixed it for you in the pull request that I submitted on GitHub.