Arduino Motor Control

Hammerstein_bb.jpg (1447117Bytes)

Hi;

I am working on a web controlled rover and need a little help with fine tuning the controls, I need more precise control over the motors.

Bottom Line Up Front (BLUF)

How can I get the Arduino to process a command for a given time period, I know how to invoke a delay between commands using time.sleep(Number of seconds) but not how to run a function for a given time. My guess is that it would be in a timed loop but I don't know how to do this.

Background:

The motors are connected to an L298N H Bridge and the H Bridge is controlled by an Arduino Nano. The Nano is connected to a Raspberry Pi which sends an integer to the Nano over an i2c connection. The Nano reads the Serial data and when it receives and integer that corresponds to a set functions it runs that function, e.g. 1 = Motors Forward.

I can drive the rover forward, backwards and spin it left and right but it's the left and right that I need to control, at the minute when running the Left or Right functions the corresponding motors spin for a second which is too long small turns, in fact in that time the damm thing has nearly done a 360!!

On the Pi side in the code there is a delay of 1 second (time.sleep(1)) between reading and writing serial data which (I have read) is to avoid overload the i2c serial bus??

The solution is either PWM or Timing, however PWM is for some reason not working, the ENA and ENB connections on the L298 are connected to Digital PWM pins on the Nano but lowering the PWM using analogueWrite(Pin, PWM) just stops the motor?

The Schematic is attached and here's the Arduino code:

// Arduino Pin A5 to RPi SDA
// Arduino Pin A6 to RPi SCL
// Inspiration from Ocra Laing's Blog http://blog.oscarliang.net/raspberry-pi-arduino-connected-i2c 

#include <Wire.h>
#include <Servo.h>

#define SLAVE_ADDRESS 0x04
int number = 0;
int state = 0;

// Setup Ultrasonic Sensor Pins
#define trigPin 12
#define echoPin 13

// Defines for reading distances
#define microsecondsToCentimeters(microseconds) (unsigned long)microseconds / 29.1 / 2.0
#define MinActionDistance 40 // Set maximum allowaable distance to obstacle

// Setup motor controller pins for L298N
// Right Motor
int enA = 11;
int in1 = 8;
int in2 = 7;

//Left Motor
int enB = 10;
int in3 = 6;
int in4 = 5;

// Setup LED test pin
int Led = 3;

// Setup the servo
Servo myservo;

byte sweep_pos = 0;
byte pos_index = 90;
unsigned long left_dist, right_dist;

//Set unsigned integer variables to be used
unsigned int duration;
unsigned int distance;
unsigned int FrontDistance;
unsigned int LeftDistance;
unsigned int RightDistance;

void setup() {
 
 Serial.begin(9600); // Start serial for output
 Wire.begin(SLAVE_ADDRESS); // Initialise i2c as slave

 //Define callbacks for i2c communication
 Wire.onReceive(receiveData);
 Wire.onRequest(sendData);
 
 //Setup the servo
 myservo.attach(2); //Attaches the servo to pin 2 of the Nano
 myservo.write(90); //Set the servo to face front
 
 //Below set all the pin modes as OUTPUT as they will all be outputting data
 //Set modes for distance sensor pins
 pinMode(trigPin, OUTPUT);
 pinMode(echoPin, INPUT);
 
 //Set modes for motor controller pins
 pinMode(enA, OUTPUT);   
 pinMode(enB, OUTPUT);   
 pinMode(in1, OUTPUT);   
 pinMode(in2, OUTPUT);   
 pinMode(in3, OUTPUT);   
 pinMode(in4, OUTPUT);

 //Set mode for Led test pin
 pinMode(Led, OUTPUT);

 // Declare ready
 Serial.println(“Hammerstein Ready!”);
}

void loop() {
 delay(100);
 unsigned long dist_fwd;
 //Rotate the sensor to check for obstacles
 //scan(); //Call the scan function
 ping();
 
}

// Callback for received data
void receiveData(int byteCount) {
 
 while(Wire.available()) {
   number = Wire.read();
   Serial.println("data received: ");
   Serial.println(number);
   
   if (number == 0) {
     Stop();
   }
   if (number == 1) {
     Forward();
   }
   if (number == 2) {
     Left();
   }
   if (number == 3) {
     Right();
   }
   if (number == 4) {
     Backward();
   }
   if (number == 5) {
     Servo_Centre();
   }
   if (number == 6) {
     Servo_Left();
   }
   if (number == 7) {
     Servo_Right();
   }
   if (number == 8) {
     led_on();
   }
   
  if (number == 9) {
   led_off();
  }
 }
}

// Callback for sending data
void sendData() {
 Wire.write(number);
}

void scan() //This function tells the robot to scan for obstacles  
{
 if (sweep_pos <=0) {
   pos_index = 20;
 }
 else if (sweep_pos >=180) {
   pos_index = -20;
 }
 Serial.print ("pos_index = ");
 Serial.println(pos_index);
 sweep_pos += pos_index;
 Serial.print("sweep_pos = ");
 Serial.println(sweep_pos);
 myservo.write (sweep_pos);
}

void Servo_Centre()
{
 Serial.println("");
 Serial.println(“Scanning Forward”);
 if (sweep_pos != 90) {
 myservo.write(90);
 sweep_pos = 90;
 }
}

void Servo_Right()
{
 Serial.println("");
 Serial.println(“Scanning Right”);
 if (sweep_pos != 20) {
   myservo.write(20);
   sweep_pos = 20;
 }
}

void Servo_Left()
{
 Serial.println("");
 Serial.println(“Scanning Left”);
 if (sweep_pos != 160) {
   myservo.write(160);
   sweep_pos = 160;
 }
}

void led_on()
{
 Serial.println("");
 Serial.println(“Led On”);
 digitalWrite(Led, HIGH);
}

void led_off()
{
 Serial.println("");
 Serial.println(“Led Off”);
 digitalWrite(Led, LOW);
}

//Read the HC-SR04 sensor
unsigned long ping()
{
 //Trigger the sensor to send out a ping
 digitalWrite (trigPin, LOW);
 delayMicroseconds (5);
 digitalWrite (trigPin, HIGH);
 delayMicroseconds (10);
 //Measure how long the ping took to return and convert to centimeters
 return (microsecondsToCentimeters (pulseIn (echoPin, HIGH)));
}

void Forward()                                    //This function tells the robot to go forward
{
 Serial.println("");
 Serial.println(“Moving forward”);
 // turn on left motor   
 digitalWrite(in1, HIGH);   
 digitalWrite(in2, LOW);   
 // set speed out of possible range 0~255
 analogWrite(enA, 200);   
 // turn on right motor   
 digitalWrite(in3, LOW);   
 digitalWrite(in4, HIGH);   
 // set speed out of possible range 0~255   
 analogWrite(enB, 255);   
 //delay(100);
}

void Backward()                                  //This function tells the robot to move backward
{
 Serial.println("");
 Serial.println(“Moving backward”);
 // turn on left motor   
 digitalWrite(in1, LOW);   
 digitalWrite(in2, HIGH);   
 // set speed out of possible range 0~255
 analogWrite(enA, 200);   
 // turn on right motor   
 digitalWrite(in3, HIGH);   
 digitalWrite(in4, LOW);   
 // set speed out of possible range 0~255   
 analogWrite(enB, 255);   
 //delay(100);
}

void Left()                                      //This function tells the robot to turn left
{
 Serial.println("");
 Serial.println(“Moving left”);
 digitalWrite(in1, LOW);
 digitalWrite(in2, LOW); //Was High
// set speed out of possible range 0~255
 analogWrite(enA, 0);
 digitalWrite(in3, LOW);
 digitalWrite(in4, HIGH);
// set speed out of possible range 0~255   
 analogWrite(enB, 255);   
 //delay(100);  
}

void Right()                                    //This function tells the robot to turn right
{
 Serial.println("");
 Serial.println(“Moving right”);
 digitalWrite(in1, HIGH);
 digitalWrite(in2, LOW);
// set speed out of possible range 0~255
 analogWrite(enA, 200);
 digitalWrite(in3, LOW); //Was High
 digitalWrite(in4, LOW);
 analogWrite(enB, 0);
 //delay(100);
}

void Stop()                                     //This function tells the robot to stop moving
{
 Serial.println("");
 Serial.println(“Stopping”);
// now turn off motors   
 digitalWrite(in1, LOW);   
 digitalWrite(in2, LOW);
 analogWrite(enA, 0);  
 digitalWrite(in3, LOW);   
 digitalWrite(in4, LOW);
 analogWrite(enB, 0);
}

 

 

     

Scanning your code

shows that you are using PWM and it must be working.

To run something for a period of time, you could always look at the blink without delay example. What keeps you from simply reading a repeated input? If the L key is depressed, keep turning until it is released? I would also hope that you might clean up your movement code.

My code is far from perfect, but, it gets rid of repetitive code. http://pastebin.com/EXGjMNrz

Thanks birdmun, funilly

Thanks birdmun, funilly enough I was just looking at the blink without delay.

I’ll try and clean up my code, its a work in progress and there are parts that don’t do anything yet but they will be needed later. I am progressing since my first posts in this forum :slight_smile:

Ref reading a repeated input, this sort of happens already and works fine for Forward and Backward but I need more control in the turns, when pressing left or right even momenterily the motors run for at least a second which is too long.

There is a delay of one second between commands built in on the Python side on the Raspberry Pi, this (so I am told) is needed when communicating over i2c to avoid overload on the serial bus?

Birdmun - I think I replied

Birdmun - I think I replied to my own thread and not to your post - trying to multitask!!