Engineering

Outreach

Resources

Enrichment

Green Engineers

Mechatronics Studio

Contact Us

Mechatronics Learning Studio

 

Mo The Robot

 

Chris Falconi, Jon Gilchrist, Ryan Jordan, Mechanical Engineering, University of Ottawa

 

 

 

 

 

Introduction

 

The goal of this project was to produce an electromechanical robot that could be either controlled by a user or identify and follow a line while clearing any objects encountered on it’s path. This robot has been given the name Mo. The robot features an onboard Arduino microcontroller for autonomous operation, and also features a remote control for manual control. As a method of locomotion, Mo uses an eight-legged design based on a Theo Jansen mechanism. This type of mechanism is ideal for converting a rotational movement, such as that produced by the motor, into a walking or crawling motion. Mo’s movement can be controlled by the microcontroller in order to follow a line on the floor that is located using infrared reflectance sensors, or a user can manually control it via the remote control. To provide a means of clearing a path in front of the robot, Mo has been equipped with a robotic arm. The arm can be controlled by the microcontroller in order to sweep objects out of the way, or can be controlled by a user for more precise and responsive control. An ultrasonic proximity sensor is used to detect when objects are in the path of the robot, which will cause Mo to stop and attempt to remove the object from its path.

 

Materials and Tools

 

Electronics Materials

 

Mechanical Materials

 

·         Arduino Uno Microcontroller

·         2 High-Torque Brushed DC Motors

·         7 Servomotors

·         2 TIP121 Transistors

·         Various Resistors

·         Various Rectifier Diodes

·         One Solderless Breadboard

·         Multiple Solder-On Circuit Boards

·         Batteries: 2x 9V, 1x 7.2V, 1x 6V

·         Various Coloured LEDs

·         2 Dual-Axis Joysticks

·         Multiple Toggle and Momentary Switches

·         Potentiometer

·         Piezo-Electric Buzzer

·         PING Ultrasonic Proximity Sensor

·         3 Infrared Reflectance Sensors

·         2 Computer Fans

·         Heat Shrink

 

·         Acrylic Sheets

·         Aluminum Bars

·         Various Fasteners

·         High Strength Epoxy, Super Glue, Acrylic Solvent Cement

·         Brass and Aluminum Tubing and Rods

·         Copper Plate

·         Double Sided Foam Tape

·         Adhesive Velcro

 

Tools Used

 

·         Scroll Saw

·         Drill and Drill Press

·         Soldering Iron

·         Screw Drivers

·         Files

·         Bench Grinder

 

 

 

Drive System

 

The drive system of the robot features a Theo Jansen mechanism incorporated into four sets of legs. Each set of the leg has two feet and two shoulders, which are constructed of acrylic sheets that have been cut by hand on a scroll saw. These pieces are connected by aluminum bars, which have been cut and drilled to suit their respective dimensions. These elements are held together using nuts and bolts, and are then connected to a crankshaft. The crankshaft was built using aluminum bars which have been cut and drilled to act as cams, these cams are connected by aluminum rods in order to form a full shaft. The use of cams on the crankshaft allows the rotational motion of the motor to be converted to a stepping motion. The crankshaft is then connected to the gearbox, which has been hand built in order to provide a high torque ratio. A high torque ensures smooth operation of the legs, while maintaining a desirable speed well suited to the Theo Jansen mechanism.

 

Two high-torque motors originally designed for use in off-road remote control vehicles provide the power of the drive system. These motors run on a voltage of 7.2 volts, supplied by the robot’s main battery.  When operating in an autonomous mode, the motors are controlled by the microcontroller via a transistor array. The microcontroller uses sensor data to determine which motor(s) should be operating and sends a digital signal to the transistors. Depending on the signal received, the transistors then allow current to pass or not. When operating from the remote control, the user will use toggle switches to control the directions of the motors and momentary switches to control whether the motors are on or off.

 

Robot Frame/Body

 

The frame of the robot, like the legs, has been cut from sheets of acrylic and is reinforced with aluminum to provide the desired rigidity. Acrylic sheets provide a central platform on which the robot’s electronics are placed, as well as anchor points below for the gearbox, motors, sensors and legs. Brass rods that connect at the stationary points of the mechanism act as pins and support the legs.

 

Arm System

 

Once more, the central frame of the robotic arm is constructed from acrylic sheets that have been hand cut to their proper shapes. The arm has a total of 6 degrees of freedom and is controlled by a total of 7 servomotors. The servomotors are driven by a 6-volt power source, provided by a secondary battery.  Each servo is individually controlled by an output on the microcontroller, which uses pulse width modulation to send a signal pulse to each servo. The servo is able to read the length of the pulse, which corresponds to an angular position, and proceeds to and maintains the desired position. When controlled by a user, the desired position is determined using joysticks of the remote control. The joysticks consist of two potentiometers each, which vary the resistance when they are moved along the axes. The resistances of the potentiometers can be read by the microcontroller in order to determine the desired position. In the autonomous mode, the arm is programmed to perform a “sweep” movement, which is controlled by a pre-set algorithm contained in the code.

 

Electronics and Control Systems

 

The principal purpose of the electronics system of the robot is control the drive and arm systems. This is performed through the use of the 3 infrared reflectance sensors, the proximity sensor, the microcontroller and other components as outlined above. There also exists a secondary electronic circuit, which is used to control the auxiliary systems of the robot. These systems include lighting, cooling, and the use of a buzzer.

 

The lighting system consists of various general Light Emitting Diodes, which are primarily decorative, as well as two high-brightness diodes, which act as flood lights and illuminate a path in front of the robot. The lighting system is powered by a 9V battery, and uses resistors to supply an appropriate voltage to each sub-circuit. The sub-circuits are wired in parallel, in order to provide the same voltage to all elements. Through the use of toggle switches on the remote control, the user can control the lighting system.

 

The cooling system consists of two computer fans mounted on top of a copper plate heatsink that is connected to the transistors. As a result of the high torque, the motors draw high amounts of current that can cause the transistors to overheat. By mounting them in a cooling system, safe levels can be maintained for the components. The cooling system is wired in parallel with the lighting system and is controlled by toggles on the remote control.

 

As an additional feature, the robot is equipped with a piezo-electric buzzer that the user can control from the remote control. The buzzer is connected in series to a potentiometer, which allows the volume of the buzzer to be adjusted. The buzzer circuit is also wired in parallel to the lighting and cooling circuits.

 

Additional Information

 

As a result of the excess heat produced by the transistors, one of the components had been damaged before the cooling system was implemented. As a result only one transistor is available to be used at present. As a result, the programming has been modified to utilize the remaining transistor as a signaling system, which will illuminate LEDs on each side of the robot when a line is being successfully followed, and will turn the LEDs off when the line is not being followed. The LEDs will also flash rapidly when an object is detected in front of the robot. The robot will regain full functionality upon replacement of the damaged transistor.

 

It should also be noted that one of the servos used in the arm is non-operational at the moment, which limits the arm to 5 degrees of freedom. Further information and a demonstration of the robot in action can be seen at the link.

http://www.youtube.com/watch?v=eVrOko1YKs8&feature=plcp

 

 Code

 

The microcontroller code has been placed below for your information.


 

#define rmotorPin 8

#define lmotorPin 12

#define rline 2    //blue

#define cline 4    //red

#define lline 7    //grey

#define ping 11

#include <Servo.h>

int mover = 0;

int movel = 0;

int movec = 0;

long result = 0;

int pingstore = 0;

Servo elbow;  // create servo object to control a servo

Servo wrist;

Servo claw;

Servo base;

int potpin0 = 0;  // analog pin used to connect the potentiometer

int val0;    // variable to read the value from the analog pin

int pos0 = 90;

int potpin1 = 1;  // analog pin used to connect the potentiometer

int val1;    // variable to read the value from the analog pin

int pos1 = 90;

int potpin2 = 2;  // analog pin used to connect the potentiometer

int val2;    // variable to read the value from the analog pin

int pos2 = 90;

int potpin3 = 3;  // analog pin used to connect the potentiometer

int val3;    // variable to read the value from the analog pin

int pos3 = 90;

void setup(){

  pinMode(rmotorPin, OUTPUT);

  pinMode(lmotorPin, OUTPUT);

  pinMode(rline, INPUT);

  pinMode(cline, INPUT);

  pinMode(lline, INPUT);

 elbow.attach(3);  // attaches the servo on pin 3 to the servo object

 wrist.attach(5);

 claw.attach(6);

 base.attach(9);

   Serial.begin(9600);

   Serial.println("start");      // a personal quirk

}

void loop(){

   Serial.println("loop");      // a personal quirk

   //ELBOW START

   val0 = analogRead(potpin0);            //*******servo******* reads the value of the potentiometer (value between 0 and 1023)

  val0 = map(val0, 0, 1023, 0, 179);  // scale it to use it with the servo (value between 0 and 180)

  Serial.println("---ELBOW----");

  Serial.println(val0);

  Serial.println(pos0);

  Serial.println("------");

  if (val0<=85){

    if(pos0>=90 || pos0>=val0){

  elbow.write(val0);   // sets the servo position according to the scaled value

  pos0 = val0;

  Serial.println("moving elbow up");

  delay(10);                           // waits for the servo to get there

}}

 if (val0>=95){

    if(pos0<=90 || pos0<=val0){

  elbow.write(val0);   // sets the servo position according to the scaled value

  pos0 = val0;

  Serial.println("moving elbow down");

  delay(10);                           // waits for the servo to get there

}

}  //***********END ELBOW******

//Wrist Start

val1 = analogRead(potpin1);            //*******servo******* reads the value of the potentiometer (value between 0 and 1023)

  val1 = map(val1, 0, 1023, 0, 179);  // scale it to use it with the servo (value between 0 and 180)

  Serial.println("----Wrist---");

  Serial.println(val1);

  Serial.println(pos1);

  Serial.println("------");

  if (val1<=85){

    if(pos1>=90 || pos1>=val1){

  wrist.write(val1);   // sets the servo position according to the scaled value

  pos1 = val1;

  Serial.println("moving wrist up");

  delay(10);                           // waits for the servo to get there

}}

 if (val1>=95){

    if(pos1<=90 || pos1<=val1){

  wrist.write(val1);   // sets the servo position according to the scaled value

  pos1 = val1;

  Serial.println("moving wrist down");

 

  delay(10);                           // waits for the servo to get there

}

}  //***********END Wrist*******

   //Base Start

   val2 = analogRead(potpin2);            //*******servo******* reads the value of the potentiometer (value between 0 and 1023)

  val2 = map(val2, 0, 1023, 0, 179);  // scale it to use it with the servo (value between 0 and 180)

  Serial.println("----BASE---");

  Serial.println(val2);

  Serial.println(pos2);

  Serial.println("------");

  if (val2<=85){

    if(pos2>=90 || pos2>=val2){

  base.write(val2);   // sets the servo position according to the scaled value

  pos2 = val2;

  Serial.println("moving base up");

  delay(10);                           // waits for the servo to get there

}}

 if (val2>=95){

    if(pos2<=90 || pos2<=val2){

  base.write(val2);   // sets the servo position according to the scaled value

  pos2 = val2;

  Serial.println("moving base down");

  delay(10);                           // waits for the servo to get there

}

}  //***********END BASE*******

   //CLAW START

   val3 = analogRead(potpin3);            //*******servo******* reads the value of the potentiometer (value between 0 and 1023)

  val3 = map(val3, 0, 1023, 0, 100);  // scale it to use it with the servo (value between 0 and 180)

  Serial.println("---CLAW---");

  Serial.println(val3);

  Serial.println(pos3);

  Serial.println("------");

  if (val3<=43){

    if(pos3>=45 || pos3>=val3){

  claw.write(val3);   // sets the servo position according to the scaled value

  pos3 = val3;

  Serial.println("moving claw up");

  delay(10);                           // waits for the servo to get there

}}

 if (val3>=46){

    if(pos3<=54 || pos3<=val3){

  claw.write(val3);   // sets the servo position according to the scaled value

  pos3 = val3;

  Serial.println("moving claw down");

 

  delay(10);                           // waits for the servo to get there

}

}  //***********END CLAW*******

delay(10);

  mover= RCtime(rline);

        Serial.println("Right");

        Serial.println(mover);

  movel= RCtime(lline);

        Serial.println("LEFT");

        Serial.println(movel);

  movec=RCtime(cline);

        Serial.println("center");

        Serial.println(movec);

  if (movec<mover && movec<movel){

    stopmotors();

    bmotor();

    Serial.println("running both motors");

    delay(10);

  }

if (mover<movec && mover<movel){

     stopmotors();

    rmotor();

    Serial.println("running left motor");

    delay(10);

  }

if (movel<mover && movel<movec){

     stopmotors();

    rmotor();

    Serial.println("running right motor");

    delay(10);

  }

pingstore = PING();

   Serial.println("PING Reading");

   Serial.println(pingstore);

   if(pingstore < 12){

     //Run arm program

     stopmotors();

     Serial.println("Run the arm");

     delay(50);

   }

}

void rmotor() {

  digitalWrite(rmotorPin, HIGH);

  delay(10);

}

void stopmotors(){

  digitalWrite(rmotorPin,LOW);

  digitalWrite(lmotorPin,LOW);

}

 

void rturn() {

  digitalWrite(lmotorPin, HIGH);

  delay(20);

}

void lmotor() {

  digitalWrite(lmotorPin, HIGH);

  delay(10);

}

void bmotor() {

  digitalWrite(rmotorPin, HIGH);

  digitalWrite(lmotorPin, HIGH);

  delay(10);

}

long RCtime(int sensPin){

   long result = 0;

   pinMode(sensPin, OUTPUT);       // make pin OUTPUT

   digitalWrite(sensPin, HIGH);    // make pin HIGH to discharge capacitor - study the schematic

   delay(10);                       // wait a  ms to make sure cap is discharged

 

   pinMode(sensPin, INPUT);        // turn pin into an input and time till pin goes low

   digitalWrite(sensPin, LOW);     // turn pullups off - or it won't work

   while(digitalRead(sensPin)){    // wait for pin to go low

      result++;

   }

   return result;                   // report results  

}  

  long PING(){

  long duration, inches, cm;

  pinMode(ping, OUTPUT);

  digitalWrite(ping, LOW);

  delayMicroseconds(2);

  digitalWrite(ping, HIGH);

  delayMicroseconds(10);

  digitalWrite(ping, LOW);

  pinMode(ping, INPUT);

  duration = pulseIn(ping, HIGH);

  // convert the time into a distance

  inches = microsecondsToInches(duration);

  cm = microsecondsToCentimeters(duration); //use cm for distance

  delay(10);

  return cm;

}

long microsecondsToInches(long microseconds)

{

  return microseconds / 74 / 2;

}

long microsecondsToCentimeters(long microseconds)

{

  return microseconds / 29 / 2;

}