Motor Encoder - Program an action for every loop

My project is a six barrel gatling gun (mini-gun) toy. My current goal is to have the light inside the barrel light up when the barrel reaches the top of the circle. I

I'm using a DC motor with an encoder. The encoder gets 408.168 counts per rotation.

Barrel 1 will be in the correct position at startup, when the encoder is at 0.
Barrel 2 will be in the correct position at 68 counts
Barrel 3 will be in the correct position at 136 counts so on and so on.

I also want to set a duration variable for how long the light stays on i.e. Barrel 1 will stay on from 0 counts to 10 counts. int duration =10;

This is all easy to write a program for for one rotation, but what if I just want it to perpetually spin. I don't want to reset the encoder counts at 408 because that decimal of .168 will compound with each rotation and eventually make it off.

I started writing an obscenely verbose if statement array

if (   encoderBarrell >= (barrellOneStart) && encoderBarrell <= (barrellOneStart + barrellDuration)   )    || 
   (   encoderBarrell >= (barrellOneStart + (408*1) && encoderBarrell <= (barrellOneStart + (408*1)) + barrellDuration)  ||
   (   encoderBarrell >= (barrellOneStart + (408*2) && encoderBarrell <= (barrellOneStart + (408*2)) + barrellDuration)  ||
   (   encoderBarrell >= (barrellOneStart + (408*3) && encoderBarrell <= (barrellOneStart + (408*3)) + barrellDuration)  ||

But then decided to see if there was a better solution for this. Does anyone know of any easier way to perform this kind of work?

Do I understand that you are getting FRACTIONAL counts from an encoder that only is able to have integer counts?
Paul

Yes that is correct. I think the number of counts doesn't equal out to a complete rotation: Here is the page for the motor: https://www.pololu.com/product/4844

The encoder is capable of 1632.67 counts per rotation if you count the rise and fall of each sensor. I'm counting the rise of just one (1632.67/4 = 408.1675)

Do you need that resolution? It might not be too hard to make, say, a 6 count per rev encoder with a Hall Effect switch or optical sensor. Then use millis() for the dwell.

I probably don't need that high of resolution, but I do want to make the first barrel return to the top position when it slows to a stop. This way it will always be reset properly. To do that I think I would probably need more than the six steps, but probably not 408.

I have thought about using an absolute position encoder rather than relative, but this is really just a toy and I don't want to start getting into more expensive components if I don't need to. I just figured there is so much about the coding side things I"m not aware of that I might just be missing a function or library that can handle this kind of thing.

i believe you need to accumulate the frac, 0.168 each complete rotation, cnt > 408, and whenever the accumulated fraction > 1, subtract 409 instead of 408 from your count as well as subtracting 1 from the accumulation

Yeah I think you're right. I have an excel sheet set up that does just that for me. I'm just not sure if the best way to implement it into code without writing 50,000 if statements.

I guess I don't mind doing it if that's the way. I just didn't know if there was something more efficient

Maybe try x = (count x 1000) % 408168

x will roll over to zero every time count = 408168

flash your light when x=0, 68028, 136056, 204084, etc.

% = modulo
https://www.arduino.cc/en/pmwiki.php?n=Reference/Modulo

Ooooohhhhh. That's fine good thinking

Without having to write all the "flash light if" statements is there an easy way to do that just as a multiple? I.e every multiple of 68028 flash light

If you could mount magnets in or on the barrels you could make a six PPR encoder.  "Fire" each barrel when its magnet passes a Hall switch.  Mount the magnet on barrel '1' a few inches further along (out of range) than the others and add another Hall switch for a home position sensor.

YMMV

Yes, using modulo as suggested

if(count % 68028 == 0)
{
  //doSomething 
}

if you reset your count correctly (!) each revolution, wouldn't you only need the following to determine when a barrel is at top

    if (! (cnt % 68))

Thank you, I'll continue looking into this method.

Thank you for your help! I'll keep working with this!

does this look right to you

there's a line whenever (! (cnt % 68))
1st column is the absolute count
2nd column is a running count is the cnt that's reset each complete rotation
3rd is the adjust offset reduced by 1.0 when >= 1.0
4th column indicates when the extra adjustment is made

       68     68    0.000      barrel
      136    136    0.000      barrel
      204    204    0.000      barrel
      272    272    0.000      barrel
      340    340    0.000      barrel
      408    408    0.000      barrel
      476     68    0.168      barrel
      544    136    0.168      barrel
      612    204    0.168      barrel
      680    272    0.168      barrel
      748    340    0.168      barrel
      816    408    0.168      barrel
      884     68    0.336      barrel
      952    136    0.336      barrel
     1020    204    0.336      barrel
     1088    272    0.336      barrel
     1156    340    0.336      barrel
     1224    408    0.336      barrel
     1292     68    0.504      barrel
     1360    136    0.504      barrel
     1428    204    0.504      barrel
     1496    272    0.504      barrel
     1564    340    0.504      barrel
     1632    408    0.504      barrel
     1700     68    0.672      barrel
     1768    136    0.672      barrel
     1836    204    0.672      barrel
     1904    272    0.672      barrel
     1972    340    0.672      barrel
     2040    408    0.672      barrel
     2108     68    0.840      barrel
     2176    136    0.840      barrel
     2244    204    0.840      barrel
     2312    272    0.840      barrel
     2380    340    0.840      barrel
     2448    408    0.840      barrel
     2449      0    0.008   *  barrel
     2517     68    0.008      barrel
     2585    136    0.008      barrel
     2653    204    0.008      barrel
     2721    272    0.008      barrel
     2789    340    0.008      barrel
     2857    408    0.008      barrel
     2925     68    0.176      barrel
     2993    136    0.176      barrel
     3061    204    0.176      barrel
     3129    272    0.176      barrel
     3197    340    0.176      barrel
     3265    408    0.176      barrel
     3333     68    0.344      barrel
     3401    136    0.344      barrel
     3469    204    0.344      barrel
     3537    272    0.344      barrel
     3605    340    0.344      barrel
     3673    408    0.344      barrel
     3741     68    0.512      barrel
     3809    136    0.512      barrel
     3877    204    0.512      barrel
     3945    272    0.512      barrel
     4013    340    0.512      barrel
     4081    408    0.512      barrel
     4149     68    0.680      barrel
     4217    136    0.680      barrel
     4285    204    0.680      barrel
     4353    272    0.680      barrel
     4421    340    0.680      barrel
     4489    408    0.680      barrel
     4557     68    0.848      barrel
     4625    136    0.848      barrel
     4693    204    0.848      barrel
     4761    272    0.848      barrel
     4829    340    0.848      barrel
     4897    408    0.848      barrel
     4898      0    0.016   *  barrel
     4966     68    0.016      barrel

Yeah man, that matches my excel Sheet exactly. My column 1 matches your column 2 which I think is the most important part as far as the correct integer value with the remainder added when appropriate.

code for output in post #16

#include <stdio.h>

const int   PulsePerRot = 408;
const float OffsetInc   = 0.168;

long  enc;

void
gatling (void)
{
    static float offset;
    static int   cnt;
    int          tic = 0;

    cnt++;

    if (PulsePerRot < cnt)  {
        cnt    -= PulsePerRot;
        offset += OffsetInc;
        if (1 <= offset)  {
            offset -= 1;
            cnt--;
            tic++;
        }
    }

    if (! (cnt % 68))
        printf (" %8d %6d %8.3f %3s  barrel\n",
            enc, cnt, offset, tic ? "*" : " ");
}

int
main ()
{
    for (enc = 1 ; 5000 > enc; enc++)
        gatling();

    return 0;
}
1 Like

Oh wow. This is incredible. Let me try to wrap my head around this and implement into my code.
Seriously, this is above and beyond, thank you so much.