Driving Arduino motor shield from Pi


31 posts   Page 1 of 2   1, 2
by joan » Fri Aug 31, 2012 11:27 am
Some time ago I bought http://www.ebay.co.uk/itm/Motor-Drive-Shield-Expansion-Board-L293D-Arduino-Duemilanove-Mega-UNO-/200727260111 intending to use it with an Arduino. The Arduino hasn't turned up yet.

Anyhow I wondered how easy it would be to get it to work with the Pi. The answer is not hard. The unit is a clone of the Adafruit shield (http://shieldlist.org/adafruit/motor). I rejigged the Arduino software to use Gordon's WiringPi library, used 6 gpio lines for control, and I can now drive (4) DC motors backwards/forwards with variable speed. I haven't looked at the servo/stepper motor software but expect it's just as easy to convert for the Pi.

img_2732b.jpg
img_2732b.jpg (44.24 KiB) Viewed 6248 times


I apologise if this has been reported before, but the Arduino shields may make useful add-ons for the Pi.
User avatar
Posts: 4214
Joined: Thu Jul 05, 2012 5:09 pm
Location: UK
by simplesi » Fri Aug 31, 2012 11:57 am
keep these ideas coming :)

Si
Seeking help with Scratch and I/O stuff for Primary age children
http://cymplecy.wordpress.com/ @cymplecy on twitter
Posts: 1790
Joined: Fri Feb 24, 2012 6:19 pm
Location: Euxton, Lancashire, UK
by rasbeer » Fri Aug 31, 2012 7:41 pm
Same item on another site (run by the same seller I think*):
http://www.buyincoins.com/new_en/detail ... 12329.html

*Based on the watermark in the pic, HK location & huge amount of feedback in the ebay store.
Posts: 242
Joined: Wed Mar 07, 2012 8:35 am
by joan » Fri Aug 31, 2012 8:03 pm
Looks the same. I think some of these Chinese sellers on eBay have multiple trading names. These will be clone boards though, i.e. they've taken the (I believe) open source hardware design and manufactured their own board.
User avatar
Posts: 4214
Joined: Thu Jul 05, 2012 5:09 pm
Location: UK
by BBsan2k » Tue Oct 09, 2012 2:08 pm
Sorry for bringing this up again,
but isn't there a problem using 3.3V Raspberry Pi? How did you manage to controll the motor shield?
Posts: 27
Joined: Sat May 19, 2012 2:18 pm
by poing » Tue Oct 09, 2012 3:05 pm
joan wrote:I rejigged the Arduino software to use Gordon's WiringPi library, used 6 gpio lines for control, and I can now drive (4) DC motors backwards/forwards with variable speed.


Very interested in this, can you elaborate on what you have done exactly? It's all quite new to me so what you wrote is not all that clear ;)
Posts: 1090
Joined: Thu Mar 08, 2012 3:32 pm
by joan » Tue Oct 09, 2012 8:40 pm
BBsan2k wrote:Sorry for bringing this up again,
but isn't there a problem using 3.3V Raspberry Pi? How did you manage to controll the motor shield?

I didn't have any problems with the signal levels. I suppose a 3.3V low is pretty much the same as a 5V low and a 3.3V high is high enough to count as a 5V high.
User avatar
Posts: 4214
Joined: Thu Jul 05, 2012 5:09 pm
Location: UK
by joan » Tue Oct 09, 2012 8:54 pm
poing wrote:
joan wrote:I rejigged the Arduino software to use Gordon's WiringPi library, used 6 gpio lines for control, and I can now drive (4) DC motors backwards/forwards with variable speed.


Very interested in this, can you elaborate on what you have done exactly? It's all quite new to me so what you wrote is not all that clear ;)

There are simpler ways to drive motors from the Pi, e.g. http://www.ebay.co.uk/itm/140743762410

The opening post points to the motor shield specs. The specs also point to software for driving the shield from an Arduino. I just ported the code to the Pi using the wiringPi library.

For what its worth the code used was
Code: Select all
#include <stdio.h>
#include <errno.h>
#include <string.h>

#include <wiringPi.h>
#include <softPwm.h>

typedef unsigned char uint8_t;

#define _BV(bit) (1 << (bit))

#define MOTORLATCH  0
#define MOTORCLK    1
#define MOTORENABLE 2
#define MOTORDATA   3
#define MOTOR_1_PWM 4
#define MOTOR_2_PWM 5

#define MOTOR1_A 2
#define MOTOR1_B 3
#define MOTOR2_A 1
#define MOTOR2_B 4
#define MOTOR4_A 0
#define MOTOR4_B 6
#define MOTOR3_A 5
#define MOTOR3_B 7

#define FORWARD  1
#define BACKWARD 2
#define BRAKE    3
#define RELEASE  4

#define RANGE      100
#define   DC_MOTORS  4

static unsigned char latch_state;

void latch_tx(void)
{
   unsigned char i;

   digitalWrite(MOTORLATCH, LOW);

   digitalWrite(MOTORDATA, LOW);

   for (i=0; i<8; i++)
   {
      digitalWrite(MOTORCLK, LOW);

      if (latch_state & _BV(7-i))
      {
         digitalWrite(MOTORDATA, HIGH);
      }
      else
      {
         digitalWrite(MOTORDATA, LOW);
      }
      digitalWrite(MOTORCLK, HIGH);
   }
   digitalWrite(MOTORLATCH, HIGH);
}


void enable(void)
{
   pinMode(MOTORLATCH,  OUTPUT);
   pinMode(MOTORENABLE, OUTPUT);
   pinMode(MOTORDATA,   OUTPUT);
   pinMode(MOTORCLK,    OUTPUT);

   latch_state = 0;

   latch_tx();

   digitalWrite(MOTORENABLE, LOW);
}

typedef struct motorInf_t
{
   uint8_t pwmfreq;
};

motorInt_t motorInf[DC_MOTORS];

void DCMotorInit(uint8_t num, uint8_t freq)
{
   motorInf[num].pwmfreq = freq;

   enable();

   switch (num)
   {
      case 1:
         latch_state &= ~_BV(MOTOR1_A) & ~_BV(MOTOR1_B);
         latch_tx();
         initPWM(1, freq);
         break;
      case 2:
         latch_state &= ~_BV(MOTOR2_A) & ~_BV(MOTOR2_B);
         latch_tx();
         initPWM(2, freq);
         break;
      case 3:
         latch_state &= ~_BV(MOTOR3_A) & ~_BV(MOTOR3_B);
         latch_tx();
         initPWM(3, freq);
         break;
      case 4:
         latch_state &= ~_BV(MOTOR4_A) & ~_BV(MOTOR4_B);
         latch_tx();
         initPWM(4, freq);
         break;
   }
}

int motorMap [] = {MOTOR_1_PWM, MOTOR_2_PWM};

void setPWM(uint8_t num, int freq)
{
   softPwmWrite (motorMap [num], freq) ;
}

void initPWM(uint8_t num, int freq)
{
   softPwmCreate (motorMap [num], 0, RANGE) ;
   setPWM(num, freq);
}

void DCMotorRun(uint8_t motornum, uint8_t cmd)
{
   uint8_t a, b;

   switch (motornum)
   {
      case 1:
         a = MOTOR1_A; b = MOTOR1_B;
         break;
      case 2:
         a = MOTOR2_A; b = MOTOR2_B;
         break;
      case 3:
         a = MOTOR3_A; b = MOTOR3_B;
         break;
      case 4:
         a = MOTOR4_A; b = MOTOR4_B;
         break;
      default:
         return;
   }
 
   switch (cmd)
   {
      case FORWARD:
         latch_state |= _BV(a);
         latch_state &= ~_BV(b);
         latch_tx();
         break;
      case BACKWARD:
         latch_state &= ~_BV(a);
         latch_state |= _BV(b);
         latch_tx();
         break;
      case RELEASE:
         latch_state &= ~_BV(a);
         latch_state &= ~_BV(b);
         latch_tx();
       break;
   }
}

void DCMotorSetSpeed(uint8_t motornum, int speed)
{
   switch (motornum)
   {
      case 1:
         setPWM(1, speed);
         break;
      case 2:
         setPWM(2, speed);
         break;
      case 3:
         setPWM(3, speed);
         break;
      case 4:
         setPWM(4, speed);
         break;
   }
}

int main ()
{
   int i, j ;

   if (wiringPiSetup () == -1)
   {
      fprintf (stdout, "oops: %s\n", strerror (errno)) ;
      return 1 ;
   }

   for (i = 0 ; i < NUM_MOTORS ; ++i)
   {
      softPwmCreate (motorMap [i], 0, RANGE) ;
   }

   // Bring all up in stages 25%, 50%, 75% 100%

   for (j = 25 ; j <= RANGE ; j+=25)
   {
      printf("pwm %d%%\n", j);
      for (i = 0 ; i < NUM_MOTORS ; ++i)
      {
         softPwmWrite (motorMap [i], j) ;
      }
      delay(6000);
   }
   // Bring all up in stages 25%, 50%, 75% 100%

   for (j = RANGE-25 ; j >= 0; j-=25)
   {
      printf("pwm %d%%\n", j);
      for (i = 0 ; i < NUM_MOTORS ; ++i)
      {
         softPwmWrite (motorMap [i], j) ;
      }
      delay(6000);
   }
   return 0;
}
User avatar
Posts: 4214
Joined: Thu Jul 05, 2012 5:09 pm
Location: UK
by cbis » Wed Jan 02, 2013 1:02 am
Joan

I want to try and do the same thing.. could you possibly provide some guidance please?

I have a python app that currently waits for a command to move forward or backward.. and a sainsmart 4x4 car..

Just need to match up the raspberry pi ports to motor shield now :)
Posts: 8
Joined: Wed Jan 02, 2013 12:58 am
by joan » Fri Jan 04, 2013 11:14 am
From the Pi end I was using wiringPi from Gordon so they will be the corresponding Wiring Pi logical pin on the Pi.

https://projects.drogon.net/raspberry-pi/wiringpi/pins/

MOTORLATCH 0 // pin P1-11
MOTORCLK 1 // pin P1-12
MOTORENABLE 2 // pin P1-13
MOTORDATA 3 // pin P1-15
MOTOR_1_PWM 4 // pin P1-16
MOTOR_2_PWM 5 // pin P1-18

The software I modified can be found at http://www.ladyada.net/make/mshield/download.html

The motor shield pins used are

http://shieldlist.org/adafruit/motor

MOTORLATCH D12
MOTORCLK D4
MOTORENABLE D7
MOTORDATA D8

MOTOR1 PWM D11
MOTOR2 PWM D3
MOTOR3 PWM D5
MOTOR4 PWM D6

Note, I didn't connect any gpios to MOTOR3/4 as I only had 2 motors.

I also connected the Pi's ground to the shield's ground and probably the Pi's 5V to the shield's 5V.

The motors were powered separately.

A better photo is http://abyz.co.uk/photos/img_2732.jpg
User avatar
Posts: 4214
Joined: Thu Jul 05, 2012 5:09 pm
Location: UK
by cbis » Fri Jan 04, 2013 11:10 pm
Thanks for the info on the pins! I have it all hooked up and execute the code example but nothing happens! I must be missing something for it to literally not fire off any of the motors
Posts: 8
Joined: Wed Jan 02, 2013 12:58 am
by joan » Fri Jan 04, 2013 11:47 pm
Double check the connections. The photo is the definitive connection diagram. It was a rev 1 board but I don't think those pin assignments have changed.
User avatar
Posts: 4214
Joined: Thu Jul 05, 2012 5:09 pm
Location: UK
by joan » Sat Jan 05, 2013 12:03 pm
I got the shield out and have rewired it to a Pi.

You need to connect the Pi and shield's ground.

You don't need to connect the 5V line.

I powered my motors from a 9V battery.

I've stripped the software down to just driving the motors forwards then backwards.

Code: Select all
#include <stdio.h>
#include <errno.h>
#include <string.h>

#include <wiringPi.h>
#include <softPwm.h>

typedef unsigned char uint8_t;

#define _BV(bit) (1 << (bit))

#define MOTORLATCH  0
#define MOTORCLK    1
#define MOTORENABLE 2
#define MOTORDATA   3
#define MOTOR_1_PWM 4
#define MOTOR_2_PWM 5

#define MOTOR1_A 2
#define MOTOR1_B 3
#define MOTOR2_A 1
#define MOTOR2_B 4
#define MOTOR4_A 0
#define MOTOR4_B 6
#define MOTOR3_A 5
#define MOTOR3_B 7

#define FORWARD  1
#define BACKWARD 2
#define BRAKE    3
#define RELEASE  4

static unsigned char latch_state;

void latch_tx(void)
{
   unsigned char i;

   digitalWrite(MOTORLATCH, LOW);

   digitalWrite(MOTORDATA, LOW);

   for (i=0; i<8; i++)
   {
      digitalWrite(MOTORCLK, LOW);

      if (latch_state & _BV(7-i))
      {
         digitalWrite(MOTORDATA, HIGH);
      }
      else
      {
         digitalWrite(MOTORDATA, LOW);
      }
      digitalWrite(MOTORCLK, HIGH);
   }
   digitalWrite(MOTORLATCH, HIGH);
}


void enable(void)
{
   pinMode(MOTORLATCH,  OUTPUT);
   pinMode(MOTORENABLE, OUTPUT);
   pinMode(MOTORDATA,   OUTPUT);
   pinMode(MOTORCLK,    OUTPUT);

   latch_state = 0;

   latch_tx();

   digitalWrite(MOTORENABLE, LOW);
}

void DCMotorInit(uint8_t num)
{
   switch (num)
   {
      case 1:
         latch_state &= ~_BV(MOTOR1_A) & ~_BV(MOTOR1_B);
         latch_tx();
         break;
      case 2:
         latch_state &= ~_BV(MOTOR2_A) & ~_BV(MOTOR2_B);
         latch_tx();
         break;
      case 3:
         latch_state &= ~_BV(MOTOR3_A) & ~_BV(MOTOR3_B);
         latch_tx();
         break;
      case 4:
         latch_state &= ~_BV(MOTOR4_A) & ~_BV(MOTOR4_B);
         latch_tx();
         break;
   }
}

void DCMotorRun(uint8_t motornum, uint8_t cmd)
{
   uint8_t a, b;

   switch (motornum)
   {
      case 1:
         a = MOTOR1_A; b = MOTOR1_B;
         break;
      case 2:
         a = MOTOR2_A; b = MOTOR2_B;
         break;
      case 3:
         a = MOTOR3_A; b = MOTOR3_B;
         break;
      case 4:
         a = MOTOR4_A; b = MOTOR4_B;
         break;
      default:
         return;
   }
 
   switch (cmd)
   {
      case FORWARD:
         latch_state |= _BV(a);
         latch_state &= ~_BV(b);
         latch_tx();
         break;
      case BACKWARD:
         latch_state &= ~_BV(a);
         latch_state |= _BV(b);
         latch_tx();
         break;
      case RELEASE:
         latch_state &= ~_BV(a);
         latch_state &= ~_BV(b);
         latch_tx();
       break;
   }
}

int main ()
{
   int i, j ;

   if (wiringPiSetup () == -1)
   {
      fprintf (stdout, "oops: %s\n", strerror (errno)) ;
      return 1 ;
   }

   pinMode(MOTOR_1_PWM, OUTPUT);
   pinMode(MOTOR_2_PWM, OUTPUT);

   digitalWrite(MOTOR_1_PWM, 0);
   digitalWrite(MOTOR_2_PWM, 0);

   enable();

   DCMotorInit(1);
   DCMotorInit(2);

   DCMotorRun(1, FORWARD);
   digitalWrite(MOTOR_1_PWM, 1);
   sleep(1);

   DCMotorRun(1, RELEASE);
   sleep(1);

   DCMotorRun(1, BACKWARD);
   sleep(1);

   DCMotorRun(1, RELEASE);
   sleep(1);
   
   DCMotorRun(2, FORWARD);
   digitalWrite(MOTOR_2_PWM, 1);
   sleep(1);

   DCMotorRun(2, RELEASE);
   sleep(1);

   DCMotorRun(2, BACKWARD);
   sleep(1);

   DCMotorRun(2, RELEASE);
   sleep(1);
}

Connections
Code: Select all
MOTORLATCH  D12 YELLOW 0 P1-11
MOTORCLK    D4  GREEN  1 P1-12
MOTORENABLE D7  BROWN  2 P1-13
MOTORDATA   D8  PINK   3 P1-15

MOTOR1 PWM  D11 WHITE  4 P1-16
MOTOR2 PWM  D3  BLUE   5 P1-18
MOTOR3 PWM  D5
MOTOR4 PWM  D6
User avatar
Posts: 4214
Joined: Thu Jul 05, 2012 5:09 pm
Location: UK
by joan » Sat Jan 05, 2013 12:36 pm
img_2321a.jpg
img_2321a.jpg (58.47 KiB) Viewed 5177 times
img_2322a.jpg
img_2322a.jpg (58.39 KiB) Viewed 5177 times
img_2323a.jpg
img_2323a.jpg (58.25 KiB) Viewed 5177 times
User avatar
Posts: 4214
Joined: Thu Jul 05, 2012 5:09 pm
Location: UK
by cbis » Sun Jan 06, 2013 12:54 am
Thanks for the update.. I had a response from the motors!! Motor 1.. "Ticked" forward then rolled back for a second.. then motor 2 rolled forward and rolled back..

I continued testing and now for some reason both motors tick forward and tick back? an example can be seen here : http://www.project-tool.co.uk/car1.mov
Posts: 8
Joined: Wed Jan 02, 2013 12:58 am
by cbis » Sun Jan 06, 2013 1:02 am
ha! Changed the ground point that I used on the motor shield from 1 jumper block to a different one and hey presto!!!
Posts: 8
Joined: Wed Jan 02, 2013 12:58 am
by cbis » Sun Jan 06, 2013 5:51 pm
Ok scratch that.. They all end up just ticking.. Switching the ground pin just cut power to the logic of the shield which reset it.. At the moment I just get ticking.. Maybe I need to reinit the motors each time??
Posts: 8
Joined: Wed Jan 02, 2013 12:58 am
by joan » Sun Jan 06, 2013 6:26 pm
I used the ground on the same strip as the other connections.

If your jumpers are like mine they are quite a loose fit on the shield pins. I had to sort of weigh the board down on top of the jumpers to keep them from falling out.

When I tried to use the code I originally posted it didn't compile. I must have made an erroneous change in the month since I had the shield working. That's why I went back to a minimum set-up. My throw away code isn't controlled. :oops:
User avatar
Posts: 4214
Joined: Thu Jul 05, 2012 5:09 pm
Location: UK
by cbis » Sun Jan 06, 2013 8:37 pm
ive checked the pins and the connections which are soldered to plugs.. I also went through the code again and im only going to try and work with two motors for now..

same problem.. tick.. tick.. then nothing.. I wonder if the board isn't getting the power it wants? possibly a faulty board.. if I put the 5v from the pi into the board the motors constantly turn..
Posts: 8
Joined: Wed Jan 02, 2013 12:58 am
by joan » Sun Jan 06, 2013 8:45 pm
Sounds like the power. I only used 3V model motors this time, even so the small 9V battery I used would only spin them for a few seconds continuously. I put the sleeps in partly to give the battery a rest.

You wouldn't get any result at all if the shift register jumpers weren't correct. Ditto to get a motor to move you'd need the relevant jumper. I'd guess your connections are correct.
User avatar
Posts: 4214
Joined: Thu Jul 05, 2012 5:09 pm
Location: UK
by cyrano » Sun Jan 06, 2013 10:38 pm
Are you certain that 9V battery is able to drive a motor?

Those 9V blocks already have some internal resistance. Combined with wiring and the FET in the L293 this might restrict the motor from starting.
User avatar
Posts: 372
Joined: Wed Dec 05, 2012 11:48 pm
Location: Belgium
by joan » Sun Jan 06, 2013 10:53 pm
Shield specs suggest motor inputs are 4.5V to 36V.

http://shieldlist.org/adafruit/motor
User avatar
Posts: 4214
Joined: Thu Jul 05, 2012 5:09 pm
Location: UK
by cbis » Mon Jan 07, 2013 12:34 am
The motors are part of the sainsmart 4x4 car built to go with the motor shield I'm using.. If I link the power to the motor separately it goes just fine and if I power the motor from the pi 5v it spins happily.. I might whack another power block on and see what it does.. Think ill buy a different hbridge as well to move my project on..
Posts: 8
Joined: Wed Jan 02, 2013 12:58 am
by cyrano » Mon Jan 07, 2013 1:10 am
cbis wrote:The motors are part of the sainsmart 4x4 car built to go with the motor shield I'm using..


Those are geared motors. They're not very powerful, but still require a fair amount of current to start. Same thing happened to me with two 12V 1A geared motors. They worked fine connected to 10 AA NiMH in series, but not once all the cabling and a couple of used relays were in place. With exactly the same symptom: just a tick, no power. New relays and proper cabling did the job.

And these 9V blocks are notorious for having a high internal resistance.
User avatar
Posts: 372
Joined: Wed Dec 05, 2012 11:48 pm
Location: Belgium
by cbis » Mon Jan 07, 2013 9:35 am
The car came with the pack for the 6 x AA batteries.. which would suggest that was enough to drive the motors.. however looking back through the vehicle documentation they tend to sell the car with http://www.sainsmart.com/sainsmart-l298 ... robot.html instead of the L298D board..

I have ordered one of the L298N boards which should arrive in a few days.. I will keep you guys posted! Thanks for the ongoing help.
Posts: 8
Joined: Wed Jan 02, 2013 12:58 am