Sending data to Roboclaw

I have not used a motor controller before so need a little help with sending data to the roboclaw 2x5A I have. I have wrote a PID algorithm(really just the ‘P’) and will have calculated a value between 1-127. Looks like I am wanting to use Simple Serial for Channel 1 to send this value too for it to determine how fast and which direction to tell my wiper motor to turn.

So, my main question is…I am not sure where to look for help/example on how to send this data to the roboclaw using whatever code I need too. I have checked out the datasheet which is the reason I came to a conclusion of the Simple Serial where I can use Channel 1, but that is about as far as I got.

I am unsure but could this be a possibility? I am using xbees with two arduinos. I will read in the value from a pot into this arduino. Here I am wanting to use Channel 2 to apply full forward or full reverse on a actuator for a brake depending on the value of the pot.

#include <SoftwareSerial.h>
//SoftwareSerial steer(2); //steering connected to pin 2
//SoftwareSerial brake(4); //brake connected to pin 
void setup()
{
  Serial.begin(9600);
  pinMode(2, OUTPUT);
  pinMode(4, OUTPUT);
}

void loop()
{
    else if(.....) //if pot1 changed, do this using value above
    {
            //This will be on channel 2. 128 = full reverse, 192=stop, 255=full forward
      if(val > 150)
      {
        //send 128 to the roboclaw Channel 2 to apply full brake
        digitalWrite(4, 128);
        //brake.write(128);
      }
      else
      {
        //send 255 to roboclaw to not brake
        digitalWrite(4, 255);
        //brake.write(255);
      }
          
    }
}

Have one more question dealing with Channel 2 that I will ask later.

Hello,

You posted a different question about a RoboClaw a few days ago in this thread. Are your latest questions related? In general, you should try to keep discussion on the same topic in a single thread so that relevant information is easier to find. Also, please do not blank out your earlier posts, as this makes it harder for us to remember what you are doing, and it makes the thread useless to readers who find it in the future. (The whole point of the forum is to provide a public discussion from which others might benefit.)

There are a couple issues with the code that you posted. While we could work on fixing them, an easier solution would probably be to use the Arduino library that Basic Micro wrote for the RoboClaw controllers, which can be found on the Resources tab of the RoboClaw’s product page. The library includes some example programs that you could use as a starting point for your own program.

By the way, you might consider using one of our jrk motor controllers instead, which have built-in support for analog input and potentiometer feedback and can perform PID position control by themselves. This might allow you to leave the Arduino out of your system entirely.

- Kevin

Thought the roboclaw has PID position control on them. I can not remove an arduino as this project is wireless. I am receiving pot values through one arduino and sending them through xbee to another. This second arduino is what will be connected to the roboclaw sending data to two motors. One of them being the brake motor which I have example code above for. I am reading in a pot and if it is >150 I want to apply full reverse or else full forward.

And I have already wrote a position control algorithm myself in my code to find a value between 1-127 to send to channel 1 of the roboclaw.

So here is an updated with using the library(SimpleSerial)(only a portion of the void loop code, only posted what I have question about):

#include "BMSerial.h"

BMSerial steer(5,1); //receive pin from arduino(output pin), transmit pin on roboclaw
BMSerial brake(6,2); //receive pin from arduino, tranmit pin on roboclaw

char string[8]; //can be 4, 8 is fine
byte var;
int index = 0;
int val;
char ltr;
boolean started=false;
boolean ended=false;

//pin0 will be steering wheel
//pin1 will be brake
//pin2 will be gas


void setup()
{
  Serial.begin(9600);
  steer.begin(9600);
  brake.begin(9600);
}

void loop()
{
    if(ltr == 'A') //if steering wheel changed, do this using value above
    {   
      double steeringInput = val; //Need to use the value calculated above
      steeringInput = constrain(steeringInput, steeringpotMin, steeringpotMax);
      double targetPos = map(steeringInput, steeringpotMin, steeringpotMax, -100, 100);
      int potPin3 = 3; //use pin3 on arduino2 for 'current' pot
      double wheelInput = analogRead(potPin3);
      wheelInput = constrain(wheelInput, wheelpotMin, wheelpotMax);
      double currentPos = map(wheelInput, wheelpotMin, wheelPotMax, -100,100);
      int error = targetPos - currentPos;

      if(error > 10)
      {
        int Turn = Kp*error;
        Turn = constrain(Turn,-63,63);
        Turn = Turn+64;

        steer.write(Turn);
        //send to roboclaw, value between 1 and 127
        //roboclaw datasheet: 1 = fullreverse, 127=fullforward, 64=stop
      }
    }

    //Connect to S2 on roboclaw from arduino output pin4
    else if(ltr == 'B') //if pot1 changed, do this using value above
    {
      //This will be on channel 2. 128 = full reverse, 192=stop, 255=full forward
      if(val > 150)
      {
        
        //send 128 to the roboclaw Channel 2 to apply full brake
        brake.write(128);
      }
      else
      {
        //send 255 to roboclaw to not brake
        brake.write(255);
      }
    }

The RoboClaw can do closed-loop speed control with encoders, but it definitely does not have any support for doing position control with potentiometers (which is why you are writing your own control algorithm on your Arduino).

You seem to be defining a different serial object for each motor channel, which is not correct. The RoboClaw has a single serial interface, and the specific serial commands you send determine which motor channel you are controlling.

The BMSerial class works similarly to SoftwareSerial, and its two required arguments are the Arduino pins you want to use for receiving and transmitting. So in the SimpleSerial example that comes with the RoboClaw library, this line:

BMSerial mySerial(5,6);

creates a BMSerial interface that receives on the Arduino’s pin 5 and transmits on pin 6. The receive pin is not important in this case, since the RoboClaw does not transmit anything back to the Arduino in Simple Serial mode, but the transmit pin (6) should be connected to the RoboClaw’s receive pin (S1).

As for the commands, in Simple Serial mode, a byte from 1 to 127 sets the speed of motor channel 1, while a byte from 128 to 255 sets the speed of motor channel 2. This is explained on page 26 of the RoboClaw datasheet. Regardless of which motor channel you are sending a command for, though, you would still send it on the same serial interface.

- Kevin

Ok, thankyou for explaining the BMSerial receive and transmit. I understand the bytes for each channel. Will report back if I run into any more problems.

Ok, well I have gotten my other motor controller (high power 36v20) to communicate properly. Now I am using the roboclaw to communicate with two dc motors. My first objective is to communicate with channel 2 of the roboclaw to an actuator. I have checked switches to make sure they are in serial mode and they are. In my code I am receiving an integer from a pot over xbee which is reason for most of the first code. I am determining which pot was changed and using that integer to decide what to do. For my question, I am not getting any communication with the roboclaw and actuator when dealing with the BMSerial brake which is the ‘B’ if statement. I have debugged it and I get the correct values output and also ‘Brake applied’ or ‘Brake not applied’ but seems like it is not getting to the roboclaw correctly.

#include "BMSerial.h"

//receive and transmit. Not receiving so transmit pin 6 should go to roboclaw S2
BMSerial brake(5,6);

#define PWML    10 //PWM pin for Low, do not need to direction of motor.
#define PWMH    11 //PWM pin for High, needed for direction of motor
#define DIR    12 //non PWM pin for direction control

char string[8]; //long enough string for value
byte var; //store each byte
int index = 0;
int val; //store the integer
char ltr; //store the character 
boolean started=false;
boolean ended=false;


void setup()
{
  Serial.begin(9600);
  brake.begin(9600);

}

void loop()
{
  while(Serial.available() > 0)
  {
    var=Serial.read();
    // less than, <, starts the current value
    if(var=='<') 
    {
      started = true;
      index=0;
      string[index]='\0';
    }
    //break out of while loop when '>' received
    else if(var=='>')
    {
      ended = true;
      break; 
    }
    //if value has started, create string
    else if(started)
    {
      string[index]=var;
      index++;
      string[index]='\0';
    }
  }
  //if you have value, grab character to determine which pot and create integer
  if(started && ended)
  {
    ltr = ' ';
    if(strlen(string) > 0)
    {
      ltr = string[0];
      string[0] = ' ';
      val=atoi(string); 
    }

    //Steering algorithm
    if(ltr == 'S')
    {
      Serial.print("This is letter: ");
      Serial.println(ltr);
      Serial.print("<");
      Serial.print(val);
      Serial.println(">");
    }

    //BRAKE
    else if(ltr == 'B')
    {
      Serial.print("This is letter: ");
      Serial.println(ltr);
      Serial.print("<");
      Serial.print(val);
      Serial.println(">");
      
      //int Bval = map(val, 0 , 1023, 0,);
      
      if(val > 250) 
      {
        //send 128 to the roboclaw Channel 2 to apply full brake
        Serial.print("Brake is applied");
        brake.write(128);
      }
      else
      {
        //send 255 to roboclaw to not brake
        Serial.print("Brake is not applied");
        brake.write(255);
      }

    }

    //Throttle
    else if(ltr == 'G')
    {
      Serial.print("This is letter: ");
      Serial.println(ltr);
      Serial.print("<");
      Serial.print(val);
      Serial.println(">");

      //map down to 1/4 of full speed of 36V motor
      int PWMval = map(val, 0,1023, 0,64); //PWM between 0-255 with 255 being max

      if (PWMval>0)
      {
        Serial.print("Speed Value Forward: ");
        Serial.println(PWMval);
        motorForward(PWMval);
      }   
    }

    //next time
    started = false;
    ended = false;

    index = 0;
    string[index]='\0';
  }
}

//Implement to shut down motor
void stopFunction()
{
  analogWrite(PWML, 0);
  analogWrite(PWMH, 0);
}

//Forard of the motor
void motorForward(int PWMforward)
{
  digitalWrite(DIR, LOW); 
  digitalWrite(PWML, HIGH);
  analogWrite(PWMH, PWMforward);

}

Your comment here suggests that you don’t have your connections quite right:

//receive and transmit. Not receiving so transmit pin 6 should go to roboclaw S2
BMSerial brake(5,6);

Your Arduino’s transmit pin (6) needs to go to the RoboClaw’s receive pin (S1). Your Arduino’s receive pin (5) does not need to be connected to anything on the RoboClaw.

Also, just to make sure, do you have SW1 OFF, SW2 ON, SW3 OFF, SW4 ON, and SW5 OFF? That should set the RoboClaw to be in simple serial mode with slave select off and 9600 baud rate.

- Kevin

Yes, sorry for the comment. I had S2 going to pin6 in the arduino, nothing for pin5 in arduino. This part of the code is for channel 2. I have another motor(wiper motor) as S1 channel 1 but I am not working on that yet.

I have the switches correct for simple serial and 9600 baud rate.

I have the pin6 from arudino going to first pin on S2, nothing connected to middle pin of S2 and ground going to back pin of S2.

Edit: I am going to run it again now and make sure all the connections are correct.

Well, I tried it again and nothing seems to be communicating. I do not have S1 pin or S1 gnd plugged into arduino as I am not using it at this time, just S2. I have a picture of why work but can’t seem to get it onto my computer.

I have the pin6 from arudino going to first pin on S2, nothing connected to middle pin of S2 and ground going to back pin of S2.

I have the actuator into M2A and M2B and the 12V into +/- and also the wiper motor into M1A/M1B. I flip the switch to power on and am using the code below, I marked the areas of concern with ‘****’.

[b]*****#include "BMSerial.h"

//receive and transmit. Not receiving so transmit pin 6 should go to roboclaw S2
BMSerial brake(5,6);********[/b]
//pin 3 should go to roboclaw S1
//BMSerial steer(2,3);

#define PWML    10 //PWM pin for Low, do not need to direction of motor.
#define PWMH    11 //PWM pin for High, needed for direction of motor
#define DIR    12 //non PWM pin for direction control
//#define SWTCH   8; //switch enable for forward/reverse

//read till end of packet
char string[8]; //long enough string for value
byte var; //store each byte
int index = 0;
int val; //store the integer
char ltr; //store the character 
boolean started=false;
boolean ended=false;


void setup()
{
  Serial.begin(9600);
[b] ********* brake.begin(9600);[/b]
  //steer.begin(9600);

}

void loop()
{
  while(Serial.available() > 0)
  {
    var=Serial.read();
    // less than, <, starts the current value
    if(var=='<') 
    {
      started = true;
      index=0;
      string[index]='\0';
    }
    //break out of while loop when '>' received
    else if(var=='>')
    {
      ended = true;
      break; 
    }
    //if value has started, create string
    else if(started)
    {
      string[index]=var;
      index++;
      string[index]='\0';
    }
  }
  //if you have value, grab character to determine which pot and create integer
  if(started && ended)
  {
    ltr = ' ';
    if(strlen(string) > 0)
    {
      ltr = string[0];
      string[0] = ' ';
      val=atoi(string); 
    }

    //Steering algorithm
    if(ltr == 'S')
    {
      Serial.print("This is letter: ");
      Serial.println(ltr);
      Serial.print("<");
      Serial.print(val);
      Serial.println(">");

      //Test wiper motor, channel 1: 1 full rev, 0-stop, 127-forward
      //steerval=map(val,0,1023,0,127);

      //steer.write(steerval);

     /* double steeringInput = val; //Need to use the value calculated above
       steeringInput = constrain(steeringInput, steeringpotMin, steeringpotMax);
       
       double targetPos = map(steeringInput, steeringpotMin, steeringpotMax, -100, 100);
       
       double wheelInput = analogRead(potPin3);
       wheelInput = constrain(wheelInput, wheelpotMin, wheelpotMax);
       
       double currentPos = map(wheelInput, wheelpotMin, wheelPotMax, -100,100);
       
       int error = targetPos - currentPos;
       
       //If error > 10 then apply new turn position
       if(error > 10)
       {
       int Kp = 2; //Will change depending upon testing
       int Turn = Kp*error;
       Turn = constrain(Turn,-63,63);
       Turn = Turn+64;
       Serial.print("Turn position: ");
       Serial.print(Turn);
       steer.write(Turn);
       //send to roboclaw, value between 1 and 127
       //roboclaw datasheet: 1 = fullreverse, 127=fullforward, 64=stop
       }*/

    }

[b]***************    //Brake
    else if(ltr == 'B')
    {
      Serial.print("This is letter: ");
      Serial.println(ltr);
      Serial.print("<");
      Serial.print(val);
      Serial.println(">");
      
      //int Bval = map(val, 0 , 1023, 0,);
      
      if(val > 250) //check this number as seems to record B without being pressing sometimes and want to make 
        //it where it has high enough value to not engage brake while not pressed and motor running
      {
        //stopFunction(); //cut the motor while applying brake
        //send 128 to the roboclaw Channel 2 to apply full brake
        Serial.println("Brake is applied");
        brake.write(128);
      }
      else
      {
        //send 255 to roboclaw to not brake
        Serial.println("Brake is not applied");
        brake.write(255);
      }

    }*********************[/b]

    //Throttle
    else if(ltr == 'G')
    {
      Serial.print("This is letter: ");
      Serial.println(ltr);
      Serial.print("<");
      Serial.print(val);
      Serial.println(">");

      //map down to 1/4 of full speed of 36V motor
      int PWMval = map(val, 0,1023, 0,64); //PWM between 0-255 with 255 being max

      //if(digitalRead(switchPin)==HIGH)
     
      if (PWMval>0)
      {
        Serial.print("Speed Value Forward: ");
        Serial.println(PWMval);
        motorForward(PWMval);
      } 
    }

    //next time
    started = false;
    ended = false;

    index = 0;
    string[index]='\0';
  }
}

//Implement to shut down motor
void stopFunction()
{
  analogWrite(PWML, 0);
  analogWrite(PWMH, 0);
}

//Forard of the motor
void motorForward(int PWMforward)
{
  digitalWrite(DIR, LOW); 
  digitalWrite(PWML, HIGH);
  analogWrite(PWMH, PWMforward);

}

You should connect pin 6 to S1, not S2. In serial mode, S1 and S2 do not correspond to motor channels 1 and 2; S1 is the (only) serial input pin on the RoboClaw, and it is used for controlling both motor channels.

- Kevin

OK!

Got it working now. Thanks!

Ok, so I got the brake working. Now, when I try to implement the steering the brake seems to not cooperate. I am sure I am making a small mistake again. Here is the brake and steering together. First part of main is getting the value through xbee. First ‘if’ statement is the steering(I am receiving in a pot value directly from the second arduino for current wheel position, all other pot values are over xbee). Second ‘if’ statement is the braking. I debugged and tested my values from second arduino and all pots seem to be getting correct values when I turn all the pots. So something seems to not be translating over the the roboclaw.

I would imagine the BMSerial steer as a possible mistake?

#include "BMSerial.h"

pin6 to S1
BMSerial brake(5,6);
BMSerial steer(2,6);

#define PWML    10 //PWM pin for Low, do not need to direction of motor.
#define PWMH    11 //PWM pin for High, needed for direction of motor
#define DIR    12 //non PWM pin for direction control
//#define SWTCH   8; //switch enable for forward/reverse

//read till end of packet
char string[8]; //long enough string for value
byte var; //store each byte
int index = 0;
int val; //store the integer
char ltr; //store the character 
boolean started=false;
boolean ended=false;
int potPin3 = A3;

void setup()
{
  Serial.begin(9600);
  brake.begin(9600);
  steer.begin(9600);

}

void loop()
{
  while(Serial.available() > 0)
  {
    var=Serial.read();
    // less than, <, starts the current value
    if(var=='<') 
    {
      started = true;
      index=0;
      string[index]='\0';
    }
    //break out of while loop when '>' received
    else if(var=='>')
    {
      ended = true;
      break; 
    }
    //if value has started, create string
    else if(started)
    {
      string[index]=var;
      index++;
      string[index]='\0';
    }
  }
  //if you have value, grab character to determine which pot and create integer
  if(started && ended)
  {
    ltr = ' ';
    if(strlen(string) > 0)
    {
      ltr = string[0];
      string[0] = ' ';
      val=atoi(string); 
    }

    //Steering algorithm
    if(ltr == 'S')
    {
      Serial.print("This is letter: ");
      Serial.println(ltr);
      Serial.print("<");
      Serial.print(val);
      Serial.println(">");

       double steeringInput = val; //Need to use the value calculated above for steering pot
       steeringInput = constrain(steeringInput, 345, 795); //345 and 795 were min and max of steering wheel pot
       
       double targetPos = map(steeringInput, 345, 795, -100, 100);
       
       double wheelInput = analogRead(potPin3);

       Serial.print("Wheels moved: ");
       Serial.print(wheelInput);
       wheelInput = constrain(wheelInput, 400, 645); //400 and 645 were min and max of wheel position pot
       
       double currentPos = map(wheelInput, 400, 645, -100,100);
       
       int error = targetPos - currentPos;
       
       //If error > 10 then apply new turn position
       if(error > 10)
       {
       int Kp = 2; //Will change depending upon testing
       int Turn = Kp*error;
       Turn = constrain(Turn,-63,63);
       Turn = Turn+64;
       Serial.print("Turn position: ");
       Serial.print(Turn);
       steer.write(Turn);
       //send to roboclaw, value between 1 and 127
       //roboclaw datasheet: 1 = fullreverse, 127=fullforward, 64=stop
       }

    }

    //Brake
    else if(ltr == 'B')
    {
      Serial.print("This is letter: ");
      Serial.println(ltr);
      Serial.print("<");
      Serial.print(val);
      Serial.println(">");
      
      if(val > 250) 
      {
        //send 128 to the roboclaw Channel 2 to apply full brake
        Serial.println("Brake is applied");
        brake.write(128);
      }
      else
      {
        //send 255 to roboclaw to not brake
        Serial.println("Brake is not applied");
        brake.write(255);
      }

    }

EDIT: Just thought about it again and have changed to something new, I will be testing it out tomorrow. I changed instead of using BMSerial brake and BMSerial steer, I now assume I only need to call BMSerial once so I did:

BMSerial command(5,6);

Then 
command.begin(9600);

Then used command.write for steering between 1-127 and using command.write for braking between 128-255. 

Is that correct thought process for roboclaw? Using ‘command’ for both steering and brake motor but depending on range of value is what motor it controls at that time.

You seem to be on the right track with the code you posted in your edit, along with your description of what you will do. You should try it and see how it turns out.

- Kevin