Using Potentiometer to Change Robot Speed

Hi everyone,

I am working on a line-following robot for an Intro to Engineering Design class. We are assigned to model a chassis for it and go through our processes and present it. My partner and I have been done with our chassis for a while and would like to make some modifications to the electronics side of things while we have time. (I am more knowledgeable in electronics and he is more on the mechanical side).

One of the things that we wanted to do was to be able to change the speed on the spot with a potentiometer instead of having to modify and re-upload the code every time we wanted to change the speed. The speed was originally defined as #define SPEED 65 //set speed from 0-255. So, I removed that and put all of the necessary lines of code for the microcontroller to get a value from a potentiometer under the loop and mapped the values that it reads from pin A5 to a range of 0-255 instead of 0-1023. Code will be posted below (modified from the code that Penn State gave me).

The issue that I am hitting is that it only reads from around 100 to 200. When the potentiometer is near the counterclockwise bound, it shuts the motors off, and when it is near the clockwise bound, it sends the motors full-throttle. When I made a quick sketch to print the potentiometer value in the serial monitor, it reads the full range of the potentiometer perfectly fine (it’s not linear but that is to be expected). I also noticed that the program will not check the address of the motor board unless I turn the potentiometer to which its value is around that 100 mark, which is not a huge deal, but I am thinking it is what is causing my issues. Does anyone have any ideas on what could be getting in the way here?


#include <Arduino.h>
#include <stdint.h>
#include "SCMD.h"
#include "SCMD_config.h" //Contains #defines for common SCMD register names and values
#include "Wire.h"

int QRE1113_Pinl = 0; //left sensor connected to analog 0
int QRE1113_Pinc = 1; //center sensor connected to analog 1
int QRE1113_Pinr = 2; //right sensor connected to analog 2


#define LINETHRESHOLD 400 // This threshold should be updated with the number from your testing 
int SPEED = 0; // sets the nominal speed. Set to any number from 0 - 255.
const int potPin = A5;
SCMD myMotorDriver; //This creates the main object of one motor driver and connected slaves.

void setup()
{
  pinMode(8, INPUT_PULLUP); //Use to halt motor movement (ground)
  pinMode(potPin, INPUT);
  Serial.begin(9600);
  Serial.println("Starting sketch for real.");

  myMotorDriver.settings.commInterface = I2C_MODE;
  myMotorDriver.settings.I2CAddress = 0x5A; //config pattern "0101" on board for address 0x5A

  Serial.println("Got here");

  while ( myMotorDriver.begin() != 0xA9 ) //Wait until a valid ID word is returned
  {
    Serial.println( "ID mismatch, trying again" );
    delay(500);
  }
  Serial.println( "ID matches 0xA9" );

  //  Check to make sure the driver is done looking for slaves before beginning
  Serial.print("Waiting for enumeration...");
  while ( myMotorDriver.ready() == false );
  Serial.println("Done.");
  Serial.println();

  //*****Set application settings and enable driver*****//

 /*EDSGN Based on how you set up your motor, 
you may need to invert the motors. 
(If a wheel is going backwards when you want it to go forward, 
it needs to be inverted)*/
//EDSGN: Uncomment code for motor 0 inversion
  //while( myMotorDriver.busy() );
  //myMotorDriver.inversionMode(0, 1); //invert motor 0
//EDSGN: End uncomment code for motor 0 inversion

 //EDSGN: Uncomment the following code for motor 1 inversion
 // while ( myMotorDriver.busy() ); //Waits until the SCMD is available.
//myMotorDriver.inversionMode(1, 1); //invert motor 1
//EDSGN: End of where you need to uncomment code for motor 1 inversion
/*EDSGN: End of code you need to switch for motor inversion*/

  while ( myMotorDriver.busy() );
  myMotorDriver.enable(); //Enables the output driver hardware

   // Serial.begin(9600);
    Serial.println("Arduino Lab: Line Follower Bot");
    Serial.println("------------------------------------------");
    delay(2000);
    Serial.println("IR Sensor Readings: ");
    delay(500);
}
/*EDSGN: Switch motor definitions here if the right motor and left motor
are switched during the test.*/
#define LEFT_MOTOR 1 //Switch based on motor calibration
#define RIGHT_MOTOR 0 //Switch based on motor calibration
/*EDSGN: End of code you need to switch to define motors*/
void loop()
{
SPEED = analogRead(potPin);
SPEED = map(SPEED, 0, 1023, 0, 255);
Serial.print(SPEED);
  
int right = analogRead(QRE1113_Pinr);

int left = analogRead(QRE1113_Pinl);

int center = analogRead(QRE1113_Pinc);


    // if on the line drive left and right at the same speed (left is CCW / right is CW)
   if(center > LINETHRESHOLD)
    {
        myMotorDriver.setDrive( LEFT_MOTOR, 0, SPEED);
        myMotorDriver.setDrive( RIGHT_MOTOR, 0, SPEED);
Serial.println("center");
Serial.println(center);
    }

    // if the line is under the right sensor, adjust relative speeds to turn to the right
    else if(right > LINETHRESHOLD)
  //  if(right > LINETHRESHOLD)
    {
        myMotorDriver.setDrive( LEFT_MOTOR, 0, (SPEED+30));
        myMotorDriver.setDrive( RIGHT_MOTOR, 1, SPEED+30);
Serial.println("right");
Serial.println(right);

    }

    // if the line is under the left sensor, adjust relative speeds to turn to the left
    else if(left > LINETHRESHOLD)
    {
        myMotorDriver.setDrive( LEFT_MOTOR, 1, (SPEED+30));
        myMotorDriver.setDrive( RIGHT_MOTOR, 0, SPEED+30);
Serial.println("left");
Serial.println(left);

    }

    // if all sensors are on black or up in the air, stop the motors.
    // otherwise, run motors given the control speeds above.
    if((left> LINETHRESHOLD) && (center> LINETHRESHOLD) && (right > LINETHRESHOLD) )
    {
        myMotorDriver.setDrive( LEFT_MOTOR, 0, 0);
        myMotorDriver.setDrive( RIGHT_MOTOR, 0, 0);
            Serial.println("stop");

    }
    else
    {
        myMotorDriver.setDrive( LEFT_MOTOR, 0, SPEED);
        myMotorDriver.setDrive( RIGHT_MOTOR, 0, SPEED);


    }
    delay(0);  //$$$ add a delay to decrease sensitivity.
}

Thank you,
Joe

Please confirm the maximum and minimum raw values read by the potentiometer.

Is this a linear potentiometer ?

It is not a linear potentiometer. By raw values, do you mean the values before the mapping or the actual resistances of the potentiometer with a DMM?

The values after the analog read, before map.

BTW, you can just divide the read value by 4 instead of using map.

SPEED = analogRead(potPin) / 4;

I get values from around 550 to around 850. I did have it set up that way before, but changed it to map just to make sure it wasn’t causing the issue and then just ended up leaving the map anyways.

If you are getting those values, raw values should be 0-1023.

Assume you have a 10k potentiometer top to 5v, bottom to GND, wiper to A0.

Get a new potentiometer, linear is best for most applications i.e. logarithmic is for audio stuff.

Yes my potentiometer is wired that way. When I run a program just to write the values in the serial monitor, I get the 0-1023, but just not linearly, so the potentiometer is working the way it should. Maybe it’s just how I integrated it into the program?

I am missing something here :woozy_face:

What do you get with this ?

SPEED = analogRead(potPin);
Serial.println(SPEED);
SPEED = map(SPEED, 0, 1023, 0, 255);
Serial.println(SPEED);

The numbers I get before the map is ~550 to about 800 and the numbers after the mapping are ~130 to about 200. Tried a linear potentiometer as well as a number of different log pots and all the same results.

When I test each potentiometer with the code below, I get the full 0 - 255 as I should, which is confusing the hell out of me as to why it won’t function correctly when incorporated into the robot’s code.


int SPEED = 0;
const int potPin = A5;

void setup() {
  pinMode(potPin, INPUT);
  Serial.begin(9600);
}

void loop() {
SPEED = analogRead(potPin);
SPEED = map(SPEED, 0, 1023, 0, 255);
Serial.print(SPEED);
Serial.println();
delay(2000);
}

EDIT: I noticed that when I near the left and right bounds of the potentiometer, it stops the program completely until I turn the potentiometer back into the range that the serial monitor has been displaying (~130 to about 180ish). I also noticed that the code wont verify the address of the motor driver board until I turn said potentiometer to that range as well, and then it will move out of the setup and into the loop. I just cant figure why that could be.

Hi,

I assume you are using a UNO or Nano Arduino controller.

Try using another analog input rather than A4 or A5, they are also connected to the I2C /wire().

When you use your test code, you do not have the wire() function operating.

In your full code you do use wire(), and A4 and A5 are then used as I2C comms pins.

This link will help explain;
https://www.arduino.cc/en/reference/wire

Tom… :grinning: :+1: :coffee: :australia:

Ah! I did not realize that A4 and 5 were I2C pins. Never even crossed my mind. I will try A3 and report back!

Bingo! Works flawlessly. Thank you both very much for your help. It is greatly appreciated. Thanks for removing my brain fart about the Wire library Tom! :laughing:

Hi,
Good to hear.
Easily done, some Uno PCBs have separate I2C pins, however they are still connected to A4 and A5, the PCB overlay doesn’t show this.

Tom… :grinning: :+1: :coffee: :australia:

SPEED = map(SPEED, 0, 1023, 0, 255);

sp.

SPEED /= 4;

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.