In a project I haven't talked too much about here on Cemetech yet, I'm building a set of physical controls for Train Simulator, including gauges, buttons, throttle/brake, etc. (build log part 1 and build log part 2). In part 1, I describe my process of tearing down a cheap aftermarket tachometer and reusing its two H-bridges and stepper motor with a Raspberry Pi Pico controller.

It works pretty well (photos in the log above), but the microstepping does not produce consistently sized angular steps: the microsteps close to a full step are small, and the microsteps midway between full steps are large. I wracked my brain quite a bit in January, and performed testing (including sanity checking by measuring and charting current draw through a single coil with PWM duty cycle from 0% to 100% versus a theoretical current assuming a 5mA drop through the attached current limiting resistor and finding it to be linear). Any debugging approaches would be greatly appreciated.

My microstepping table is generated as follows:
   size_t increments = 0;
   for(size_t phase = 0; phase < 4; ++phase) {
      for(size_t microstep = 0; microstep < MICROSTEPS; ++microstep, ++increments) {
         double angle = increments * (M_PI / 2. / MICROSTEPS);
         microstepping_store[phase][microstep][0] = (int)(100. * std::sin(angle));
         microstepping_store[phase][microstep][1] = (int)(100. * std::cos(angle));
   microstepping_store[2][0][0] = -0;

This table is used as follows with this PIO program:

void PicoStepper::stepMotor(int step, int microstep) {

  int coil0 = microstepping_store[step][microstep][0];
  int coil2 = microstepping_store[step][microstep][1];
  int phase0 = 0;
  int count0 = (coil0 >= 0 ? coil0 : -coil0);
  count0 = (count0 > 0) ? (count0 - count0Offset) : 0;

  int phase2 = 0;
  int count2 = coil2 >= 0 ? coil2 : -coil2;
  count2 = (count2 > 0) ? (count2 - count2Offset) : 0;

   if (coil0 > 0) {
      phase0 = 0b1000;
   } else if (coil0 < 0) {
      phase0 = 0b0100;
   if (coil2 > 0) {
      phase2 = 0b0010;
   } else if (coil2 < 0) {
      phase2 = 0b0001;
   const int phase1 = phase0 | phase2;
   int count1 = maxPWM - count0 - count2 - count1Offset;

   pio_sm_put(pio_, sm_, (count2 << 25) | (phase2 << 21) | (count1 << 15) | (phase1 << 11) | (count0 << 4) | phase0);
I don't have much familiarity with stepper motor control, but these comments about accuracy from the Wikipedia page on stepper motors seem relevant to your observations:
many modern hybrid step motors are rated such that the travel of every full step (example 1.8 degrees per full step or 200 full steps per revolution) will be within 3% or 5% of the travel of every other full step, as long as the motor is operated within its specified operating ranges. Several manufacturers show that their motors can easily maintain the 3% or 5% equality of step travel size as step size is reduced from full stepping down to 1/10 stepping. Then, as the microstepping divisor number grows, step size repeatability degrades. At large step size reductions it is possible to issue many microstep commands before any motion occurs at all and then the motion can be a "jump" to a new position.[6] Some stepper controller ICs use increased current to minimise such missed steps, especially when the peak current pulses in one phase would otherwise be very brief.
Does the accuracy improve if you reduce the number of microsteps?

I'd have guessed that a gauge like that would often use a servo rather than stepper motor, but perhaps the stepper is cheaper. In any case, I imagine a servo would be easier to drive with the desired precision.
Random note on a later phase of this project: although the original stepper I was using was a normal bipolar stepper, the latest ones I'm using are actually Lavet-type, which means they need a 6-state sequence. I've moved far beyond what I was testing here for code wrapped around this library, but the stepping and microstepping itself hasn't changed much. I'm going to next try porting this to the Pico:
Register to Join the Conversation
Have your own thoughts to add to this or any other topic? Want to ask a question, offer a suggestion, share your own programs and projects, upload a file to the file archives, get help with calculator and computer programming, or simply chat with like-minded coders and tech and calculator enthusiasts via the site-wide AJAX SAX widget? Registration for a free Cemetech account only takes a minute.

» Go to Registration page
Page 1 of 1
» All times are UTC - 5 Hours
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum