Friday, September 24, 2010

1

ARDUINO + RKL298 + LIMIT SWITCHES

A couple of weeks ago I talked about how to control 2 DC motors using an Arduino and a RKL298. Here is a small improvement to that idea.

I added two limit switches to each motor. This way the Arduino would stop the motors automatically if any limit switch is activated. The following picture illustrates better the concept.

There is some additional wiring to do in order to use the switches, here you can see how to wire the Limit Switch A1 to the Arduino

As you can see, when the Limit Switch A1 closes the input to the Arduino's digital port 9 becomes HIGH and when the switch is released it becomes LOW. When digital port 9 goes to HIGH state the Arduino will stop motor A automatically. The wiring is analogous for the rest of the switches the difference is that Limit Switch A2, B1 and B2 uses digital port 8, 4 and 3 respectively.

You can find out more details by reading the source code:

/*
   Serial Motor Interface
   Author: Martin Peris-Martorell - www.martinperis.com

   Description: This program is a serial port motor interface.
   It is used to command an H-Bridge motor controller based on
   L298. 
   This motor controller can be found at www.rkeducation.co.uk
   under the reference part number: RKL298 PCB

   The RKL298 PCB can control 2 DC motors. The control is achieved
   by using 6 control lines: ENA, IP1, IP2, ENB, IP3 and IP4.

   ENA, IP1 and IP2 are used to command the motor A
   ENB, IP3 and IP4 are used to command the motor B

   Limit switches: LIA1, LIA2, LIB1, LIB2
   LIA1, LIB1 are the forward limit switches for motor A and B
   LIA2, LIB2 are the reverse limit switches for motor A and B

   Wiring with arduino: 
  
   RKL298 PCB |     Arduino
   -----------------------------
   ENA       <-> Digital port 12
   IP1       <-> Digital port 11
   IP2       <-> Digital port 10
   LIA1      <-> Digital port 9
   LIA2      <-> Digital port 8
   
   ENB       <-> Digital port 7
   IP3       <-> Digital port 6
   IP4       <-> Digital port 5
   LIB1      <-> Digital port 4
   LIB2      <-> Digital port 3 

   A LED can be connected to digital port 13  

   Serial port configuration: 9600 bauds

   Comunication protocol: Connect the arduino via USB to
   a PC, or via digital pins 0 and 1 to a serial port.

   Open the serial port for communication and send 3 bytes.
   The format is:

   Byte 0: 255  //Sync. signal
   Byte 1: Motor identificator. 0 for motor A, 1 for motor B.
   Byte 2: Command. A value between 0 and 63. 
                    0       = Full stop (free running)
                    1 - 31  = Backward with PWM ( 1: slowest, 31: fastest)
                    32      = Full stop (active braking)
                    33 - 63 = Forward with PWM (33: slowest, 63: fastest)

  For example, if you want to move motor A backward at 50% of speed
  the command would be:  255 0 16
  If you want to stop motor A the command would be: 255 0 0

  Additionally there are two limit switches for each motor. 
  If a motor is running and a limit switch is activated, it will
  stop automatically. This is useful for permitting the automatic
  protection of your device, without the direct involvement of the
  controlling computer. 

  This program is distributed under the terms of the GNU General Public License.
   
  Enjoy it.
*/


#define STOP 0
#define FORWARD 1
#define REVERSE -1

/* Declarations for serial communications */
int incomingByte[128];
int numBytes = 0;

/* Declarations for wiring */
int pinEN[2];
int pinIP1[2];
int pinIP2[2];
int pinLIA[2];
int pinLIB[2];

/* Declarations for motor state */
int stateMotor[2];

void setup(){
  int i = 0;
  //0 refers to Motor A; 1 refers to Motor B
  pinEN[0] = 12;
  pinEN[1] = 7;

  pinIP1[0] = 11;
  pinIP2[0] = 10;
  pinLIA[0] = 9;
  pinLIA[1] = 8;

  pinIP1[1] = 6;
  pinIP2[1] = 5;
  pinLIB[0] = 4;
  pinLIB[1] = 3;

  //Set pin modes
  for (i = 0; i < 2; i++){
    pinMode(pinEN[i], OUTPUT);
    digitalWrite(pinEN[i],HIGH);
    pinMode(pinIP1[i], OUTPUT);
    digitalWrite(pinIP1[i],LOW);
    pinMode(pinIP2[i], OUTPUT);
    digitalWrite(pinIP2[i],LOW);
    pinMode(pinLIA[i], INPUT);
    pinMode(pinLIB[i], INPUT);
  }

  //Set initial state of the motors
  stateMotor[0] = STOP;
  stateMotor[1] = STOP;

  //Light up the led
  pinMode(13,OUTPUT);
  digitalWrite(13,HIGH);

  //Open serial port
  Serial.begin(9600);
}

void loop(){
  int i = 0;
  int motor = 0;
  int action = 0;

  //Check for data in serial port
  numBytes = Serial.available();
  if (numBytes >= 3){

    //Read all the data in the buffer
    for(i = 0; i < numBytes; i++){
      incomingByte[i] = Serial.read();
    }

  /* The data received should be: 255 M A
       Where:
        255 is the sync byte 
        M is the motor number (0 or 1)
        A is the action (a number between 0 and 63)
    */
    if (incomingByte[0] != 255 || incomingByte[1] < 0 || incomingByte[1] > 1 || incomingByte[2] < 0 || incomingByte[2] > 63){
      Serial.flush();
      return;
    }

    /* The received data is correct -> activate the appropriate pins */
    motor = incomingByte[1];
    action = incomingByte[2];

    if (action == 0){
      //Full stop (free running)
      digitalWrite(pinIP1[motor],LOW);
      digitalWrite(pinIP2[motor],LOW);
      stateMotor[motor] = STOP;
      return;
    }

    if (action == 32){
      //Full stop (active braking)
      digitalWrite(pinIP1[motor],HIGH);
      digitalWrite(pinIP2[motor],HIGH);
      stateMotor[motor] = STOP;
      return;
    }

    if (action >= 1 && action <= 31 ){
      //Check limit switches
      if ((motor==0 && digitalRead(pinLIA[1])==HIGH) || (motor==1 && digitalRead(pinLIB[1])==HIGH)){
        //Full stop (active braking)
        digitalWrite(pinIP1[motor],HIGH);
        digitalWrite(pinIP2[motor],HIGH);
        stateMotor[motor] = STOP;
      }else{
        //Reverse with PWM
        analogWrite(pinIP1[motor],0);
        analogWrite(pinIP2[motor],(action-1)*8);
        stateMotor[motor] = REVERSE;
      }
    return;
    }

    if (action >= 33 && action <= 63 ){
      //Check limit switches
      if ((motor==0 && digitalRead(pinLIA[0])==HIGH) || (motor==1 && digitalRead(pinLIB[0])==HIGH)){
        //Full stop (active braking)
        digitalWrite(pinIP1[motor],HIGH);
        digitalWrite(pinIP2[motor],HIGH);
        stateMotor[motor] = STOP;
      }else{
        //Forward with PWM
        analogWrite(pinIP1[motor],(action-33)*8);
        analogWrite(pinIP2[motor],0);
        stateMotor[motor] = FORWARD;
      }
      return;
    }

  }else{
    //If no serial message has arrived then poll the status of the limit switches
    //and stop the motors as necessary

    if (stateMotor[0] == REVERSE && digitalRead(pinLIA[1]) == HIGH){
      //Full stop (active braking)
      digitalWrite(pinIP1[0],HIGH);
      digitalWrite(pinIP2[0],HIGH);
      stateMotor[0] = STOP;
    }
    if (stateMotor[1] == REVERSE && digitalRead(pinLIB[1]) == HIGH){
      //Full stop (active braking)
      digitalWrite(pinIP1[1],HIGH);
      digitalWrite(pinIP2[1],HIGH);
      stateMotor[1] = STOP;
    }
    if (stateMotor[0] == FORWARD && digitalRead(pinLIA[0]) == HIGH){
      //Full stop (active braking)
      digitalWrite(pinIP1[0],HIGH);
      digitalWrite(pinIP2[0],HIGH);
      stateMotor[0] = STOP;
    }
    if (stateMotor[1] == FORWARD && digitalRead(pinLIB[0]) == HIGH){
      //Full stop (active braking)
      digitalWrite(pinIP1[1],HIGH);
      digitalWrite(pinIP2[1],HIGH);
      stateMotor[1] = STOP;
    }
  }
}
Enjoy it!

1 comment:

AQ said...

Greetings, i am not sure why, but my interrupt seems to not be consistent. When the limit switches close, there is a 5v signal to the arduino board, but sometimes it triggers the interrupt but at other times it doesn't. Any recommendations?

Post a Comment