FANDOM


{{Template:Infobox_Robot

| Name                                        = eXo Bot!

| Image                                       = EXO.JPG

| ProcessorType                               = Arduino

| SensorsUsed                                 = Ultrasonic Rangefinder, Bumper Switch, CMUcam, LCD Display, Pushbutton

| Purpose                                     = Learning Aid for Color Blind Children

| Creators                                    = Arthur Buege

}}


'''eXo Bot''' is a autonomous robot that identifies a sequence of colors and approaches that object. This is a learning robot for children with seeing or learning disabilities.  It will target an object of a specific color,  "blue", and navigate to that object.  Once moving in range of the object, an audible "victory sound" will be played.  Additionally, the color of the object is displayed on an LCD screen. The robot will pause for 10 seconds, then search for another object that matches a color code in its library.  This is a unique and fun way for children and adults to learn how to read and how to recognize colors in their environment.


== Problem Statement ==


Children with seeing disabilities may advance slower through certain classes due to their inability to recognize the color of an object.  If a child is color blind to a specific color, it can be frustrating for both the child and the individuals involved in their development.  Certain colors can be difficult to identify due to the fact that they look similar to another color.  Children with other learning disabilities, such as autism, also require repetitive stimuli in order for them to better develop the core learning skills.  When teaching an individual something new, it is important to maintain a calm, positive attitude during each training session.  How can this be done with a non-bias approach and minimal adult intervention?



== Robot Solution ==


eXo Bot is a grass roots project that provides a non-biased approach at teaching children colors in a unique and futuristic way.  eXo Bot will perform the following:


* It will approach a green, blue, or red block, based on the users selection

* Identify what color the block is on the LCD screen

* eXo Bot will pick up the block and return it to the start location. Upon return, eXo Bot will play a victory sound

* Then it will wait for the user to choose another color block to locate.


This cycle will repeat until the user no longer makes a color selection (the blocks will need to be re-dispersed if all of the blocks are gathered).  


A great benefit of this learning tool is that in an age when most children are glued to the Television, Computer, or Tablet device, this is a fun mobile teaching tool that will get them to move around.  


== Robot Specifications ==



{| class="wikitable"

!Item!!Specification

|-

|Dimensions (L x W x H)|| Actual Size may vary 12" x 18" x 12"

|-

|Weight || 5-20 Pounds 

|-

|Travel system || 2-track drive

|-

|Travel speed || 0 to 3 mph

|-

|Power source|| Lithium-ion rechargeable battery

|-

|Sensors|| Ultrasonic Rangefinder, Bumper Switch, CMUcam, LCD Display, Speaker 

|-

|Operating time|| 5-30 Minutes

|-

|Operating method|| User Selection, Autonomous return

|-


|}


Individual pieces include:


* Platform

* 3-Wheel Base

* 2 Motors

* 4 Servos

* Ultrasonic Rangefinder

* Bumper Switch

* CMUcam

* LCD Display

* On/Off Switch

* 3 Push Buttons

* Assorted Wires, screws, nuts, and bolts

* Tie wraps 

* Arduino Mega 


== Project Schedule ==


[[File:Robot Gantt.JPG|800px]]


== Weekly Status Updates ==


=== January 29, 2016 ===


After reviewing all of the parts I currently have, I placed an order for the additional parts required for the project.  I'm hoping that I ordered everything the project may evolve more after the initial review in class.


=== February 05, 2016 ===


This week I assembled the parts I had available.  Additionally, I assembled the CMUcam (Pixy).  


[[File:Initial Base.jpg|400px]]

[[File:InitialBase2.jpg|400px]]


I am still troubleshooting the CMUcam.  I wish the company would include a Mini-USB cable in the order.  A mini-USB is not as common as it used to be. Pixy programming is work in progress using the Pixymon software.


=== February 12, 2016 ===


After receiving feedback from Poe on my concept, I altered my robot structure some to incorporate his comments.  Additionally, I updated the concept for this project to help implement it better.  I am currently evaluating what parts I need to order verses what I have to implement the upgrades.


=== February 19, 2016 ===


Due to the modifications made last week, I placed an order for additional parts.  I built as much of the structure as I could, then continued to troubleshooted and learn PixyCam.

I had issues where only one motor is rotating when the ultrasonic activated by the ultrasonic sensor.  I am currently focusing on understanding why these issues are occurring.


=== February 26, 2016 ===


I finished testing the motors using Arduino Uno and switched out the Uno microcontroller with an Arduino Mega.  Additionally, due to the size and position required for the claw,  the configuration of the base had to be modified too accommodate.  Mounting the claw to the base has not been as simple as I had assumed it would be.  Initially, I did not realize I would need to control the claws vertical movement.  After mounting the claw in place, I have been working on a design using servos that will control the vertical claw movement.


Next step is to ensure the claw is mounted properly, connected to the servo, and an H-Bridge setup for motor control on claw opening and closing.

Currently re-wiring for Arduino Mega accommodate all sensors.


=== March 4, 2016 ===


[[File:FirstClaw.jpg|400px]]


The Arduino Mega has been mounted, and wiring is now in progress.  Troubleshooting the code for each sensor used will be the next step once the wiring is complete.  

Unfortunately, half of the parts from my original order in February still have not arrived.


Since work on the base has halted until the additional parts arrive, I went ahead and setup PixyCam with the object recognition for the color blocks that were delivered.  


=== March 11, 2016 ===


Obstacle Avoidance code still in progress.  Forward, Turn Left, Turn Right, motion programmed. Working on incorporating the Bumper Switch Interrupt, Reverse/Reverse Left/ Reverse Right, and incorporating the second Ultrasonic Sensor into the code. 


Currently I am having issues with the ultrasonic sensors.  The code is correct, but for some reason the sensors are not working properly every time.  I have pulled each sensor and tested them both stand alone.  Both sensors are not working correctly.  I placed an order for additional sensors and went ahead and borrowed two from a friend to continue on.


I was able to get Amazon to reship my initial order from February and the scheduled delivery is 03/16/16.


=== March 18, 2016 ===


In additional to having faulty ultrasonic sensors, I also found that the trigger and echo pins on the sensors I was using were connected to the same pins on the motor shield that are designated for the motor operations.

This not only caused the motors to rotate whenever the ultrasonic was actuated, but also affected the performance of the ultrasonic's as feedback from the motors was occurring every time the movement was halted.  Most likely the motor feedback fried my original sensors.


I have been coding heavily now to make sure all of the pins used on the Mega do not conflict with the motor shield pins.  This was a lesson learned the hard way, but at least I know and understand what to avoid now.


Now that the pins for the ultrasonic's no longer conflict with the motors, my collision avoidance code finally works!  How exciting to find out that my collision avoidance code was correct and it was just a wiring issue.

=== March 25, 2016 ===


This week I have been working on the claw opening and closing.  Basically, the gripper is not consistent since it runs off a DC motor instead of a more precise servo.  The DC motor runs on a specified delay in time and motor speed.  The issue I am having is that the claw motor runs at a specific constant speed while opening, but when closing the claw, the motor runs at random speeds.  Since the claw closure is not constant, I am considering using a bumper switch in the grip of the claw in order to trigger a disable on the motor movement.  


Unfortunately, the bumper switches I purchased are too large and so I have mounted a servo for vertical movement and identified the degree change required to raise and lower the claw.  


Additionally, I am now learning about I2C on the Arduino.  I have been told it is better, and the LCD screen purchased requires it to be used.  I have a ton of research to do to figure this part out.


=== April 1, 2016 ===


I have been researching the options on the claw between a purchasing a new claw that is servo operated or purchasing a smaller bumper switch to mount on the claw.  Ultimately, I found that the motor itself operates at such spontaneous speeds that I went ahead and ordered a new claw that is servo driven.  I was hoping to avoid ordering a new claw, since i would rather focus on coding, but the way the current claw is performing this was not an option.  


I have been building sections of code that when combined will allow me to control all movement.  Since the new claw will be servo driven, I have called out the specific pin that will control the claw and have continued forward in coding this project. 


Integrating Pixy into the code is turning out to be incredibly hard.  There is a massive learning curve that I have to overcome.  The basic "Hello World" tutorial code is a start, but it is no where near enough for what my project requires.  In an effort to try to get this to work easier, I have setup Pixy to only recognize the green blocks.  Once I can get eXo Bot working for one color block, I will expand on the color options.


=== April 8, 2016 ===


The new claw is here!  I have assembled the new claw and am working on mounting it on the base.  Additionally, the LCD screen is not working with the I2C on the Arduino Mega that I am using.  I troubleshooted it multiple times but the Hex digit changes every time I run the I2C Scanner code. 


I connected the LCD to an Arduino Uno to test whether or not the LCD was broken.  It turns out that for some reason I2C does not work on my Mega Board.  I borrowed another Mega from a friend to see if maybe the drivers I installed were the right ones or not. I found that the version of the driver installed mattered for the Mega.  I had to revert the version back to version 1.0.0 in order for it to work on the borrowed mega instead of version 1.0.1.  After many attempts to get the I2C working properly on my mega, It just is not working.  At this point  I have decided to continue to work on integrating PIXY to the Arduino and combining it with motor controls.


[[File:OLEDworking.jpg|200px]]


=== April 15, 2016 ===


The Claw!!!  New parallel gripper has been assembled and attached to the frame.  After many trial and error attempts, I finally figured out the correct percentages for both the vertical movement servo and the gripper open/close position.  Since the blocks are a specific size, I had to calibrate the closure of the gripper to be nearly identical to the size of the block.  If the gripper closed too tight on the block, the block would force the servo to reopen slightly and the block would drop.


The LCD screen is still not working with my mega.  I ordered another one, but I do not know if it will be delivered prior to the deadline for robot presentations.


Integrated CMU cam and movement:  I have been able to program the robot to follow a pre-programmed colored blocks using the Pixymon software.  Currently, I am trying to get the motor movement to slow and brake when a block is within range of the claw to be picked up.  Each time I add a brake operation into the code for the movement, the motors freeze up as soon as the block is located on the camera.  Essentially, I have an idea of what needs to be corrected in the code.  I just need to continue working on it until I can iron out the movement of the robot.




[[File:Final1.jpg|300px]]


== Robot Schematics ==


[[File:Schematic.JPG|800px]]


== Robot Source Code ==


<source lang="c">


#include <SPI.h>  

#include <Pixy.h>

#include <Servo.h>


const int trig1R = 16, echo1R = 17, trig2L= 21, echo2L= 20;

const int down = 120, up = 40;

int armPos = 0, armServoPin = 6;

Servo armServo;

int clawPos = 40, clawServoPin = 5;

Servo claw;

int openClaw = 110, closeB = 40, closeFull = 10;

int x = 0;

volatile byte state = HIGH;

const byte interruptPin = 19; 

long duration1R, distcm1, distinch1, duration2L, distcm2, distinch2;

int mDelay   = 5000;


//////////////////////////////////////////////

/////////        pixie stuff      ////////////

//////////////////////////////////////////////


Pixy pixy;

#define X_CENTER        ((PIXY_MAX_X-PIXY_MIN_X)/2)       

#define Y_CENTER        ((PIXY_MAX_Y-PIXY_MIN_Y)/2)

class ServoLoop

{

public:

  ServoLoop(int32_t pgain, int32_t dgain);

  void update(int32_t error);

  int32_t m_pos;

  int32_t m_prevError;

  int32_t m_pgain;

  int32_t m_dgain;

};


ServoLoop panLoop(200, 500);

ServoLoop tiltLoop(200, 900);

ServoLoop::ServoLoop(int32_t pgain, int32_t dgain)

{

  m_pos = PIXY_RCS_CENTER_POS;

  m_pgain = pgain;

  m_dgain = dgain;

  m_prevError = 0x80000000L;

}

void ServoLoop::update(int32_t error)

{

  long int vel;

  char buf[32];

  if (m_prevError!=0x80000000)

  {

    vel = (error*m_pgain + (error - m_prevError)*m_dgain)>>10;

     m_pos += vel;

    if (m_pos>PIXY_RCS_MAX_POS) 

      m_pos = PIXY_RCS_MAX_POS; 

    else if (m_pos<PIXY_RCS_MIN_POS) 

      m_pos = PIXY_RCS_MIN_POS;

  }

  m_prevError = error;

}


/////////////////////////////////////////////////////

///////                setup               //////////

/////////////////////////////////////////////////////


void setup()

{  

  Serial.begin(9600); // begin serial communitication  

  pinMode(trig1R, OUTPUT); //Right Ultrasonic

  pinMode(echo1R, INPUT);  //Right Ultrasonic

  pinMode(trig2L, OUTPUT); //Left Ultrasonic

  pinMode(echo2L, INPUT);  //Left Ultrasonic

  pinMode(12, OUTPUT); //Channel A direction

  pinMode(9, OUTPUT); //Channel A brake

  pinMode(13, OUTPUT); //Channel B direction

  pinMode(8, OUTPUT); //Channel B brake

  armServo.attach(armServoPin);

  claw.attach(clawServoPin);

  pixy.init();

  pinMode(interruptPin, INPUT_PULLUP);

  attachInterrupt(digitalPinToInterrupt(interruptPin), interupt, CHANGE);


}


void loop()

{

  int size0; 

  static int i = 0;

  int j;

  uint16_t blocks;

  char buf[32]; 

  int32_t panError, tiltError;

  Serial.println(distinch1);

  Serial.println(distinch2);  

  blocks = pixy.getBlocks();


/*  armServo.write(up);    // Claw controls.. Will need this later

  delay (1000);

  armServo.write(down);

  delay (1000);

  claw.write(openClaw);

  delay (1000);

  claw.write(closeB);  

  delay (1000);

  armServo.write(up);

*/ 

  if (blocks)

  {

    panError = X_CENTER-pixy.blocks[0].x;

    tiltError = pixy.blocks[0].y-Y_CENTER;

    panLoop.update(panError);

    tiltLoop.update(tiltError);

    pixy.setServos(panLoop.m_pos, tiltLoop.m_pos);

    i++;

    // do this (print) every 50 frames because printing every

    // frame would bog down the Arduino

    if (i%50==0) 

    {

      sprintf(buf, "Detected %d:\n", blocks);

      Serial.print(buf);

      for (j=0; j<blocks; j++)

      {

        sprintf(buf, "  block %d: ", j);

        Serial.print(buf); 

        pixy.blocks[j].print();

      }

    }

  }


// avoid();   //Adds avoidance into movement

/////////////////////////////////////////////////////

///////                PIXY                //////////

/////////////////////////////////////////////////////


if(pixy.blocks[0].x > 190)   //x axis is only from 0 to 320

{

   right();

//   delay(50);

//   avoid();     //Adds avoidance into movement

}

if(pixy.blocks[0].x < 130)

{

   left();

//   delay(50);

//   avoid();      //Adds avoidance into movement

}

if(pixy.blocks[0].x > 130 && pixy.blocks[0].x < 190)

{

  forwardSlow();

//  avoid();       //Adds avoidance into movement

  if(x<1)

  {

    clawMove();

    x=x+1;         //Restricts grab to 1 time.  Once Object is picked up it is not dropped

  }

}

}


/////////////////////////////////////////////////////

///////             commands               //////////

/////////////////////////////////////////////////////


void clawMove() {


  claw.write(openClaw);

  delay (1000);

  armServo.write(down);

  delay (1000);

  claw.write(closeB);  

  delay (1000);

  armServo.write(up);

  delay (1000);

}


void forward() {

  digitalWrite(12, LOW);   //Establishes forward direction of Channel A

  digitalWrite(9, LOW);    //Disengage the Brake for Channel A

  analogWrite(3, 200 );    //Spins the motor on Channel A at full speed

  digitalWrite(13, HIGH);  //Establishes backward direction of Channel B (Motor Rotates Opposite Channel A)

  digitalWrite(8, LOW);    //Disengage the Brake for Channel B

  analogWrite(11, 200);    //Spins the motor on Channel B at half speed

}


void forwardSlow() {

  //Motor A forward @ full speed

  digitalWrite(12, LOW);   //Establishes forward direction of Channel A

  digitalWrite(9, LOW);    //Disengage the Brake for Channel A

  analogWrite(3, 100);      //Spins the motor on Channel A at full speed


  //Motor B backward @ half speed

  digitalWrite(13, HIGH);  //Establishes backward direction of Channel B

  digitalWrite(8, LOW);    //Disengage the Brake for Channel B

  analogWrite(11, 100);     //Spins the motor on Channel B at half speed

}


void left() {

  //Motor A forward @ full speed

  digitalWrite(12, HIGH);  //Establishes forward direction of Channel A

  digitalWrite(9, LOW);    //Disengage the Brake for Channel A

  analogWrite(3, 125);     //Spins the motor on Channel A at full speed


  //Motor B backward @ half speed

  digitalWrite(13, HIGH);  //Establishes backward direction of Channel B

  digitalWrite(8, LOW);    //Disengage the Brake for Channel B

  analogWrite(11, 50);    //Spins the motor on Channel B at half speed

}


void right() {

  //Motor A forward @ full speed

  digitalWrite(12, LOW);   //Establishes forward direction of Channel A

  digitalWrite(9, LOW);    //Disengage the Brake for Channel A

  analogWrite(3, 50);     //Spins the motor on Channel A at full speed


  //Motor B backward @ half speed

  digitalWrite(13, LOW);   //Establishes backward direction of Channel B

  digitalWrite(8, LOW);    //Disengage the Brake for Channel B

  analogWrite(11, 125);    //Spins the motor on Channel B at half speed

}


void backward() 

{

  //Motor A forward @ full speed

  digitalWrite(12, HIGH);  //Establishes forward direction of Channel A

  digitalWrite(9, LOW);    //Disengage the Brake for Channel A

  analogWrite(3, 200);     //Spins the motor on Channel A at full speed


  //Motor B backward @ half speed

  digitalWrite(13, LOW);   //Establishes backward direction of Channel B

  digitalWrite(8, LOW);    //Disengage the Brake for Channel B

  analogWrite(11, 200);    //Spins the motor on Channel B at half speed

}



void brake() 

{

  digitalWrite(9, HIGH);

  analogWrite(3, 0);       //Stops the motor on Channel A

  digitalWrite(8, HIGH);

  analogWrite(11, 200);    //Stops the motor on Channel B

}  


/////////////////////////////////////////////////////

///////          object avoidance          //////////

/////////////////////////////////////////////////////


void avoid()

{

  PingRead1R();

  Serial.println(distinch1);

  PingRead2L();

  Serial.print (distinch2); 

  if (distinch1 < 40)

    {

    brake();

    delay (500);

    right();

    delay (500);

    } 

  if (distinch2 < 40)

    {

    brake();

    delay (500);

    right();

    delay (500);

    } 

  if (distinch1 && distinch2 < 25)

  {

     brake();

     delay (500);

     backward();    

     delay (500);

     interupt();

   if (distinch1 < distinch2)

     {

       right();

       delay (500);

     }

   else

     {

       left();

       delay (500);

     } 

   }

}


void interupt()

{

  state = !state;

  brake();

  delay (500);

  forward();

  delay (500);

}



/////////////////////////////////////////////////////

///////            ultrasonics             //////////

/////////////////////////////////////////////////////

void PingRead1R() 

  {

  digitalWrite(trig1R, HIGH);

  delay(15);

  digitalWrite(trig1R, LOW);

  duration1R = pulseIn(echo1R, HIGH);

  distcm1 = duration1R / 58;  // time to centimetres

  distinch1 = duration1R / 148; // time to inches

  Serial.print("Distance in cm = ");

  Serial.print(distcm1);

  Serial.print("   Distance in inches = ");

  Serial.println(distinch1);

  delay(100);

  }


void PingRead2L() 

  {

  digitalWrite(trig2L, HIGH);

  delay(15);

  digitalWrite(trig2L, LOW);

  duration2L = pulseIn(echo2L, HIGH);

  distcm2 = duration2L / 58;  // time to centimetres

  distinch2 = duration2L / 148; // time to inches

  Serial.print("Distance in cm = ");

  Serial.print(distcm2);

  Serial.print("   Distance in inches = ");

  Serial.println(distinch2);

  delay(100);

  }

</source>


== Video of the Robot ==


[https://www.youtube.com/watch?v=DQAOvshY_AA Object Avoidance]


[https://www.youtube.com/watch?v=pUuTLz3jpbQ Claw Motion]


[https://www.youtube.com/watch?v=tcmXZ9ycbg8 Restricted movement of the claw]


[https://www.youtube.com/watch?v=Gckphux0v3Q Pixy Running off Arduino to a programmed object]


[https://www.youtube.com/watch?v=4ufpIPY5BAk Pixy guiding motor movement (Left/Right/Forward) based on the position of the block]


== Photos of the Robot ==


[[File:Initial Base.jpg|300px]][[File:InitialBase2.jpg|300px]][[File:FirstClaw.jpg|300px]] [[File:Claw andPixycam.jpg|400px]][[File:Troubleshooting Ultrasonic.jpg|200px]][[File:NewClaw.jpg|400px]]


[[File:Final1.jpg|400px]][[File:Final2.jpg|400px]] [[File:Final3.jpg|500px]]

Ad blocker interference detected!


Wikia is a free-to-use site that makes money from advertising. We have a modified experience for viewers using ad blockers

Wikia is not accessible if you’ve made further modifications. Remove the custom ad blocker rule(s) and the page will load as expected.