Blog 15

From BitWizard Wiki
Jump to navigation Jump to search

BETA

Stepper Motor Raspberry Pi

In this part I am going to show my bash script for the raspberry pi version of rotating the stepper motor.

Hardware I used:

Programmed with:


I connected the RPi_UI board with the 7fets through a spi cable(on spi0). The stepper motor I connected with the 7fets through 5 male-female cables. Cables blue till orange from the stepper motor I put on pin 2,4,6,8. ( 2 = blue 8 = orange ) The Red cable I putted on pin 3. It can also put on pin 1 or all the other dev power pins. (DIO protocol) You can see at the arduino set-up picture how I put them.

What my goal with the script was that the stepper motor should rotate with the value you gave it and stops for 10 seconds after that it has to start all over again.

The full script:

#!/bin/bash

Address="bw_tool -s 50000 -a 88"

Rot=-400
Target=`$Address -R 41:i`
#Speed=200
#$Address -W 43:$Speed:b`

Current="" 

while true; do 
  $Address -W 42:$Rot:i
  Target=`$Address -R 41:i`
  while [ "$Current" != "$Target" ] ; do
    sleep 0.2
    Current=`$Address -R 40:i`
  done
  sleep 10
done
Address="bw_tool -s 50000 -a 88"

Here I put the address of the script, where the script can reference multiple times to.

Rot=-400 

With changing the number after rot you can change the amount of rotation. That the script has to do later. With 400 it turns 180 degrees. And with minus it turns right without minus it turns right-ways.

Target=`$Address -R 41:i`

With target it will give the position it currently is in. This is for making it equal to the current.

#Speed=200
#$Address -W 43:$Speed:b`

This is something I added to the code. With this you can change the step delay. For now I gave it 200, what is equal to 20ms. So if you want it to turn faster you have to make the step delay less.

Current="" 

This is to give current for now no worth. So that in the script it will directly start running the stepper motor.

$Address -W 42:$Rot:i
Target=`$Address -R 41:i`

Here I reference the rot and address commands and want it to rotate the amount of give in the rot part. And here again it asks for the target location with the second line.

while [ "$Current" != "$Target" ] ; do
  sleep 0.2
  Current=`$Address -R 40:i`

Here it looks if the current place of the rotating stepper motor is not equal to the target. If so it will re-look after 0.2 seconds what the current is. And when it is equal it will sleep for 10 seconds and then start all over again:

  done
  sleep 10
done
Rasp7fetsStepper.jpg

Working with stepper motor

In this post I am going to connect a stepper motor with my Arduino. I want the stepper motor to turn left and right, and I want the stepper motor to turn a certain degrees.

Before programming I first need to connect the Arduino with the stepper motor.

The hardware I used:

( I also posted in Blog 14, I connected the 7fets with an lcd + display. This is something what of course is not needed )

Programmed with:

  • Arduino
7fetsStepper.jpg

As you can see in the image is that the stepper Motor has 5 coloured cables, that are all together in a white cube. These cables have to get connected with the 7fets. To do this you have to get 5 male to female cables. From cable blue to orange from the stepper motor it has to be connected to pin 2,4,6,8. The red cable can be put on pin 1, all the other places in the row that are dev power. ( Places where it can gets it's voltage ) ( out 1 till 4 , works different counts 0 till 3) ( in 1 till 4 ) 7FETs

Now the programming part:

I used a script named ardemo_lcd.pde, that I changed to get it working with the stepper motor.

const int SPICLK  = 13;
const int SPIMOSI = 11;
const int SPIMISO = 12;
const int SPISS  = 10;

void SPIinit(void)
{
  pinMode (SPICLK,  OUTPUT);
  pinMode (SPIMOSI, OUTPUT);
  pinMode (SPIMISO, OUTPUT);
  pinMode (SPISS,   OUTPUT);
  digitalWrite (SPISS, 1);
   
  SPCR    =  _BV(SPE) | _BV(MSTR) | _BV(SPR1) | _BV(SPR0);
} 

char SPI(char d) 
{  // send character over SPI
  char received = 0;
  SPDR = d;
  while(!(SPSR & _BV(SPIF)));
  received = SPDR;
  return (received);
} 

void SPI_startpkt (void)
{
 digitalWrite (SPISS, 0);
}

void SPI_endpkt (void) 
{
  digitalWrite (SPISS, 1);
}

void set_var32 (unsigned char addr, unsigned char a, unsigned long v)
{
  SPI_startpkt ();
  delayMicroseconds (WAIT1);
  SPI (addr);
  delayMicroseconds (WAIT2);
  SPI (a);
  delayMicroseconds (WAIT2);
  SPI (v);
  delayMicroseconds (WAIT2);
  SPI (v>>8);
  delayMicroseconds (WAIT2);
  SPI (v>>16);
  delayMicroseconds (WAIT2);
  SPI (v>>24);
  delayMicroseconds (WAIT2);
  SPI_endpkt ();   
}

static unsigned char spi_7fet_addr = 0x88;

void setup() {
  //declare the motor pins as outputs
  SPIinit ();  
  Serial.begin(9600);
}

void loop(){
  set_var32 (0x88, 0x42, 0x50);
  delay(1000); 
}
void setup() {
  //declare the motor pins as outputs
  SPIinit ();  
  Serial.begin(9600);
}

For activating the pins.

void loop(){
  set_var32 (0x88, 0x42, 0x50);
  delay(1000); 
}

This says that at address 0x88 from the 7fets it has to go 50 further from the current position and after that it should take a 1 sec break. ( repeat and repeat itself) If you want to let the stepper motor to turn the other way you have to add a minues before 0x50. Example:

   set_var32 (0x88, 0x42, -0x50);

0x42 is for setting the relative position. ( so in the example script it goes 50 further from the current position ) Port 42 is 32bits, don't forget about if a port is 32bits or not. ( On the DIO protocol you can find all the ports. )

Rotating Plateau

Now I want to explain how you could rotate the stepper motor a certain degrees and in which direction. This can be handy if you want to use the stepper motor as plateau for a museum, or of course other projects were you need a stepper motor.

For this I will only paste the setup + loop. ( The other parts you can just copy paste from the previous code. I didn't want to make this page too long )


//beta

 void loop(){
 set_var32 (0x88, 0x42, 0x200);
 delay(1000);  
 }

This script makes it possible that it turns 90 degrees with the register 0x200.

The values with the amount of rotation they make: 0x800 = 360 degrees 0x400 = 180 degrees 0x200 = 90 degrees 0x267 = 120 degrees

If you want another degree like for instance 45 you can just convert it. Example 800:360 = 2.2222222 * 45 = 100

The final script to make it all work: I used a script named ardemo_lcd.pde and used the set_var32 from previous script.


unsigned long get_var32 (unsigned char addr, unsigned char a)
{
  unsigned long v;
  
  SPI_startpkt ();
  delayMicroseconds (WAIT1);
  SPI (addr+1);
  delayMicroseconds (WAIT2);
  SPI (a);
  delayMicroseconds (WAIT2);
  v = (unsigned long)SPI (0x00);
  delayMicroseconds (WAIT2);
  v |= (unsigned long)SPI (0x00) << 8;
  delayMicroseconds (WAIT2);
  v |= (unsigned long)SPI (0x00) << 16;
  delayMicroseconds (WAIT2);
  v |= (unsigned long) SPI (0x00) << 24;
  delayMicroseconds (WAIT2);
  SPI_endpkt ();    
  return v;
}   

/*
unsigned char get_var (unsigned char addr, unsigned char a)
{
  unsigned char v;
  
  SPI_startpkt ();
  delayMicroseconds (WAIT1);
  SPI (addr+1);
  delayMicroseconds (WAIT2);
  SPI (a);
  delayMicroseconds (WAIT2);
  v = SPI (0x00);
  delayMicroseconds (WAIT2);
  SPI_endpkt ();    
  return v;
}
*/   

//Time to pause rotating
static unsigned long Pause = 10000;
//Amount you want the stepper motor to rotate (0x200 = 25%  0x400 = 50% 0x800= 100% )
static unsigned long Rot = 0x200;  

void setup() { 
  //declare the motor pins as outputs
  SPIinit ();  
  Serial.begin(9600);
  char buf[32];
  unsigned long Tar;
  unsigned long Cur;  

  //Makes the current(0x40) + target(0x41) zero. Handy if the current + target have a big difference. 
  //set_var32(0x88, 0x40, 0x00);
  //set_var32(0x88, 0x41, 0x00); 

  //Change the step delay //50 is 4 times as fast as he normally goes (200)
  //set_var(0x88, 0x43, 50);
 
  Tar = get_var32 (0x88, 0x41);
  sprintf (buf, "FTarget: %08lx\r\n", Tar );
  Serial.write (buf); 

  Cur = get_var32 (0x88, 0x40);
  sprintf (buf, "Fcur:    %08lx\r\n", Cur);
  Serial.write (buf);
} 

void loop()
{
  unsigned long v;
  unsigned long Cur;
 
  char buf[32];
  set_var32(0x88, 0x42, Rot);  

  v = get_var32 (0x88, 0x41);
  sprintf (buf, "Target:  %08lx\r\n", v);
  Serial.write (buf); 

  do {
    delay(200);
    Cur = get_var32 (0x88, 0x40);
    sprintf (buf, "cur:     %08lx\r\n", Cur);
    Serial.write (buf);   

  } while (Cur != v); 

  delay(Pause);  
}

Explanation from the code:

unsigned long get_var32 (unsigned char addr, unsigned char a) {

 unsigned long v;
 
 SPI_startpkt ();
 delayMicroseconds (WAIT1);
 SPI (addr+1);
 delayMicroseconds (WAIT2);
 SPI (a);
 delayMicroseconds (WAIT2);
 v = (unsigned long)SPI (0x00);
 delayMicroseconds (WAIT2);
 v |= (unsigned long)SPI (0x00) << 8;
 delayMicroseconds (WAIT2);
 v |= (unsigned long)SPI (0x00) << 16;
 delayMicroseconds (WAIT2);
 v |= (unsigned long) SPI (0x00) << 24;
 delayMicroseconds (WAIT2);
 SPI_endpkt ();    
 return v;
}

This is for let later in the script be able to read the 32bit variables. ( That you normally do with -R on Raspberry Pi ) To make it let to read you have to count +1 on the addres. So if 0x88 is write 0x89 will than be read.

SPI (addr+1);  

v is an unsigned long to make it 32 bits. give value of 8bit, 16bit and 24bit.
unsigned char get_var is in not used but can be used if you want to change the step delay from the stepper motor

Here you can easily change the time for the delay rotating and change the amount the stepper motor has to rotate.

//Time to pause rotating
static unsigned long Pause = 10000;
//Amount you want the stepper motor to rotate (0x200 = 25%  0x400 = 50% 0x800= 100% )
static unsigned long Rot = 0x200; 

These 2 codes are taken out, because they are only needed if the difference between current and target is too big. I had the problem while making this code that my target was counting up from an other value than that the value was.

 //Makes the current(0x40) + target(0x41) zero. Handy if the current + target have a big difference. 
 //set_var32(0x88, 0x40, 0x00);
 //set_var32(0x88, 0x41, 0x00); 

Here you can change the step delay to make the stepper faster or slower.

 //Change the step delay //50 is 4 times as fast as he normally goes (200)
 //set_var(0x88, 0x43, 50);

Here it is getting the first Target and the current. ( You can directly see in the serial monitor if the values are right )

 Tar = get_var32 (0x88, 0x41);
 sprintf (buf, "FTarget: %08lx\r\n", Tar );
 Serial.write (buf); 

 Cur = get_var32 (0x88, 0x40);
 sprintf (buf, "Fcur:    %08lx\r\n", Cur);
 Serial.write (buf);

Here it writes to the stepper motor that it has to rotate 25%(0x200) forward.

 char buf[32];
 set_var32(0x88, 0x42, Rot);  

After that it reads the new target.

 v = get_var32 (0x88, 0x41);
 sprintf (buf, "Target:  %08lx\r\n", v);
 Serial.write (buf);

In the do while it will look after every 0.2sec ( I didn't want a big list of spam ) what the the current position is. When the current and the target have the same value the do while ends and it will pause for 10 sec(Pause).

 do {
   delay(200);
   Cur = get_var32 (0x88, 0x40);
   sprintf (buf, "cur:     %08lx\r\n", Cur);
   Serial.write (buf);   

 } while (Cur != v); 

 delay(Pause);  
}

Useful links