New to the forum, need some expert advice

Hello all,
I’m a novice coder and Arduino enthusiast .I would like some advice on a project I have in mind and am getting frustrated with.
I have an idea for a 2 wheeled robot, with some basic obstacle avoidance.

the robot is made of:
2 dc motors salvaged from an old Roomba.----plus encoders.
spark fun monster moto shield------or an l293d—I have both options.
1to3 ultrasonic sensors.
and a basic base to mount everything.

my problem is this. :confused:
i can use examples of code to run the motors, and do basic if/else statements. to drive the robot around and read the sensors by modifying the example sketches. but its just not good enough for the behavior I want. I can get values from the encoders but I have no idea how to use the information to have proportional controls to the motors. so it can drive it in a straight line, or compensate being to close to a wall and change its power from one motor to another.

in other words I suck at coding :grin:

I guess my question is. I have some sample code to drive the motors. but it is a long sketch and can be confusing when trying to add code for sensor readings. is there any way to simplify this code?
so that I can add obstacle avoidance with a sonar sensor. and maybe proportional motor controls based on the encoder readings? or would it be easier to ditch the motor shield for the l293d ?

/*  MonsterMoto Shield Example Sketch
  date: 5/24/11
  code by: Jim Lindblom
  hardware by: Nate Bernstein
  SparkFun Electronics
 
 License: CC-SA 3.0, feel free to use this code however you'd like.
 Please improve upon it! Let me know how you've made it better.
 
 This is really simple example code to get you some basic
 functionality with the MonsterMoto Shield. The MonsterMote uses
 two VNH2SP30 high-current full-bridge motor drivers.
 
 Use the motorGo(uint8_t motor, uint8_t direct, uint8_t pwm) 
 function to get motors going in either CW, CCW, BRAKEVCC, or 
 BRAKEGND. Use motorOff(int motor) to turn a specific motor off.
 
 The motor variable in each function should be either a 0 or a 1.
 pwm in the motorGo function should be a value between 0 and 255.
 */
#define BRAKEVCC 0
#define CW   1
#define CCW  2
#define BRAKEGND 3
#define CS_THRESHOLD 100

/*  VNH2SP30 pin definitions
 xxx[0] controls '1' outputs
 xxx[1] controls '2' outputs */
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;

void setup()
{
  Serial.begin(9600);
  
  pinMode(statpin, OUTPUT);

  // Initialize digital pins as outputs
  for (int i=0; i<2; i++)
  {
    pinMode(inApin[i], OUTPUT);
    pinMode(inBpin[i], OUTPUT);
    pinMode(pwmpin[i], OUTPUT);
  }
  // Initialize braked
  for (int i=0; i<2; i++)
  {
    digitalWrite(inApin[i], LOW);
    digitalWrite(inBpin[i], LOW);
  }
  // motorGo(0, CW, 1023);
  // motorGo(1, CCW, 1023);
}

void loop()
{
  motorGo(0, CW, 1023);
  motorGo(1, CCW, 1023);
  delay(500);

  motorGo(0, CCW, 1023);
  motorGo(1, CW, 1023);
  delay(500);
  
  if ((analogRead(cspin[0]) < CS_THRESHOLD) && (analogRead(cspin[1]) < CS_THRESHOLD))
    digitalWrite(statpin, HIGH);
}

void motorOff(int motor)
{
  // Initialize braked
  for (int i=0; i<2; i++)
  {
    digitalWrite(inApin[i], LOW);
    digitalWrite(inBpin[i], LOW);
  }
  analogWrite(pwmpin[motor], 0);
}

/* motorGo() will set a motor going in a specific direction
 the motor will continue going in that direction, at that speed
 until told to do otherwise.
 
 motor: this should be either 0 or 1, will selet which of the two
 motors to be controlled
 
 direct: Should be between 0 and 3, with the following result
 0: Brake to VCC
 1: Clockwise
 2: CounterClockwise
 3: Brake to GND
 
 pwm: should be a value between ? and 1023, higher the number, the faster
 it'll go
 */
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);
      else
        digitalWrite(inApin[motor], LOW);

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

      analogWrite(pwmpin[motor], pwm);
    }
  }
}

this is how I modified it… :grinning: don’t laugh too hard. like I said in the previous post. im a novice.
I do not have a servo at the moment. so what im doing is moving the robot right/middle/left to check the distance with the ultrasonic sensor.then move to the open area. Im waiting for the servo to come in the mail.

// endoder
const int enc_pin = 2;
unsigned long ticks = 0;
//#include <Servo.h>  //servo library
//Servo myservo;      // create servo object to control servo

int Echo = A4;  
int Trig = A5; 



#define BRAKEVCC 0
#define CW   1
#define CCW  2
#define BRAKEGND 3
#define CS_THRESHOLD 100
#define Speed 150
/*  VNH2SP30 pin definitions
 xxx[0] controls '1' outputs
 xxx[1] controls '2' outputs */
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;
int rightDistance = 0, leftDistance = 0, middleDistance = 0;

 //encoder
  void countTicks() {
  ticks++;
}            
void forward(){
  motorGo(0, CW, Speed);
  motorGo(1, CW, Speed); 
  Serial.println("Forward");
}

void back() {
  //back
  motorGo(0, CCW, Speed);
  motorGo(1, CCW, Speed);
  Serial.println("Back");
}

void left() {
  //Left turn
  motorGo(0, CCW, Speed);
  motorGo(1, CW, Speed);
  Serial.println("Left");
}

void right() {
  //right turn
  motorGo(0, CW, Speed);
  motorGo(1, CCW, Speed);
  //analogWrite(ENA, carSpeed);
  //analogWrite(ENB, carSpeed);
  //digitalWrite(IN1, HIGH);
  //digitalWrite(IN2, LOW);
  //digitalWrite(IN3, HIGH);
  //digitalWrite(IN4, LOW);
  Serial.println("Right");
}

void stop() {
  
  //stop
 motorGo(0, CCW, 3);
 motorGo(1, CCW, 3);
  //digitalWrite(ENA, LOW);
  //digitalWrite(ENB, LOW);
  Serial.println("Stop!");

 if ((analogRead(cspin[0]) < CS_THRESHOLD) && (analogRead(cspin[1]) < CS_THRESHOLD))
    digitalWrite(statpin, HIGH);
}

void motorOff(int motor)
{
  // Initialize braked
  for (int i=0; i<2; i++)
  {
    digitalWrite(inApin[i], LOW);
    digitalWrite(inBpin[i], LOW);
  }
  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);
      else
        digitalWrite(inApin[motor], LOW);

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

      analogWrite(pwmpin[motor], pwm);
    }
  }
}

//Ultrasonic distance measurement Sub function
int Distance_test() {
  digitalWrite(Trig, LOW);   
  delayMicroseconds(2);
  digitalWrite(Trig, HIGH);  
  delayMicroseconds(20);
  digitalWrite(Trig, LOW);   
  float Fdistance = pulseIn(Echo, HIGH);  
  Fdistance= Fdistance / 58;       
  return (int)Fdistance;
}  

void setup() { 
//encoder
  pinMode(enc_pin, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(enc_pin), countTicks, CHANGE);
  //myservo.attach(3);  // attach servo on pin 3 to servo object
  Serial.begin(9600);     
  pinMode(Echo, INPUT);    
  pinMode(Trig, OUTPUT);
    
  pinMode(statpin, OUTPUT);

  // Initialize digital pins as outputs
  for (int i=0; i<2; i++)
  {
    pinMode(inApin[i], OUTPUT);
    pinMode(inBpin[i], OUTPUT);
    pinMode(pwmpin[i], OUTPUT);
  }
  // Initialize braked
  for (int i=0; i<2; i++)
  {
    digitalWrite(inApin[i], LOW);
    digitalWrite(inBpin[i], LOW);
  }
  // motorGo(0, CW, 1023);
  // motorGo(1, CCW, 1023);
} 



 
void loop() { 
  //encoder
  Serial.println(ticks);
  delay(100);
    //myservo.write(90);  //setservo position according to scaled value
    //delay(500); 
    middleDistance = Distance_test();

    if(middleDistance <= 20) {     
      stop();
      delay(500);                         
      right();//  myservo.write(10);          
      delay(1000);      
      rightDistance = Distance_test();
      
      delay(500);
    left(); // myservo.write(90);              
      delay(1000);                                                  
     left();// myservo.write(180);              
      delay(1000); 
      leftDistance = Distance_test();
      
      delay(500);
      right();//myservo.write(90);              
      delay(1000);
      if(rightDistance > leftDistance) {
        right();
        delay(360);
      }
      else if(rightDistance < leftDistance) {
        left();
        delay(360);
      }
      else if((rightDistance <= 20) || (leftDistance <= 20)) {
        back();
        delay(180);
      }
      else {
        forward();
      }
    }  
    else {
        forward();
    }  
 }
  float Fdistance = pulseIn(Echo, HIGH);

pulseIn() is a blocking function. Look at the NewPing library to see how to read the distance sensors without blocking.

  delay(100);

If I turned you loose in a strange city, would you, while walking down the street, keep closing your eyes? While in a delay, you are NOT looking where you are going. You'll never be able to go in a straight line, or follow a wall, if you persist in using delay()s.

It's very hard to follow your code with its random indents. Use Tools + Auto Format, and re-post your code.

If you have an encoder for each wheel, then an easy way to drive straight is to count ticks (for a short period of time) and take the difference of the two sides.

If the difference is not zero, increase the power to one motor and decrease the power to the other. Experiment to find a suitable scale (this is the "P" of PID control), as outlined in pseudo-code below:

loop:
count_ticks();
tick_diff = left_ticks-right_ticks;
set_speed_left(base_speed - tick_diff*scale);  //if tick_diff is positive, reduce left motor speed by a fraction
set_speed_right(base_speed + tick_diff*scale);
end

Turns can be accomplished smoothly by adding a bias.

jremington

I used your example. and I wrote this myself. minus the motor codes

im unsure if this is the correct method. but thank you for sparking my thought process.

it seams logical to me

[code]
// encoder pin setup
const int enc_pin1 = 2;
const int enc_pin2 = 3;

//counting ticks
unsigned long left_ticks = 0;
unsigned long right_ticks = 0;
int tick_diff = left_ticks - right_ticks;

//setting motor speed
int scale = tick_diff;
int base_speed = 150;
int set_speed_left = 0;
int set_speed_right = 0;


void setup() {
  Serial.begin(9600);
  //pull up pins from low state
  pinMode(enc_pin1, INPUT_PULLUP);
  pinMode(enc_pin2, INPUT_PULLUP);
  //attch to interrup pins
  attachInterrupt(digitalPinToInterrupt(enc_pin1), left_ticks, CHANGE);
  attachInterrupt(digitalPinToInterrupt(enc_pin2), right_ticks, CHANGE);

}

void loop() {
  // calling the count ticks function
  count_ticks();

}
void count_ticks() {

  tick_diff = left_ticks - right_ticks;
  if (tick_diff <= base_speed ) {
    // increase left motor speed somehow?????
  } else {
    //??????????
  }
}
//increment the ticks when detected on left and right wheel
void leftticks() {
  left_ticks++;
}
void rightticks() {
  right_ticks++;
}

ok, my last code I posted was broken. but im learning. so I am able to read the values from 2 encoders on the motors now. and also compare the two. to see which one is higher. also get the difference between the two. but im at a loss on how to implement the h bridge. I assume I will need to map the values between 0 -1023…so I can drive the motors.??? any ideas anyone…

const int enc_pin1 = 2;
const int enc_pin2 = 3;
unsigned long ticks = 0;
unsigned long ticks2 = 0;
int tickDiff;
int MotorBaseSpeed = 150;

void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);
  pinMode(enc_pin1, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(enc_pin1), countTicks, CHANGE);
  pinMode(enc_pin2, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(enc_pin2), countTicks2, CHANGE);
}

void loop() {
  // put your main code here, to run repeatedly:
  Serial.println(ticks);
  Serial.println(ticks2);
  Serial.println(tickDiff);
  delay(100);
  compareTicks();
  
  //see if the left motor is slower
  tickDiff = ticks - ticks2;
}

void countTicks() {
  ticks++;
}
void countTicks2() {
  ticks2++;
}
void compareTicks() {
  if (ticks < ticks2) {
    Serial.println("left wheel is faster");
    //increase power to right wheel
  }    else {
    Serial.println("right wheel is faster");
    //increase power to left wheel
  }
}

but im at a loss on how to implement the h bridge.

If you mean control the right and left motor speeds, go back and study the simple examples you mentioned in your first post.

With Arduino, usually a PWM output is connected to a motor driver input. PWM values 0 to 255 set the speed from 0 to full on, but not in a linear fashion.

The example sketch in my first post is beyond my knowledge. Its difficult for me to read or modify their code....i need a simplified version.
But thank you for your help. Its much appreciated....i think im going to try and control the left and right motors with the l239d chip...it might be easier for me to control than the monster moto shield from spark fun.

The L293D chip is ancient, very inefficient and wimpy. If it works at all with Roomba motors, don't expect that to last. It is more likely to overheat and shut down.

The example sketch in my first post is beyond my knowledge.

That is exactly where you need to start, before heading out into the unknown. If you don't understand it, then you are not ready to write your own program. Also look at other working examples, and study the on line tutorials. That way you learn the programming language and special features of the Arduino, and spare yourself endless frustration.

Good advice, thanks will do