PWM control using arduino on 18v25 simple motor controller

Hello Guys,

I am doing a Project on 2DOF Motion seat Simulator and in my code I want to use the pwm values and control the Speed of the Motor.
I have a pololu 18v25 simple Motor Controller, but as you know you can only Change the pwm frequency manually in the pololu application. So I wanted to know is there any protocol or any other way to Change These pwm values through arduino and Input it to pololu Motor Controller.

I will send you the code wriiten for Motomonster, I want write this for Pololu 18v25, please help me out, it is very important for me to do this.

    /*   
     Arduino code for dynamic playseat 2DOF
     
     */
#include <SoftwareSerial.h>
    #define BRAKEVCC 0
    #define RV  2 //beware it's depending on your hardware wiring
    #define FW  1 //beware it's depending on your hardware wiring
    #define STOP 0
    #define BRAKEGND 3

    ////////////////////////////////////////////////////////////////////////////////
    #define pwmMax 255 // or less, if you want to lower the maximum motor's speed

    // defining the range of potentiometer's rotation
    const int potMini=208;
    const int potMaxi=815;

    ////////////////////////////////////////////////////////////////////////////////
    #define motLeft 0
    #define motRight 1
    #define potL A0
    #define potR A1

    ////////////////////////////////////////////////////////////////////////////////
    //  DECLARATIONS
    ////////////////////////////////////////////////////////////////////////////////
    /*  VNH2SP30 pin definitions*/
    /*int inApin[2] = {
      7, 4};  // INA: Clockwise input
    int inBpin[2] = {
      8, 9}; // INB: Counter-clockwise input
    int pwmpin[2] = {
      5, 6}; // PWM input
    int cspin[2] = {
      2, 3}; // CS: Current sense ANALOG input
    int enpin[2] = {
      0, 1}; // EN: Status of switches output (Analog pin)
    int statpin = 13;  //not explained by Sparkfun
    /* init position value*/
    int DataValueL=512; //middle position 0-1024
    int DataValueR=512; //middle position 0-1024
    
    
    
    #define rxPin1 3  // pin 3 connects to smcSerial TX  (not used in this example)
    #define txPin1 4  // pin 4 connects to smcSerial RX
    SoftwareSerial smcSerial1(rxPin1, txPin1);
    #define rxPin2 7  // pin 3 connects to smcSerial TX  (not used in this example)
    #define txPin2 8  // pin 4 connects to smcSerial RX
    SoftwareSerial smcSerial2(rxPin2, txPin2);

    ////////////////////////////////////////////////////////////////////////////////
    // INITIALIZATION
    ////////////////////////////////////////////////////////////////////////////////
    void setup()
    {
      // serial initialization
      Serial.begin(115200);
    }
// required to allow motors to move
// must be called when controller restarts and after any error// initialization of Arduino's pins
     /* pinMode(statpin, OUTPUT); //not explained by Sparkfun
      digitalWrite(statpin, LOW);

      for (int i=0; i<2; i++)
      {
        pinMode(inApin[i], OUTPUT);
        pinMode(inBpin[i], OUTPUT);
        pinMode(pwmpin[i], OUTPUT);
      }
      // Initialize braked for motor
      for (int i=0; i<2; i++)
      {
        digitalWrite(inApin[i], LOW);
        digitalWrite(inBpin[i], LOW);
      }*/
 
    ////////////////////////////////////////////////////////////////////////////////
    ///////////////////////////////// Main Loop ////////////////////////////////////
    ////////////////////////////////////////////////////////////////////////////////
    void loop()
    {
      int sensorL,sensorR;

      readSerialData();   // DataValueR & L contain the last order received (if there is no newer received, the last is kept)
      // the previous order will still be used by the PID regulation MotorMotion Function

      sensorR = analogRead(potR);  // range 0-1024
      sensorL = analogRead(potL);  // range 0-1024

      motorMotion(motRight,sensorR,DataValueR);
      motorMotion(motLeft,sensorL,DataValueL);
    }
    ////////////////////////////////////////////////////////////////////////////////
    // Procedure: wait for complete trame
    ////////////////////////////////////////////////////////////////////////////////
    void readSerialData()
    {
      byte Data[3]={
        '0','0','0'          };
      // keep this function short, because the loop has to be short to keep the control over the motors

      if (Serial.available()>2){
        //parse the buffer : test if the byte is the first of the order "R"
        Data[0]=Serial.read();
        if (Data[0]=='L'){
          Data[1]=Serial.read();
          Data[2]=Serial.read();
          //  call the function that converts the hexa in decimal and that maps the range
          DataValueR=NormalizeData(Data);
        }
        if (Data[0]=='R'){
          Data[1]=Serial.read();
          Data[2]=Serial.read();
          //  call the function that converts the hexa in decimal and maps the range
          DataValueL=NormalizeData(Data);

        }
      }
      if (Serial.available()>16) Serial.flush();
    }
    ////////////////////////////////////////////////////////
   void motorMotion(int numMot,int actualPos,int targetPos)
    ////////////////////////////////////////////////////////
    {
      int Tol=20; // no order to move will be sent to the motor if the target is close to the actual position
      // this prevents short jittering moves
      //could be a parameter read from a pot on an analogic pin
      // the highest value, the calmest the simulator would be (less moves)

      int gap;
      int pwm;
      int brakingDistance=30;

      // security concern : targetPos has to be within the mechanically authorized range
      targetPos=constrain(targetPos,potMini+brakingDistance,potMaxi-brakingDistance);

      gap=abs(targetPos-actualPos);

      if (gap<= Tol) {
        motorOff(numMot); //too near to move     
      }
      else {
        // PID : calculates speed according to distance
        pwm=195;
        if (gap>50)   pwm=215;
        if (gap>75)   pwm=235;   
        if (gap>100)  pwm=255;
        pwm=map(pwm, 0, 255, 0, pwmMax);  //adjust the value according to pwmMax for mechanical debugging purpose !

        // if motor is outside from the range, send motor back to the limit !
        // go forward (up)
        if ((actualPos<potMini) || (actualPos<targetPos)) motorGo(numMot, FW, pwm);
        // go reverse (down)   
        if ((actualPos>potMaxi) || (actualPos>targetPos)) motorGo(numMot, RV, pwm);

      }
    }



    ////////////////////////////////////////////////////////////////////////////////
    void motorOff(int motor){ //Brake Ground : free wheel actually
      ////////////////////////////////////////////////////////////////////////////////
      /*digitalWrite(inApin[motor], LOW);
      digitalWrite(inBpin[motor], LOW);*/
      
      smcSerial1.write(0xE0);
      smcSerial2.write(0xE0);
      analogWrite(pwmpin[motor], 0);
    }
    ////////////////////////////////////////////////////////////////////////////////
    /*void motorOffBraked(int motor){ // "brake VCC" : short-circuit inducing electromagnetic brake
      ////////////////////////////////////////////////////////////////////////////////
      digitalWrite(inApin[motor], HIGH);
      digitalWrite(inBpin[motor], HIGH);
      analogWrite(pwmpin[motor], 0);
    }*/

    ////////////////////////////////////////////////////////////////////////////////
    void motorGo(uint8_t motor, uint8_t direct, uint8_t pwm)
    ////////////////////////////////////////////////////////////////////////////////
    {
      if (motor <= 1)
      {
        if (direct <=4)
        {
          // Set inA[motor]
          if (direct <=1)
            //digitalWrite(inApin[motor], HIGH);
            smcSerial1.write(0x85);
          else
            //digitalWrite(inApin[motor], LOW);
            smcSerial1.write(0xE0);

          // Set inB[motor]
          if ((direct==0)||(direct==2))
            //digitalWrite(inBpin[motor], HIGH);
            smcSerial2.write(0x85);
          else
            //digitalWrite(inBpin[motor], LOW);
            smcSerial2.write(0xE0);

          analogWrite(pwmpin[motor], pwm);

        }
      }
    }

    ////////////////////////////////////////////////////////////////////////////////
    void motorDrive(uint8_t motor, uint8_t direct, uint8_t pwm)
    ////////////////////////////////////////////////////////////////////////////////
    {
      // more readable function than Jim's (for educational purpose)
      // but 50 octets heavier ->  unused
      if (motor <= 1 && direct <=4)
      {
        switch (direct) {
        /*case 0: //electromagnetic brake : brake VCC
          digitalWrite(inApin[motor], HIGH);
          digitalWrite(inBpin[motor], HIGH);
          break;*/
        case 3: //Brake Ground (free wheel)
          //digitalWrite(inApin[motor], LOW);
          //digitalWrite(inBpin[motor], LOW);
          smcSerial1.write(0xE0);
          smcSerial2.write(0xE0);
          break;
        case 1: // forward : beware it's depending on your hardware wiring
          //digitalWrite(inApin[motor], HIGH);
          //digitalWrite(inBpin[motor], LOW);
          smcSerial1.write(0x85);
          smcSerial2.write(0xE0);
          break;
        case 2: // Reverse : beware it's depending on your hardware wiring
          //digitalWrite(inApin[motor], LOW);
          //digitalWrite(inBpin[motor], HIGH);
          smcSerial1.write(0xE0);
          smcSerial2.write(0x85);
          break;
        }
        analogWrite(pwmpin[motor], pwm);
      }
    }
    ////////////////////////////////////////////////////////////////////////////////
    // testPot
    ////////////////////////////////////////////////////////////////////////////////
    void testPot(){

      Serial.print(analogRead(potL));
      Serial.print(";");
      Serial.println(analogRead(potR));
      delay(250);

    }
    ////////////////////////////////////////////////////////////////////////////////
    void testpulse(){
      int pw=120;
      while (true){

        motorGo(motLeft, FW, pw);
        delay(250);       
        motorOff(motLeft);
        delay(250);       
        motorGo(motLeft, RV, pw);
        delay(250);       
        motorOff(motLeft);     

        delay(500);       

        motorGo(motRight, FW, pw);
        delay(250);       
        motorOff(motRight);
        delay(250);       
        motorGo(motRight, RV, pw);
        delay(250);       
        motorOff(motRight);     
        Serial.println("testpulse pwm:80");     
        delay(500);

      }
    }
    ////////////////////////////////////////////////////////////////////////////////
    // Function: convert Hex to Dec
    ////////////////////////////////////////////////////////////////////////////////
    int NormalizeData(byte x[3])
    ////////////////////////////////////////////////////////////////////////////////
    {
      int result;

      if ((x[2]==13) || (x[2]=='R') || (x[2]=='L'))  //only a LSB and Carrier Return or 'L' or 'R' in case of value below 16 (ie one CHAR and not 2)
      {
        x[2]=x[1];  //move MSB to LSB
        x[1]='0';     //clear MSB
      }
      for (int i=1; i<3; i++)
       {
        if (x[i]>47 && x[i]<58 ){//for x0 to x9
          x[i]=x[i]-48;
        }                       
          if (x[i]>64 && x[i]<71 ){//for xA to xF
          x[i]=(x[i]-65)+10;       
        }
      }
      // map the range from Xsim (0 <-> 255) to the mechanically authorized range (potMini <-> potMaxi)
      result=map((x[1]*16+x[2]),0,255,potMini,potMaxi);
      return result;
    }

Hello.

It sounds like you want to change the PWM frequency on the Simple Motor Controller in order to change the speed of your motor, which is incorrect. Changing the duty cycle of the PWM signal will change the speed of the motor, and that can be done by sending certain serial TTL signals to the Simple Motor Controller. Judging by your code, it looks like you are already trying this. If your motor is not running as you expect, can you try simplifying your system by running our “Simple Example” for Arduino? You can find that under the “Arduino Examples” section of Simple Motor Controller’s user’s guide, which can be found under the “Resources” tab of any Simple Motor Controller’s product page. If the motor does not run when you try that code, can you tell me more about your system? How are you supplying power? What motor are you using? It would also help if you post pictures of your setup.

-Jon

Hello Jon,
Thank you so much for the reply…

We have tried all the examples that you said and it is working completely fine.
And today I changed the program according to pololu controller and tried, now I have no Errors on the program, not even on the pololu application, but the Motor just keeps rotating and does nothing.

As you know I am taking the values from the X sim Software and Controlling the pololu Controllers with arduino for my 2DOF Motion Simulator, so I will send you the pics of my Connection and also the Screen shots from Xsim and the new code. so please help me out.

And this is the new code…

#include <SoftwareSerial.h>
    #define BRAKEVCC 0
    #define STOP 0
    #define BRAKEGND 3

    ////////////////////////////////////////////////////////////////////////////////
    #define pwmMax 255 // or less, if you want to lower the maximum motor's speed

    // defining the range of potentiometer's rotation
    const int potMini=20;
    const int potMaxi=620;

    ////////////////////////////////////////////////////////////////////////////////
    #define motLeft 0
    #define motRight 1
    #define potL A0
    #define potR A5

 
    int DataValueL=512; //middle position 0-1024
    int DataValueR=512; //middle position 0-1024
    
    
    
    #define rxPin1 3  // pin 3 connects to smcSerial TX  (not used in this example)
    #define txPin1 4  // pin 4 connects to smcSerial RX
    SoftwareSerial smcSerial1(rxPin1, txPin1);
    #define rxPin2 7  // pin 3 connects to smcSerial TX  (not used in this example)
    #define txPin2 8  // pin 4 connects to smcSerial RX
    SoftwareSerial smcSerial2(rxPin2, txPin2);
    
    
    ////////////////////////////////////////////////////////////////////////////////
    // INITIALIZATION
    ////////////////////////////////////////////////////////////////////////////////

    // required to allow motors to move
    // must be called when controller restarts and after any error
    void exitSafeStart()
    {
      smcSerial1.write(0x83);
      smcSerial2.write(0x83);
    }

    void setup()
    {
      // initialize software serial object with baud rate of 19.2 kbps
      smcSerial1.begin(19200);
      smcSerial2.begin(19200);
     
      // the Simple Motor Controller must be running for at least 1 ms
      // before we try to send serial data, so we delay here for 5 ms
      delay(5);
     
      // if the Simple Motor Controller has automatic baud detection
      // enabled, we first need to send it the byte 0xAA (170 in decimal)
      // so that it can learn the baud rate
      smcSerial1.write(0xAA);  // send baud-indicator byte
      smcSerial2.write(0xAA);
      // next we need to send the Exit Safe Start command, which
      // clears the safe-start violation and lets the motor run
      exitSafeStart();  // clear the safe-start violation and let the motor run
    }


    ////////////////////////////////////////////////////////////////////////////////
    ///////////////////////////////// Main Loop ////////////////////////////////////
    ////////////////////////////////////////////////////////////////////////////////
    void loop()
    {
      int sensorL,sensorR;

      readSerialData();   // DataValueR & L contain the last order received (if there is no newer received, the last is kept)
      // the previous order will still be used by the PID regulation MotorMotion Function

      sensorR = analogRead(potR);  // range 0-1024
      sensorL = analogRead(potL);  // range 0-1024

      motorMotion(motRight,sensorR,DataValueR);
      motorMotion(motLeft,sensorL,DataValueL);
    }
    ////////////////////////////////////////////////////////////////////////////////
    // Procedure: wait for complete trame
    ////////////////////////////////////////////////////////////////////////////////
    void readSerialData()
    {
      byte Data[3]={
        '0','0','0'          };
      // keep this function short, because the loop has to be short to keep the control over the motors

      if (Serial.available()>2){
        //parse the buffer : test if the byte is the first of the order "R"
        Data[0]=Serial.read();
        if (Data[0]=='L'){
          Data[1]=Serial.read();
          Data[2]=Serial.read();
          //  call the function that converts the hexa in decimal and that maps the range
          DataValueR=NormalizeData(Data);
        }
        if (Data[0]=='R'){
          Data[1]=Serial.read();
          Data[2]=Serial.read();
          //  call the function that converts the hexa in decimal and maps the range
          DataValueL=NormalizeData(Data);

        }
      }
      if (Serial.available()>16) Serial.flush();
    }
    ////////////////////////////////////////////////////////
   void motorMotion(int numMot,int actualPos,int targetPos)
    ////////////////////////////////////////////////////////
    {
      int Tol=20; // no order to move will be sent to the motor if the target is close to the actual position
      // this prevents short jittering moves
      //could be a parameter read from a pot on an analogic pin
      // the highest value, the calmest the simulator would be (less moves)

      int gap;
      int pwm;
      int brakingDistance=30;

      // security concern : targetPos has to be within the mechanically authorized range
      targetPos=constrain(targetPos,potMini+brakingDistance,potMaxi-brakingDistance);

      gap=abs(targetPos-actualPos);

      if (gap<= Tol) {
        motorOff(numMot); //too near to move     
      }
      else {
        // PID : calculates speed according to distance
        pwm=195;
        if (gap>50)   pwm=215;
        if (gap>75)   pwm=235;   
        if (gap>100)  pwm=255;
        pwm=map(pwm, 0, 255, 0, 3200);  //adjust the value according to pwmMax for mechanical debugging purpose !

        // if motor is outside from the range, send motor back to the limit !
        // go forward (up)
        if ((actualPos<potMini) || (actualPos<targetPos)) motorGo(numMot, pwm);
        // go reverse (down)   
        if ((actualPos>potMaxi) || (actualPos>targetPos)) motorRev(numMot, pwm);

      }
    }


////////////////////////////////////////////////////////////////////////////////
    void motorOff(int motor){ //Brake Ground : free wheel actually
      ////////////////////////////////////////////////////////////////////////////////
      smcSerial1.write(0xE0);
      smcSerial2.write(0xE0);
      //analogWrite(pwmpin[motor], 0);
    }

    void motorGo(uint8_t motor, int speed)
    
    {
      if (motor == 0)
       {  smcSerial2.write(0x85);  // full-speed forward
          smcSerial2.write(speed & 0x1F);
          smcSerial2.write(speed >> 5);
       }
      else
       {  smcSerial1.write(0x85);  // full-speed forward
          smcSerial1.write(speed & 0x1F);
          smcSerial1.write(speed >> 5);
       }  
  }


    void motorRev(uint8_t motor, int speed)
    
    {
      if (motor == 0)
       {  smcSerial2.write(0x86);  // full-speed forward
          smcSerial2.write(speed & 0x1F);
          smcSerial2.write(speed >> 5);
       }
      else
       {  smcSerial1.write(0x86);  // full-speed forward
          smcSerial1.write(speed & 0x1F);
          smcSerial1.write(speed >> 5);
       }  
    
    }



 ////////////////////////////////////////////////////////////////////////////////
    // Function: convert Hex to Dec
    ////////////////////////////////////////////////////////////////////////////////
    int NormalizeData(byte x[3])
    ////////////////////////////////////////////////////////////////////////////////
    {
      int result;

      if ((x[2]==13) || (x[2]=='R') || (x[2]=='L'))  //only a LSB and Carrier Return or 'L' or 'R' in case of value below 16 (ie one CHAR and not 2)
      {
        x[2]=x[1];  //move MSB to LSB
        x[1]='0';     //clear MSB
      }
      for (int i=1; i<3; i++)
       {
        if (x[i]>47 && x[i]<58 ){//for x0 to x9
          x[i]=x[i]-48;
        }                       
          if (x[i]>64 && x[i]<71 ){//for xA to xF
          x[i]=(x[i]-65)+10;       
        }
      }
      // map the range from Xsim (0 <-> 255) to the mechanically authorized range (potMini <-> potMaxi)
      result=map((x[1]*16+x[2]),0,255,potMini,potMaxi);
      return result;
    }

Pololu screen shots pictures.rar (302.6 KB)

If our example code works fine, then your connections are okay, and your code is likely the issue. In particular, if your motor is rotating, but it does not stop, it sounds like you might not be calling your function to stop the motors, motorOff(). It looks like whether or not that is called depends on the value of gap, so you might try testing out some code that prints gap to the serial monitor to see if you are ever getting values less than Tol.

-Jon

Hello Jon,

Thank you for your reply.
As you know I am using Pololu simple Motor Controller 18v25. I know I can control the speed of the motor but is it possible to control the Position of the Motor through this…?

And is it possible to connect the potentiometer to analog Signal pins “A1” and simulataneously control the pololu through Arduino…? I mean can ’ Analog’ and ‘Serial’ work together…?

Hello.

The Simple Motor Controller cannot be used to do position control. If you want to achieve that, you will have to add your own external hardware for position feedback (like a potentiometer), read those values with your Arduino, and then send motor commands via TTL serial signals to the Simple Motor Controller.

As for your other question, the Simple Motor Controller is always reading the analog input channels, even when the Input Mode is not Analog. So, you could get the raw and scaled voltages measured on the analog channel inputs through serial variable requests. You can learn more about that under the “Using the Serial Interface” section of the SMC’s user’s guide. However, it would probably be easier (or at least more straightforward) to read the potentiometer directly from your Arduino.

-Jon