Robot Assembly

 

How to Build Robot

Let’s look at how to build robot, first I gathered all the pieces and just kind of loosely placed them on the chassis to get a rough idea of how they would fit. I placed the four AA batteries in the middle because they are the heaviest element, we want the heaviest thing over the center of gravity, and thus the robot will be stable and not want to tip over. Learn powerful info on how to build ┬árobot.

The receiver for the IR remote has also been connected. There are 3 wires that need to be connected, PWR, which is connected to 5V on the Arduino, GND which is connected to GND on the Arduino, and IN, which is connected to port 11 on the Arduino.

 


 

We won’t need too much of the breadboard just enough to hold the ultrasonic sensor so we can later put the 9 V battery on top of it. The breadboard that I ordered came with some sticky tape on the back the which is actually quite strong and holds very well even against wood, which is not usually a very good material for adhering to with tape. Peel the paper off to reveal the sticky part.

 

 

Then place the breadboard as close to the front of the robot as you can.

 

 

This is the box of Velcro that I use. This Velcro is nice because it comes in a long strip and you actually get quite a lot for the money compared with buying little packages. You can cut this Velcro with a pair of scissors, or a sharp utility knife.

 

 


The backside of the Arduino Uno has all the solder connections exposed it’s possible that some of these can get shorted if you laid it on top of something that was metal, its mostly plastic on top of our gearbox, but just to be sure I took the small piece of foam that came with the Arduino and mounted it on top of the foam with some little screws, but you can use just about anything else like tape or some hot melt glue if you don’t have screws. I then put the Arduino with the motor shield attached on top of the motor gearbox and fastened this down with some Velcro. Here is a view from the back of the robot you can see the small strip of Velcro and foam that the Arduino and motor shield are mounted to.

 

 

I went ahead and placed the ultrasonic sensor on the breadboard even though we haven’t yet got to programming it. We just need to get a sense of how much space it takes up, we want to leave the first two or three rows of the breadboard accessible after the ultrasonic sensor for wires to plug-in to, there is a total of 3 wires that will need to be connected to the ultrasonic sensor when we get to it.

I made sure to cut the wires connected to the motor a little bit long so that I can trim them here. I cut them close so there’s not a lot of slack wire laying around.

 

 

Here you see the motor wires are connected, it matters which wire you hook up to to the individual A and B terminals on the motor shield (because of motor direction), but we can also tweak this later in software so I didn’t worry about it too much now.

 

 

I also used Velcro to attach the battery holder for the four AA batteries. I put on a piece of Velcro which was a little too wide then used a hobby knife to trim it. Velcro is particularly useful here because when we want to remove the battery pack we can just remove it and not have to worry about scraping off tape or glue.

 

 

I also attached the 9V battery and connector using some Velcro, there was just enough room left on the breadboard to be able to get the 3 wires that we will need to hook up the ultrasonic sensor.

 

 

Lastly we need to figure out a way to attach the infrared receiver, there was not a real obvious way to do this so I end up using a small piece of Velcro and just attaching it to the back one of the plastic connectors on the motor shield.

 

 

Also for the infrared receiver, the part that does the receiving is only on one side of the device, but if the robot is making a turn, this could end up putting the backside of the receiver towards us and it would not receive the signal from the remote. To fix this I took the receiver and bent it so that the portion that actually receives the IR signal is pointed up. Since I’ll mostly be standing when I’m controlling the robot and I’m pointing the remote downward, this turned out to work quite well, and had a surprisingly good range as long as you don’t go behind an object which would block the infrared signal.

 

 

Lastly I took the wires and bent them around in a manner so they wouldn’t get hung up on the tracks or snagged on something else. In this picture, everything is connected except the ultrasonic sensor.

 

 

With the robot assembled, we are ready to write a bit more sophisticated code to actually be able to control the robot using the remote. We will get it working with the remote, then add the ultrasonic sensor as an enhancement.

First lets write a short program just to establish communication with the robot. This program will start one track in motion when a button on the remote is pressed.

#include <IRremote.h>

// variables for IR remote
int RECV_PIN = 4;
IRrecv irrecv(RECV_PIN);
decode_results results;

// hex code assigned to a button
const long prev_button = 0xFD20DF; 

void setup()
{
  Serial.begin(9600);
  irrecv.enableIRIn(); // Start the receiver

  //motor setup
  pinMode(12, OUTPUT); //Initiates Motor Channel A pin
  pinMode(9, OUTPUT); //Initiates Brake Channel A pin
}

void loop() {
  if (irrecv.decode(&results)) {   // results is an instance of a decode_results class, decode() returns an int
    //Serial.println(results.value, HEX);
    if(results.value == prev_button)
      {
        //Serial.println("in loop");
        // move motor forward
        digitalWrite(12, HIGH); // Establishes forward direction of Channel A
        digitalWrite(9, LOW);   // Disengage the Brake for Channel A
        analogWrite(3, 255);    // Spins the motor on Channel 
        delay(2000);
      }

    irrecv.resume(); // Receive the next value
  }
}

Pressing the previous button on the remote, should start the left track in motion.

Not much of that code should seem new. The code for infrared remote is very similar to what we have already seen, only here we check if it matches the hex code for the prev_button, and if it does than we start the motor on channel A, which is the left track. Its good to start with a program like this that is as short and simple as possible, yet connects all the individual components together. This program pretty much covers every element that we will need to program our robot for moving about. Lets move on to writing a more sophisticated program, and then we’ll discuss some of the code in greater detail.

How to Build Robot – Writing a Program to Control a two tracked robot

There are a few different ways we can write a program to control a two tracked robot. The way that I ended up doing it was to write a robot class, this class will keep track of the state tracky is in. There are several different ways that we could implement the capability to turn, one way would be simply to stop one of the tracks and keep the other one going, or you could change the speed of one track which would also cause the robot to turn, but I also wanted the robot to be able to spin in place, that is if we send the command to turn left while tracky is not moving the robot should spin in place. I think things are a little bit simpler overall if we implement turns not by changing the speed of the track, but by changing the direction of the track, for example to turn left we would have the left track move backwards in the right track move forwards this would be spinning left. This also means that we only need to worry about two speeds, zero, and MAX_SPEED. We can come back later and try to make a more sophisticated turning mechanism. Here is the code that provides for controlling the Robot using 5 buttons. ( forward, backward, stop, turn left, turn right ).

// adds second motor and 2 button control
#include <IRremote.h>

// pin assignments
const int RECV_PIN = 4;
const int directionPinA = 12;
const int directionPinB = 13;
const int motorPinA = 3;
const int motorPinB = 11;
const int brakePinA = 9;
const int brakePinB = 8;

// hex code assigned to a button press
const long forward_button = 0xFD807F;  // uses 'VOL+' button 
const long stop_button = 0xFDA05F;     // uses 'Play' button
const long reverse_button = 0xFD906F;  // uses 'VOL-' button
const long left_button = 0xFD20DF;     // uses 'prev' button
const long right_button = 0xFD609F;    // uses 'next' button
const long repeat = 0xFFFFFFFF;

// global vars
const int AFORWARD = LOW;
const int BFORWARD = HIGH;
IRrecv irrecv(RECV_PIN);
decode_results results;
long current_command = 0;
long previous_command = 0;

// speed is used globally for motion and steering
const int MAX_SPEED = 255; // use speed 255  

// main class to represent our robot
class Robot
{
  private:
    int _lts; // left track speed
    int _rts; // right track speed 
    int _ltd; // left track direction
    int _rtd; // right track direction
    void drive(int lts, int rts, int ltd, int rtd);

  public:
    Robot(int lts, int rts, int ltd, int rtd);
    void Stop(); // engage both brakes    
    void DriveForward(); // both forward 
    void DriveBackward(); // both backward 
    void TurnLeft(); // opposite directions 
    void TurnRight(); // opposite directions
};

// create a new robot
Robot tracky(0, 0, AFORWARD, BFORWARD); // our robot is named tracky

void setup()
{  
  Serial.begin(9600);
  irrecv.enableIRIn(); // Start the receiver

  // setup channels A
  pinMode(motorPinA, OUTPUT); //Initiates Motor Channel A pin
  pinMode(brakePinA, OUTPUT); //Initiates Brake Channel A pin

  // setup Channel B
  pinMode(motorPinB, OUTPUT); //Initiates Motor Channel B pin
  pinMode(brakePinB, OUTPUT);  //Initiates Brake Channel B pin

  digitalWrite(brakePinA, LOW);   // disengage the Brake for channel A
  digitalWrite(brakePinB, LOW);   // disengage the brake for channel B
}

void loop() 
{  
  if (irrecv.decode(&results)) {   // results is an instance of a decode_results class, decode() returns an int
    Serial.println(results.value, HEX);

    if( results.value == repeat )
     {
       current_command = previous_command;
     }
    else
     {
       current_command = results.value;
       previous_command = current_command;
     }

    // channel A is the left motor as viewed from a "driver" viewpoint"
    // channel B is the right motor as viewed from a "driver" viewpoint"  
    switch (current_command) 
      {
       //Serial.println("in switch statement");
       case forward_button:
            tracky.DriveForward();
            break;
       case stop_button: 
            tracky.Stop();
            break;
       case reverse_button:
            tracky.DriveBackward();
            break;
       case left_button:
            tracky.TurnLeft();
            break;
       case right_button:
            tracky.TurnRight(); 
            break;
      }   
     irrecv.resume(); // Receive the next value
  }
}

Robot::Robot(int lts, int rts, int ltd, int rtd)
{
  _lts = lts;
  _rts = rts;
  _ltd = ltd;
  _rtd = rtd;
}

void Robot::drive(int lts, int rts, int ltd, int rtd)
{
  //Serial.println(lts);
  digitalWrite(directionPinA, ltd); // Establishes direction of Channel A
  analogWrite(motorPinA, lts);    // Spins the motor on Channel A

  //Serial.println(rts);
  digitalWrite(directionPinB, rtd); // Establishes direction of Channel B
  analogWrite(motorPinB, rts);   // Spins the motor on Channel B at full speed 
}

void Robot::Stop()
{
  //Serial.println("Stop");
  _lts = 0;
  _rts = 0;
  drive(_lts, _rts, _ltd, _rtd);
}    

void Robot::DriveForward()
{
  //Serial.println("Forward");
  _lts = MAX_SPEED;
  _rts = MAX_SPEED;
  _ltd = AFORWARD;
  _rtd = BFORWARD;
  drive(_lts, _rts, _ltd, _rtd);
}

void Robot::DriveBackward()
{
  //Serial.println("Backwards");
  _lts = MAX_SPEED;
  _rts = MAX_SPEED;
  _ltd = !AFORWARD;
  _rtd = !BFORWARD;
  drive(_lts, _rts, _ltd, _rtd);
}

void Robot::TurnLeft()
{
  //Serial.println("Turn Left");
  Serial.println(_lts);
  Serial.println(_rts);
  // the robot does not have to be moving to turn, we will spin in place
  drive(MAX_SPEED, MAX_SPEED, !AFORWARD, BFORWARD); // drive the left track in the opposite direction  
  delay(500);
  drive(_lts, _rts, _ltd, _rtd); // resume whatever we were doing when this function was called
 }

void Robot::TurnRight()
{
  //Serial.println("Turn Right");
  // the robot does not have to be moving to turn, we will spin in place
  drive(MAX_SPEED, MAX_SPEED, AFORWARD, !BFORWARD); // drive the left track in the opposite direction  
  delay(500);
  drive(_lts, _rts, _ltd, _rtd); // resume whatever we were doing when this function was called
}

 

Lets take a closer look at this program.

The only library that we need to include is the remote control library like we did in the IR remote section.

#include <IRremote.h>

How to Build Robot if you’re new to Programming…

If you’re new to programming one thing you’ll hear about before long is being advised against using global variables, this is usually good advice and by using a class here were actually avoiding the use of a lot of global variables and the problems that can come with them, ( i.e. making variables like _lts global instead of a being a member of a class) that said there are still very good uses for global variables. Things like port assignments and hex codes that are associated with a remote control button should be declared as global variables as they won’t change throughout execution of the program, note the hex codes that we use are not int, but rather long, storing these codes actually requires a data type that is larger than a normal integer type. We assign variables to all the needed Arduino ports, and then the hex codes that represent remote control button presses.

// pin assignments
const int RECV_PIN = 4;
const int directionPinA = 12;
const int directionPinB = 13;
const int motorPinA = 3;
const int motorPinB = 11;
const int brakePinA = 9;
const int brakePinB = 8;

// hex code assigned to a button press
const long forward_button = 0xFF629D;  // uses 'VOL+' button 
const long stop_button = 0xFF02FD;     // uses 'Play' button
const long reverse_button = 0xFFA857;  // uses 'Vol-' button
const long left_button = 0xFF22DD;     // uses 'prev' button
const long right_button = 0xFFC23D;    // uses 'next' button
const long repeat = 0xFFFFFFFF;

You’ll notice most of the code that handles the infrared remote portion of the program is identical to what we did earlier, just pasted in here. There’s also a global variable to hold MAX_SPEED which is set to 255, I’m using the highest gear ratio, and with this robot’s overall speed is not very fast. So I have MAX_SPEED set to be 255, and then provide the ability to turn simply by changing direction of the tracks.

const int MAX_SPEED = 255; // use speed 255  

Remember back we were hooking up the wires to the motors and I said that how you hook up the wires was important, but we can tweak it in software? That’s being done here with the variables AFORWARD and BFORWARD. If one of your tracks is spinning in the wrong direction, you only need to change the value saved for AFORWARD or BFORWARD.

const int AFORWARD = LOW;
const int BFORWARD = HIGH;

I decided not to use the brakes with this program, I think it keeps things simpler. In the the setup() function we will disengage the brakes as soon as the program starts, then we’ll just use the speed to control when the robot stops by setting it to zero.

 digitalWrite(brakePinA, LOW);   // disengage the Brake for channel A
 digitalWrite(brakePinB, LOW);   // disengage the brake for channel B

}

Also in the setup() function, we need to set up all of our various pins as inputs or outputs, enable the infrared remote, and setup the Serial Monitor.

  Serial.begin(9600);
  irrecv.enableIRIn(); // Start the receiver

  // setup channels A
  pinMode(motorPinA, OUTPUT); //Initiates Motor Channel A pin
  pinMode(brakePinA, OUTPUT); //Initiates Brake Channel A pin

  // setup Channel B
  pinMode(motorPinB, OUTPUT); //Initiates Motor Channel B pin

There are five public functions stop(), driveForward(), driveBackward(), turnLeft(), and turnRight(). These are the primary functions that we will call from the main loop, to control the robot.

    public:
      Robot(int lts, int rts, int ltd, int rtd);
      void Stop(); // engage both brakes    
      void DriveForward(); // both forward 
      void DriveBackward(); // both backward 
      void TurnLeft(); // opposite directions 
      void TurnRight(); // opposite directions

The robot has four private variables which represent the left track speed, right track speed, left track direction, right track direction and one private function drive(). It is these four variables that maintain the Robots ‘state’. Since they are private, you can only use them from within functions that belong to the Robot class (e.g. Robot::DriveForward() ).

    private:
      int _lts; // left track speed
      int _rts; // right track speed 
      int _ltd; // left track direction
      int _rtd; // right track direction
      void drive(int lts, int rts, int ltd, int rtd);

drive() is a low-level function that is called by the other public functions. It actually sets the track directions, and commands the motors to turn.

The other public function is the constructor, which initializes the four private variables. We create a new robot object just before calling the setup() function, initializing both speeds to zero, this is done so tracky doesn’t take off as soon as we power him up.

// create a new robot
Robot tracky(0, 0, AFORWARD, BFORWARD); // our robot is named tracky

In the loop function we are reusing some of the code from the IR remote section. There are a couple new variables however, current command and previous command, these are used because our remote puts out a repeat code of FFFFFF instead of actually repeating the hex code for the button we pressed. What we need to do is save the current command to the previous command variable every time a button is pressed. Then we need to check if the repeat code is given, and if so, use the previous command.

void loop() 
{  
  if (irrecv.decode(&results)) {   // results is an instance of a decode_results class, decode() returns an int
    Serial.println(results.value, HEX);

    if( results.value == repeat )
     {
       current_command = previous_command;
     }
    else
     {
       current_command = results.value;
       previous_command = current_command;
     }

After setting the value for current command correctly we have a switch statement that checks which button has been pressed, and then calls the function that corresponds to that button.

switch (current_command) 
      {
       //Serial.println("in switch statement");
       case forward_button:
            tracky.DriveForward();
            break;
       case stop_button: 
            tracky.Stop();
            break;
       case reverse_button:
            tracky.DriveBackward();
            break;
       case left_button:
            tracky.TurnLeft();
            break;
       case right_button:
            tracky.TurnRight(); 
            break;
      }

Here is video of tracky driving about, being controlled by remote.

Next lets try and give tracky a little intelligence of his own! Easy How to build Robot tutorial!

Intro->SOS->Chassis Assembly->Motors & Drive-train->Arduino-Remote Control->Assembly->Ultrasonic Sensor->Final Testing

 

 Posted by at 3:51 pm

  5 Responses to “Robot Assembly”

  1. Could you make a tutorial for this robot but instead of using motor shield,could you use motor driver controler??If you can,send me instructions to my email,please!!!

  2. Thank you for this tutorial. It made me understand this IR trickery and finally got it to work!

 Leave a Reply

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

(required)

(required)


Time limit is exhausted. Please reload CAPTCHA.