Running Modules for a Specified Time Period

Hi;

I am having trouble manoeuvring my web controlled robot and need to fine tune the Left and Right commands.

The robot is controlled from a control panel that contains buttons (Forward, Backward, Left, Right etc) on a web page. The web control is handled by a Raspberry Pi running WebioPI that serves a Web Page.

The motors are connected to the Arduino Nano via an L298 H-Bridge and the Arduino is connected to the Raspberry Pi via an i2c 2 wire connection.

When you press a button a program on the web page WebioPi sends a number over the i2c connection to the Nano. When the Nano receives the number it runs the corresponding function e.g. Left().

The problem I am having is that when any of the drive functions are called the motors run for approx 2 seconds but for turning this is two long as the robot spins about 270 degrees, I only want to be able to turn the robot only about 90 degrees.

How can I reduce the turn? I have tried PWM but for some reasons this does not work. I there any way I can reduce the length of time the motors turn? I am experimenting with Millis() but can't seem to fathom this out.

JonnyAlpha:
Hi;

I am having trouble manoeuvring my web controlled robot and need to fine tune the Left and Right commands.

The robot is controlled from a control panel that contains buttons (Forward, Backward, Left, Right etc) on a web page. The web control is handled by a Raspberry Pi running WebioPI that serves a Web Page.

The motors are connected to the Arduino Nano via an L298 H-Bridge and the Arduino is connected to the Raspberry Pi via an i2c 2 wire connection.

When you press a button a program on the web page WebioPi sends a number over the i2c connection to the Nano. When the Nano receives the number it runs the corresponding function e.g. Left().

The problem I am having is that when any of the drive functions are called the motors run for approx 2 seconds but for turning this is two long as the robot spins about 270 degrees, I only want to be able to turn the robot only about 90 degrees.

How can I reduce the turn? I have tried PWM but for some reasons this does not work. I there any way I can reduce the length of time the motors turn? I am experimenting with Millis() but can’t seem to fathom this out.

You should, at the minimum, post the CODE using the </> button, that shows how you receive the “F, B, L, R” COMMANDS and the code that is called that actually turns the motors.

Sorry;

Here’s the latest code that I have been playing with (it has a problem now that when I press Left the motors keep spinning left and wont stop).
I have had to remove some of the non movement code from what I have posted as it exceeds the required amount.

// Program to set an Arduino as a slave for an i2c connection with a Raspberry Pi
// Controlling a mobile platform (robot) with manual and autonomous modes  
// Connections are Arduino Pin A5 to RPi SDA Arduino Pin A6 to RPi SCL
// Inspiration for i2c from Oscar Laing's Blog http://blog.oscarliang.net/raspberry-pi-arduino-connected-i2c

//Setup libraries
#include <Wire.h>
#include <Servo.h>

//Set Arduino as i2c slave and define the Serial bus address
#define SLAVE_ADDRESS 0x04

//Set variables for serial communication
int number = 0; // Number determines which command to run 
int state = 0; // Was used to check High and Low (not yet used)

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

//Defines for reading distances and collision avoidance when in autonomous mode (when setup) 
#define microsecondsToCentimeters(microseconds) (unsigned long)microseconds / 29.1 / 2.0
#define Min_Action_Distance 40 // Set maximum allowaable distance to obstacle

//Time delays for motors and servos if required
#define ServoMoveDelay 2000

//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;

//Give servos a logical designation
Servo sensor_servo;

//Setup variables
byte scan_pos = 0;
byte sweep_pos = 0;
byte pos_index = 90;
unsigned long left_distance, right_distance, forward_distance;
unsigned int duration;
unsigned int distance;
//unsigned int FrontDistance;
//unsigned int LeftDistance;
//unsigned int RightDistance;
unsigned long lastDataReceivedMillis; 
unsigned long maxGap = 10000;
unsigned int mode;
unsigned long delayPeriod;
unsigned long endtime;
unsigned long starttime;
unsigned long interval = 500;
unsigned long previousMillis = 0;
unsigned long loopcount;

//Setup battery voltage monitor variables
int batMonPin = A0;
int val = 0;
float pinVoltage = 0;
float batteryVoltage = 0;
float ratio = 2.316;

void setup() {
  delay(1000); // Sets a short delay after switching on
  Serial.begin(9600); // Start serial for output debugging
  Wire.begin(SLAVE_ADDRESS); // Initialise i2c as slave
  Wire.onReceive(receiveData); //Define callbacks for i2c communication
  Wire.onRequest(sendData); //Define callbacks for i2c communication
  
  //Setup the servo
  sensor_servo.attach(2); //Attaches the servo to pin 2 of the Nano
  sensor_servo.write(90); //Set the servo to face front
  scan_pos = 90;
  
  //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);

  // Message to serial monitor declaring that robot is ready
  Serial.println("Hammerstein Ready!");
  mode = 0;
  delayPeriod = 250;
}

void loop() { 
  ping();
  //scan(); 
  get_battery();
  readVcc();
  while(true)
  {
    if (Wire.available())
    {
    mode = 0;
    Serial.println("Manual Mode");  
    continue;
    }
    else if(millis() - lastDataReceivedMillis >= maxGap)
    {
      if (mode == 0) Serial.println("Switching to autonomous mode in 5 seconds");
      delay(5000);
      mode = 1;
      readVcc(); //Check battery?
      AutonomousMode(); //Switch to autonomous mode 
    }
   
  }
}


// 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();
    }
    //if (number == 10) { //Need to create a function in the python code to send command 10
    //  Auto_navigate();
    //}
  }
}

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

void AutonomousMode() //08/09/2015 - autonomous mode set to detect movement 
{
  Serial.println("Now in autonomous mode");
  unsigned long motion_detect_left, motion_detect_right, motion_detect_forward;
  if (mode == 1) //Only execute if in autonomous mode
  {
    Scan();
    motion_detect_left = left_distance;
    motion_detect_right = right_distance;
    motion_detect_forward = forward_distance;
    Scan();
    if (motion_detect_left == left_distance && motion_detect_right == right_distance && motion_detect_forward == forward_distance)
    {
      Stop(); 
    }
    else
    {
      Serial.println("Obstacle detected");
      number = 1;
      Auto_navigate();
      //sendData(number); //Send content of variable 'number' to inform the Raspberry Pi that an obstacle has been detected and to say something
    }
  }
}

void Auto_navigate()
{
  do
  {
    Serial.println("Auto navigating environment");
    Scan();
    if (forward_distance > Min_Action_Distance)
    {
      Forward(); 
    }
    else
    {
      Stop();
      if (left_distance > right_distance && left_distance > Min_Action_Distance)
      {
        Left();
        Forward();
      }
      else
      {
        Right();
        if (right_distance > Min_Action_Distance)
        {
          Forward();
        }
      }
    }
   } while (mode == 1);
}

 



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, 255);   
  // 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, 255);   
  // 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
{
    starttime = millis();
    endtime = starttime;
    while ((endtime - starttime) <=interval)
    {
      Serial.println("");
      Serial.println("Moving left");
      digitalWrite(in1, LOW);
      digitalWrite(in2, HIGH); 
  //  set speed out of possible range 0~255
      analogWrite(enA, 255); 
      digitalWrite(in3, LOW);
      digitalWrite(in4, HIGH);
    //set speed out of possible range 0~255   
      analogWrite(enB, 255);   
  //  delay(100);
      loopcount = loopcount+1;
      endtime = millis();
    } 
}

void Right() //This function tells the robot to turn right
{
  starttime = millis();
  endtime = starttime;
  while ((endtime - starttime) <=interval)
  {  
    Serial.println("");
    Serial.println("Moving right");
    digitalWrite(in1, HIGH);
    digitalWrite(in2, LOW);
// set speed out of possible range 0~255
    analogWrite(enA, 255); 
    digitalWrite(in3, HIGH); //Was High
    digitalWrite(in4, LOW);
    analogWrite(enB, 255);
  //delay(100);
    loopcount = loopcount+1;
    endtime = millis();
  }
}

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);
}
  starttime = millis();
  endtime = starttime;
  while ((endtime - starttime) <=interval)
  {

The more conventional way to do this would be

  starttime = millis();
  while ((millis() - starttime) <= interval)
  {

Sorry, my post was stupid. I read while and somehow saw if.

Mmm - I see what you mean that’s why when I tried this:

void Left() //This function tells the robot to turn left
{
  starttime = millis();
  while ((millis() - starttime) <= interval)
    {
      Serial.println("");
      Serial.println("Moving left");
      digitalWrite(in1, LOW);
      digitalWrite(in2, HIGH); 
  //  set speed out of possible range 0~255
      analogWrite(enA, 255); 
      digitalWrite(in3, LOW);
      digitalWrite(in4, HIGH);
    //set speed out of possible range 0~255   
      analogWrite(enB, 255);   
  //  delay(100);
     } 
}

The motor just keeps running.

So how can I achieve this control?

The motor just keeps running.

Do you issue any commands to stop it before leaving the function ?

UKHeliBob:
Do you issue any commands to stop it before leaving the function ?

No, prior to trying to fine tune using Millis() each movement function when called would run for about 1.5 to 2 seconds. This is probably because the Web Page uses a ‘Mouse Down’ to call a function to run the command and a ‘Mouse Up’ to call the Stop() function which stops the motors.

It is probably the delay between Mouse Up and Mouse Down that needs to be reduced, but that’s not an option (I don’t think), hence trying it this way?

After being prompted by a question from UKHeliBob, I realised that I had forgotten that the motors stop spinning when the Stop() function is called. This function is called when the operator releases the mouse button after clicking one of the drive controls (Forward, Backward etc).

If data flow was instantaneous a rapid click would result in the motors operating for a fraction of a second however due to delays in communication in probably several areas it takes about 1.5 - 2 seconds for the Stop() function to be called.

I have now added a Stop() at the end of the Left() and Right() drive functions and have used a for loop in an attempt to run the for a shorter period, whilst when testing I can now run the motors for a much shorter time period 0.5 seconds it has now (I think) introduced a secondary problem.

The Raspberry Pi keeps crashing, I think due to data overflow on the i2c connection?? This may be caused because when I click a drive button e.g. 'Left' the function runs for loop 20 times and then calls the Stop() function however as I release the mouse button it also calls the Stop() button. Holding the mouse button down does not keep the motors running as it is only one mouse down event?

I could remove the Mouse up event that is calling stop and see what happens?