17 Apr 2019

Autonomous Light Sensing Robot

Ladybot, the light sensing robot.

Purpose of the Ladybot

The Ladybot was created in February of my freshman year, as a project in my Cornerstone of Engineering course. Some of the biggest topics from that course were learning C++ basics, designing in AutoCAD and Solidworks, integration with Arduino, and the basics of MATLAB. This project served as a final implementation of all of those skills put together.

The prompt for the project was to create a fully autonomous robot that would locate the source of light in a dark room, and then show some form of recognition that it was found. We were given a basic chassis, the motors, and motor controllers and sent to work. Splitting the class into teams of 3, this project was set up in a competition format to see which team would locate the light the quickest. Each team also had to create some unique element to add to their robot, and my group chose to implement a small LCD screen which output a percentage estimate.

Implementation Details

At the time the code for the Ladybot was written, I was much less experienced than I am now, and so if I were to redo it there’s a lot of things I would optimize and change. However, I think that the basic hardware design was actually quite ideal for this purpose. At the front of the Ladybot were two ultrasonic distance sensors, which would force the Ladybot to turn away when met with an obstacle. The two outward-facing “antennae” of the Ladybot are long wires connected to photoresistors. The dual photoresistor design was key to our team’s success, as the Ladybot was one of the few robots in the competition which always ran towards the goal rather than stop, calibrate, and move. Finally, the red-colored LED seen at the top of the shell of the Ladybot turned on upon reaching the light source.

The second goal of the Ladybot was to implement the secondary LCD screen feature. While the robot was running, the LCD screen on the back, connected to a separate Arduino Uno, was reading out the “percent complete” of the robot’s journey. Especially as a first timer, figuring out how to work a master-slave connection between the two boards was complicated and difficult, but we did end up getting it after a lot of trial and error. Thankfully, there were many resources online for IC2 and we got it up and running.

Diagrams and Code

Solidworks Diagram for Ladybot

Fritzing Wiring Diagram:

Wiring Diagram for Ladybot

MAIN CODE (IC2 Master, Movement, Light, Distance Sensor Control)

  #include <Wire.h>
  const int rightTrigPin = 3;
  const int rightEchoPin = 13;

  const int leftTrigPin = 5;
  const int leftEchoPin = 12;

  int photoresistorR = 0;
  int photoresistorL = 0;

  //the left motor will be controlled by the motor B pins on the motor driver
  const int PWMB = 10;           
  const int BIN2 = 2;          
  const int BIN1 = 7;           

  //the right motor will be controlled by the motor A pins on the motor driver
  const int AIN1 = 8;           
  const int AIN2 = 4;           
  const int PWMA = 11;           

  const int buttonPin = 6;                                   
  const int alertLED = 9;

  float distance = 0;            

  //robot behaviour variables
  int backupTime = 300;           
  int turnTime = 150;             
  int adjustTime = 100;           

  void setup()
  {
    pinMode(rightTrigPin, OUTPUT);       
    pinMode(rightEchoPin, INPUT);       

    pinMode(buttonPin, INPUT_PULLUP);   
    pinMode(alertLED, OUTPUT);

    //set the motor contro pins as outputs
    pinMode(AIN1, OUTPUT);
    pinMode(AIN2, OUTPUT);
    pinMode(PWMA, OUTPUT);

    pinMode(BIN1, OUTPUT);
    pinMode(BIN2, OUTPUT);
    pinMode(PWMB, OUTPUT);

    Serial.begin(9600);     
    Wire.begin();                  
    Serial.print("BEGIN MOTION");  
  }

  void loop()
  {
   // button code

    if(digitalRead(buttonPin) == LOW) {
    rightMotor(0);
    leftMotor(0);
    Serial.print("Button");
    while(true) {}

    } else {

    //DETECT THE DISTANCE READ BY THE DISTANCE SENSOR

    float rightDistance = getRDistance();
    float leftDistance = getLDistance();

    if (rightDistance < leftDistance){
      distance = rightDistance;
      Serial.println("R");
    } else if (leftDistance < rightDistance){
      distance = leftDistance;
      Serial.println("L");
    } else {
      distance = (leftDistance + rightDistance) / 2;
      Serial.println("AVE");
    }

    Serial.print("Distance: ");
    Serial.print(distance);
    Serial.println(" in");             
      if(distance < 15){               
        //back up and turn
        Serial.print(" ");
        Serial.print("Turning...");

        //stop for a moment
        rightMotor(0);
        leftMotor(0);
        delay(200);

        //turn as planned
        rightMotor(-255);
        leftMotor(255);    
        delay(turnTime);

      } else {                        
        const int moveSpeed = 175;
        const int successLight = 800;
        byte lightlevel = 0;
        Serial.print(" ");
        Serial.print("Moving...");

        photoresistorR = analogRead(A0);
        photoresistorL = analogRead(A1);
        Serial.print("Right Light is: ");
        Serial.print(photoresistorR);
        Serial.print("  Left Light is: ");
        Serial.println(photoresistorL);

        if (photoresistorR > successLight || photoresistorL > successLight) {

          while(true) {
            rightMotor(0);
            leftMotor(0);
            if(photoresistorR > photoresistorL){

            Serial.print("found light source");
            digitalWrite(alertLED, HIGH);
            Wire.beginTransmission(9);
            Wire.write(99);
            Wire.endTransmission();
            }

          }
        } else if (photoresistorR > photoresistorL){
           rightMotor(0);
           leftMotor(0);
           rightMotor(moveSpeed);
           lightlevel = map(photoresistorR,0,1023,0,127);
           Wire.beginTransmission(9);
            Wire.write(lightlevel);
            Wire.endTransmission();
            Serial.print(" sent right light ");
          // Wire.write(lightlevel);

           delay(adjustTime);
        } else if (photoresistorL > photoresistorR){
           rightMotor(0);
           leftMotor(0);
           leftMotor(moveSpeed);
           lightlevel = map(photoresistorL,0,1023,0,127);
           Wire.beginTransmission(9);
            Wire.write(lightlevel);
            Wire.endTransmission();
            Serial.print(" sent left light ");
           //Wire.write(lightlevel);
           delay(adjustTime);

        }   

        rightMotor(moveSpeed);
        leftMotor(moveSpeed);
        //delay(100);
      }
  }
  }

  void rightMotor(int motorSpeed)                       
  {
    if (motorSpeed > 0)                                
    {
      digitalWrite(AIN1, HIGH);                        
      digitalWrite(AIN2, LOW);                          
    }
    else if (motorSpeed < 0)                            
    {
      digitalWrite(AIN1, LOW);                          
      digitalWrite(AIN2, HIGH);                         
    }
    else                                               
    {
      digitalWrite(AIN1, LOW);                          
      digitalWrite(AIN2, LOW);                          
    }
    analogWrite(PWMA, abs(motorSpeed));                 
  }

  void leftMotor(int motorSpeed)                        
  {
    if (motorSpeed > 0)                                 
    {
      digitalWrite(BIN1, HIGH);                         
      digitalWrite(BIN2, LOW);                         
    }
    else if (motorSpeed < 0)                           
    {
      digitalWrite(BIN1, LOW);                          
      digitalWrite(BIN2, HIGH);                        
    }
    else                                               
    {
      digitalWrite(BIN1, LOW);                         
      digitalWrite(BIN2, LOW);                         
    }
    analogWrite(PWMB, abs(motorSpeed));                 

  //RETURNS THE DISTANCE MEASURED BY THE HC-SR04 DISTANCE SENSOR
  float getRDistance()
  {
    float echoTime;                   
    float calcualtedDistance;         

    //send out an ultrasonic pulse that's 10ms long
    digitalWrite(rightTrigPin, HIGH);
    delayMicroseconds(10);
    digitalWrite(rightTrigPin, LOW);

    echoTime = pulseIn(rightEchoPin, HIGH);      


    calcualtedDistance = echoTime / 148.0;  

    return calcualtedDistance;             
  }

  float getLDistance()
  {
    float echoTime;                   
    float calcualtedDistance;         
    //send out an ultrasonic pulse that's 10ms long
    digitalWrite(leftTrigPin, HIGH);
    delayMicroseconds(10);
    digitalWrite(leftTrigPin, LOW);

    echoTime = pulseIn(leftEchoPin, HIGH);      


    calcualtedDistance = echoTime / 148.0;

    return calcualtedDistance;              
  }

LCD CODE (IC2 Slave, LCD controller)

  #include <LiquidCrystal.h>        
  #include <Wire.h>
  int photoresistorR = 0;
  int photoresistorL = 0;

  LiquidCrystal lcd(13, 12, 11, 10, 9, 8);
  int x = 0;
  void setup() {                     

    lcd.begin(16, 2);             
    lcd.clear();
    Serial.begin(9600);
    Wire.begin(9);
    Wire.onReceive(receiveEvent);
  }
  void receiveEvent(int bytes){
    x = Wire.read();
    Serial.print(x);
  }
  void loop() {
    int SL = 99;
    int realLight = x;
    bool done = false;
    Serial.println(realLight);
    int percentage = 0;
  if(realLight<SL){
    percentage = 100*realLight/SL;
    } else {
      done = true;
    }
    lcd.setCursor(1,0);  
    lcd.print("-- Progress --");
    lcd.setCursor(9,1);
    lcd.print("%");
    if(!done){
      lcd.setCursor(6,1);
      lcd.print(percentage);
    } else if(done) {
      lcd.setCursor(5,1);
      lcd.print("100");
    }
    delay(200);
    lcd.clear();
  }