User avatar
HermannSW
Posts: 5301
Joined: Fri Jul 22, 2016 9:09 pm
Location: Eberbach, Germany

pigpio C library with half-stepping for ULN2003 + 28BYJ-48 stepper motor?

Wed Nov 13, 2019 12:31 pm

I did cool stuff recently with half-stepping the 28BYJ-48 (4096 steps per revolution).
That stuff was done with Arduino Uno and AccelStepper library.

I want to move over to Raspberry controlling the stepper motors.
And I have used pigpio a lot.

I need to drive stepper motors from C, is there a pigpio based library for half-stepping with ULN2003 driver?
(I found several Python libraries)

Plan is to auto center camera while capturing video of airplane approach for landing.
I used 4 drops of superglue to build a high precision PT camera system:
https://www.raspberrypi.org/forums/view ... 9#p1565376
Image
https://hermann-sw.github.io/planar_graph_playground
https://stamm-wilbrandt.de/en#raspcatbt
https://github.com/Hermann-SW/memrun
https://github.com/Hermann-SW/Raspberry_v1_camera_global_external_shutter
https://stamm-wilbrandt.de/en/Raspberry_camera.html

User avatar
joan
Posts: 16001
Joined: Thu Jul 05, 2012 5:09 pm
Location: UK

Re: pigpio C library with half-stepping for ULN2003 + 28BYJ-48 stepper motor?

Wed Nov 13, 2019 5:36 pm

Not a library, just some code to turn a 28BYJ-48. I'm not sure if this is half-stepping or not (I've heard the term, never found out what it means).

Code: Select all

#include <stdio.h>

#include <pigpio.h>

#define STEP_DELAY 2000

/*
2000  7 RPM
1500  9 RPM
1000 13 RPM
 900 15 RPM
*/

#define Pin1 14
#define Pin2 15
#define Pin3 17
#define Pin4 18

int step = 0; 

void loop() 
{ 
   switch(step)
   { 
   case 0: 
     gpioWrite(Pin1, PI_LOW);  
     gpioWrite(Pin2, PI_LOW); 
     gpioWrite(Pin3, PI_LOW); 
     gpioWrite(Pin4, PI_HIGH); 
   break;  
   case 1: 
     gpioWrite(Pin1, PI_LOW);  
     gpioWrite(Pin2, PI_LOW); 
     gpioWrite(Pin3, PI_HIGH); 
     gpioWrite(Pin4, PI_HIGH); 
   break;  
   case 2: 
     gpioWrite(Pin1, PI_LOW);  
     gpioWrite(Pin2, PI_LOW); 
     gpioWrite(Pin3, PI_HIGH); 
     gpioWrite(Pin4, PI_LOW); 
   break;  
   case 3: 
     gpioWrite(Pin1, PI_LOW);  
     gpioWrite(Pin2, PI_HIGH); 
     gpioWrite(Pin3, PI_HIGH); 
     gpioWrite(Pin4, PI_LOW); 
   break;  
   case 4: 
     gpioWrite(Pin1, PI_LOW);  
     gpioWrite(Pin2, PI_HIGH); 
     gpioWrite(Pin3, PI_LOW); 
     gpioWrite(Pin4, PI_LOW); 
   break;  
   case 5: 
     gpioWrite(Pin1, PI_HIGH);  
     gpioWrite(Pin2, PI_HIGH); 
     gpioWrite(Pin3, PI_LOW); 
     gpioWrite(Pin4, PI_LOW); 
   break;  
     case 6: 
     gpioWrite(Pin1, PI_HIGH);  
     gpioWrite(Pin2, PI_LOW); 
     gpioWrite(Pin3, PI_LOW); 
     gpioWrite(Pin4, PI_LOW); 
   break;  
   case 7: 
     gpioWrite(Pin1, PI_HIGH);  
     gpioWrite(Pin2, PI_LOW); 
     gpioWrite(Pin3, PI_LOW); 
     gpioWrite(Pin4, PI_HIGH); 
   break;  
   default: 
     gpioWrite(Pin1, PI_LOW);  
     gpioWrite(Pin2, PI_LOW); 
     gpioWrite(Pin3, PI_LOW); 
     gpioWrite(Pin4, PI_LOW); 
   break;  
   }
} 

int main(int argc, char * argv[])
{
   int i;
   int step_delay = STEP_DELAY;

   if (argc > 1) step_delay = atoi(argv[1]);

   if ((step_delay < 800) || (step_delay>1000000)) step_delay = STEP_DELAY;

   if (gpioInitialise()<0) return 1;

   gpioSetMode(Pin1, PI_OUTPUT);  
   gpioSetMode(Pin2, PI_OUTPUT);  
   gpioSetMode(Pin3, PI_OUTPUT);  
   gpioSetMode(Pin4, PI_OUTPUT);  

   for (i=0; i<9000000; i++)
   {
      loop();
      step++;
      if (step>7) step = 0;
      gpioDelay(step_delay);
   }

   gpioTerminate();
}

User avatar
HermannSW
Posts: 5301
Joined: Fri Jul 22, 2016 9:09 pm
Location: Eberbach, Germany

Re: pigpio C library with half-stepping for ULN2003 + 28BYJ-48 stepper motor?

Wed Nov 13, 2019 8:58 pm

THANK YOU!

That got me going, I made a little demo for my ̶s̶e̶r̶v̶o̶ stepper PT camera system:
(1024 steps do a 90° change, so the code does half-stepping)

Code: Select all

/*
   $ gcc -O6 -o pt pt.c -lpigpio -lrt -lpthread
   $
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <assert.h>

#include <pigpio.h>

#define L 1024
#define D 1000

unsigned m[][4]={
  {14,15,17,18},
  {27,22,23,24}
};

int b[8]={0b0001, 0b011, 0b0010, 0b0110, 0b0100, 0b1100, 0b1000, 0b1001};

int M=sizeof(m)/sizeof(m[0]);
int N=sizeof(m[0])/sizeof(m[0][0]);

void gpiosWrite(int *p, unsigned v)
{
  for(int i=0; i<N; ++i)
    gpioWrite( p[i], (v&(1<<i)) ? 1 : 0 );
}

void hstep(int mn, unsigned v)
{
  gpiosWrite(m[mn], b[v & 0x7]);
}

void hstep2(int x, int y)
{
  hstep(0,x); hstep(1,y); usleep(D);
}

int main(int argc, char *argv[])
{
  int i,j,x=0,y=0;

  assert(gpioInitialise()>=0);

  for(i=0; i<M; ++i)
    for(j=0; j<N; ++j)
    {
      gpioSetMode(m[i][j], PI_OUTPUT);
      gpioWrite(m[i][j], 0);
    }

  hstep2(x,y);

  for(i=0; i<L/2; ++i) hstep2(x,++y);
  for(i=0; i<L; ++i) hstep2(x,--y);
  for(i=0; i<L/2; ++i) hstep2(x,++y);

  for(i=0; i<L/2; ++i) hstep2(++x,y);
  for(i=0; i<L; ++i) hstep2(--x,y);
  for(i=0; i<L/2; ++i) hstep2(++x,y);
     
  for(i=0; i<L/2; ++i) hstep2(++x,++y);
  for(i=0; i<L; ++i) hstep2(--x,--y);
  for(i=0; i<L/2; ++i) hstep2(++x,++y);
     
  for(i=0; i<L/2; ++i) hstep2(--x,++y);
  for(i=0; i<L; ++i) hstep2(++x,--y);
  for(i=0; i<L/2; ++i) hstep2(--x,++y);
     
  gpioTerminate();
}
Image


I already have red ball at end of pendulum for playing role of dark airplane before bright sky:
Image


With above code and the code I have to analyze each video frame while it gets recorded, next step is to develop automatic centering at airplane (red ball) while recording. This will be basis for new "Advanced non-modifying pipeline" section:
https://github.com/Hermann-SW2/userland ... i420toh264

This is advanced modyfing pipeline example, for each frame airplane position gets determined, and a white 2x2 dot is painted onto the determined position. This white dot is part of the .h264 video created at end of pipeline. Automatic centering will not modify frame, but both PT camera system ̶s̶e̶r̶v̶o̶ stepper positions while recording.
Image
https://hermann-sw.github.io/planar_graph_playground
https://stamm-wilbrandt.de/en#raspcatbt
https://github.com/Hermann-SW/memrun
https://github.com/Hermann-SW/Raspberry_v1_camera_global_external_shutter
https://stamm-wilbrandt.de/en/Raspberry_camera.html

User avatar
HermannSW
Posts: 5301
Joined: Fri Jul 22, 2016 9:09 pm
Location: Eberbach, Germany

Re: pigpio C library with half-stepping for ULN2003 + 28BYJ-48 stepper motor?

Thu Nov 14, 2019 12:57 pm

A common task for stepper PT camera system is to bring stepper motors into some application specific initial position.
Below simple tool move.c does allow for exactly that.

I typically run raspivid preview in desired mode for PT camera on HDMI monitor.
Then I use move.c for positioning (4096 steps are 1 revolution of 28BYJ-48 stepper motor):

Code: Select all

$ raspivid -md 1 -w 1920 -h 1080 -p 22,50,960,540 -t 0 &
[1] 1546
$ ./move
move: move.c:44: main: Assertion `((argc+1)/2==2) || !"Format: sudo ./move dx dy [D]"' failed.
Aborted
$ sudo ./move 20 -30
$
move.c:

Code: Select all

/*
   $ gcc -Wall -Wextra -O6 -o move move.c -lpigpio -lpthread
   $
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <assert.h>

#include <pigpio.h>

int D=1000;

unsigned m[][4]={
  {14,15,17,18},
  {27,22,23,24}
};

int b[8]={0b0001, 0b011, 0b0010, 0b0110, 0b0100, 0b1100, 0b1000, 0b1001};

int M=sizeof(m)/sizeof(m[0]);
int N=sizeof(m[0])/sizeof(m[0][0]);

void gpiosWrite(unsigned *p, unsigned v)
{
  for(int i=0; i<N; ++i)
    gpioWrite( p[i], (v&(1<<i)) ? 1 : 0 );
}

void hstep(int mn, unsigned v)
{
  gpiosWrite(m[mn], b[v & 0x7]);
}

void hstep2(int x, int y)
{
  hstep(0,x); hstep(1,y); usleep(D);
}

int main(int argc, char *argv[])
{
  int i,j,x=0,y=0,dx,dy;

  assert(((argc+1)/2==2) || !"Format: sudo ./move dx dy [D]");
 
  assert(gpioInitialise()>=0);

  dx = atoi(argv[1]);
  dy = atoi(argv[2]);
  if (argc==4) {
    D = atoi(argv[3]);
    D = (D<1000) ? 1000 : D;
  }

  for(i=0; i<M; ++i)
    for(j=0; j<N; ++j)
    {
      gpioSetMode(m[i][j], PI_OUTPUT);
      gpioWrite(m[i][j], 0);
    }

  hstep2(x,y);

  for(i=0; i<dx; ++i) hstep2(++x,y);
  for(i=0; i>dx; --i) hstep2(--x,y);
  for(i=0; i<dy; ++i) hstep2(x,++y);
  for(i=0; i>dy; --i) hstep2(x,--y);
     
  gpioTerminate();
}
Last edited by HermannSW on Thu Nov 14, 2019 5:06 pm, edited 2 times in total.
https://hermann-sw.github.io/planar_graph_playground
https://stamm-wilbrandt.de/en#raspcatbt
https://github.com/Hermann-SW/memrun
https://github.com/Hermann-SW/Raspberry_v1_camera_global_external_shutter
https://stamm-wilbrandt.de/en/Raspberry_camera.html

User avatar
joan
Posts: 16001
Joined: Thu Jul 05, 2012 5:09 pm
Location: UK

Re: pigpio C library with half-stepping for ULN2003 + 28BYJ-48 stepper motor?

Thu Nov 14, 2019 1:13 pm

That is a lot tidier than my code!

You can clear/set multiple GPIO at a time. I know it's a pretty pointless optimisation but it does no harm to be aware of it. As in this Python snippet.

Code: Select all

class stepper:
   """
   A class to pulse a stepper.
   """

   def __init__(self, pi, g1, g2, g3, g4):
      """
      """
      self.pi = pi
      self.g1 = g1
      self.g2 = g2
      self.g3 = g3
      self.g4 = g4
      self.all = (1<<g1 | 1<<g2 | 1<<g3 | 1<<g4)
      self.pos = 0

      pi.set_mode(g1, pigpio.OUTPUT)
      pi.set_mode(g2, pigpio.OUTPUT)
      pi.set_mode(g3, pigpio.OUTPUT)
      pi.set_mode(g4, pigpio.OUTPUT)

   def move(self):
      pos = self.pos 
      if pos < 0:
         pos = 7
      elif pos > 7:
         pos = 0
      self.pos = pos

      if   pos == 0: on = (1<<self.g4)
      elif pos == 1: on = (1<<self.g3 | 1<<self.g4)
      elif pos == 2: on = (1<<self.g3)
      elif pos == 3: on = (1<<self.g2 | 1<<self.g3)
      elif pos == 4: on = (1<<self.g2)
      elif pos == 5: on = (1<<self.g1 | 1<<self.g2)
      elif pos == 6: on = (1<<self.g1)
      else:          on = (1<<self.g1 | 1<<self.g4)

      off = on ^ self.all

      self.pi.clear_bank_1(off)
      self.pi.set_bank_1(on)

   def forward(self):
      self.pos += 1
      self.move()

   def backward(self):
      self.pos -= 1
      self.move()

User avatar
HermannSW
Posts: 5301
Joined: Fri Jul 22, 2016 9:09 pm
Location: Eberbach, Germany

Re: pigpio C library with half-stepping for ULN2003 + 28BYJ-48 stepper motor?

Thu Nov 14, 2019 5:11 pm

That code looks tidy as well, and it is good to know about setting multiple GPIOs.

In another thread I used move tool for taking first video, find details there:
https://forum.arduino.cc/index.php?topi ... msg4371497

Result is promising, shutter time 1/100 second, animation scaled down by factor 6 to get from 107MB to 3.5MB size. I reduced speed by factor 3 for easier to inspection -- original stepper movement is really fast:
Image
https://hermann-sw.github.io/planar_graph_playground
https://stamm-wilbrandt.de/en#raspcatbt
https://github.com/Hermann-SW/memrun
https://github.com/Hermann-SW/Raspberry_v1_camera_global_external_shutter
https://stamm-wilbrandt.de/en/Raspberry_camera.html

Return to “C/C++”