Problem/Finish Description

edit
  1. Get all 5 tribots running
  2. Begin programming tribots to go in a patterns like squares, circles
  3. Add remote emergency take over capability
  4. Add automous ability to travel the cooridors of first floor Clark Library Building
  5. Add features from the head
  6. Replace arduino with papilio
  7. Pull all existing documentation into one place in the below context

Conceive

edit

Project was inspired by this video that shows a robot balanced on top of a basketball. A completely powered Omni wheel connected to some accelerometer/gryo can create a powered unicycle that moves sideways. This is completely different than the one wheel motor cycle, the monocycle or the R.O.I.T wheel.

The goal is to duplicate the robot balanced on top of a basketball and ultimately duplicate the powered unicycle.

Hack a Toy

The idea was to start with hacking a toy. Here is an example hack:

Tribot

The WowWee Tribot seemed a very close match to the robot balanced on a basketball.

WowWee Tribots retail anywhere from $300 and below here The robot is officially called the "WowWee Tribot Talking Companion." There is a Wowwee Mini Tri-bot that retails for around $21 that should not be confused with the bigger brother. Online it is hard to tell them apart. The Mini Tri-bot does not ship with universal or Omni wheels.

Design

edit

Reverse engineering a toy is similar to forward design. It starts with re-creating the implmentation/operation documentation that already exists.

Original Tribot Features

The original Tribot has sophisticated hardware, but the software was primitive. The first step was to remove the logic board and replace with aruduino. The manual describes the software features that will be lost:

  • store one program (pattern of movement) at a time
  • can only program with direction buttons, can not spin in a spot
  • IR collision avoidance, intruder detection
  • Primitive alarm clock .. like that found on a stove
  • Permanent patterns that have to be repeated manually
Major Hardware Systems to be connected to Arduino
 
What is connected as of 3/12/14 .. encoders are not working

These are the major hardware systems within the Tribot that needed to be connected to the Arduino:

  • batteries
  • motors
  • head
  • encoders (counts motor/wheel revolutions and direction of rotation)
  • IR reflection sensors
  • Remote Controller (including tilt sensor in remote)
  • speaker

The current base is too low to the ground to work on top of a basketball. So the base needs to be redesigned.

New Base Design

Drew using 3DTin following these tutorials.

Red base The red base is the original tribot base. The wheel "stems" are parallel to the ground. This current base does not allow the Tribot to sit and roll atop of a basketball.

Green base The green base is a new idea for Tribot. The wheel stems would be tilted at an angle so that it would be easier to fit on a ball. This requires almost creating a new base.

Blue base The blue base is another idea. Its a conical base. A hollow cone would allow it to perfectly sit on a basketball I think. Additionally, the wheel stems would have to be recreated similar to the idea in the green base. They would also have to be slanted at an angle.

Yellow base The yellow base is the last idea I had. The yellow base is using the original base but adding extensions to the ends. It would be adding the extensions at an angle.

NEW BASE Started by testing with one 45° elbow shaped 1 1/2" pvc pipe. The motor fit inside perfectly. But wheel could not attach to the motor normally. Had to do some sanding. Video of the result. May have to dedicate a robot to the ball. Seems weaker trying to run motor test with the new base video.

Next Step May be able to use PVC pipe to pivot wheels for both ground and ball use.

Implement

edit

These are the steps to take apart a toy Tribot WowWee and add an arduino

Do not remove the wheels
Taking apart the Body

Remove the Arms

The arms are held on by three screws around the arm socket and one screw at the waist. Remove them. The black handle is held on with two screws. Do not remove them. The goal is to keep the arm assembly together as much as possible. There are two screws near the black handle, towards the back near the back IR transmitter and receiver. Remove one of these screws. The split apart the arms. The black handle should hold the shoulders together. There is a white bar that holds the back shoulders together. Replace the last screw removed.

The breast plate is a speaker. There are 3 infared transmitters and 3 receivers. They are used for the "Home" function where the robot follows someone with the remote and are used to avoid collisions. This tutorial does not show how to restore this functionality with the arduino.

Remove Existing Logic Board

Remove Existing Logic Board

Four screws hold on the existing logic board. The Arduino almost fits 2 of the screws. One screw has to be forced in at an angle, the Arduino UNO mounts at two points. The arduino is larger than the original logic board therefore putting the arms back on over the new arduino like they went over the old logic board is not an option.

Hack the Existing Motor Controler
Connecting cables to Arduino

Cable Harness A color code has been developed that maps colors to Arduino pin numbers:

Motor Function Color Arduino Pin
1 yellow on/off 12
2 teal on/off 11
3 blue on/off 10
1 white direction 9
2 gray direction 8
3 purple direction 7
1 orange encoder 6
2 red encoder 5
3 brown encoder 4
head switch white start 3

The power cables are blue and black .. and sometimes a bit thicker:


The head switch needs to be re-attached to the arduino:

Connecting Encoder

Not much work has been done.

This much about the wiring is known:

The arduino encoder web site talks about how it is hard to count these pulses ... all the code is playing with the interrupts of the arduino amtel processor. This means that the code can do nothing else .. and we want the code to turn the motors, look at IR sensors, etc. Probably going to have to build a special circuit to do this out of an FPGA papilio.

Connecting the Head

CircuitBoard in Head Wires:

  • purple is 4V
  • blue is connected to the left eye
  • green is connected to the right eye
  • yellow is connected to the right ear
  • orange is connected to the left ear
  • red is connected to mouth "m"
  • brown is connected to the mouth "r" (right??)

There are 3 wires under a label "HL". HL is headlight. The purple box is where power is connected to.

Video of trying to connect power to the head. It is not straight forward. Need to apply power slowly.

Gyro-Accelerometer

video

The 5DOF The 5DOF is called an "Inertia Measurement Unit" that measures the following:

  • Roll
  • Pitch
  • Position along X-axis
  • Position along Y-axis
  • Position along Z-axis

It has been retired by sparkfun meaning that it can no longer be purchased. But it exists in Fritzing so it is easy to draw a circuit with it.

Connecting to the Arduino Leveraged this example. A breadboard was necessary because the pins don't match the arduino headers. The alternative was to solder. Ths is how it was connected. At first only the accelerometer was connected, then the gyro was added.

IMU Pins Arduino Pins
3.3V 3.3V
Ground Ground
X-Acc A0
Y-Acc A1
Z-Acc A2
X-Rate (formerly Vref) A3
Y-Rate A4
EMPTY (formerly x-rate) A5

The starting point sketch worked except for the "zero-reading." Hypothesis is it varies from unit to unit. The code was modified to take into account the "zero-reading" in the serial output display.

Sketch: Analog Accelerometer with Serial
//Analog Accerometer w Serial
 //by Amanda Ghassaei
 //Modified by Chris Carreras
 //http://www.instructables.com/id/Use-an-Accelerometer-and-Gyroscope-with-Arduino/
 //August 2012
 /*
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 3 of the License, or
  * (at your option) any later version.
  *
 */ 

  //setup accelerometer variables
  int xAcc;
  int yAcc;
  int zAcc;
  int accZero = 322;
  
  //setup gyro variables
  int xRate;
  int yRate;
  //int Vref; This was causing issues
  

 //see the comment below for calculating this with your own     board.
 void setup(){
   Serial.begin(9600);//set up serial
 }
 void loop(){
 
   //read values
   xAcc = analogRead(A0);
   yAcc = analogRead(A1);
   zAcc = analogRead(A2);
   //Vref = analogRead(A3); This was causing issues
   yRate = analogRead(A4);
   xRate = analogRead(A3); //changed this to A3 from A5, was not working when reading from A5
 
   /**
   if you want to determine the zero point value of your board, 
   comment out the last eight lines of this loop and uncomment the lines below.
   Hold the board parallel to the ground and watch the serial monitor, 
   the xAcc and yAcc values will hover around a common value, 
   this is your "zero" value.  Change the value of the variable "zero" above.
   **/
   //print values
   Serial.print("xAcc ");
   Serial.println(xAcc - accZero);
   Serial.print("yAcc ");
   Serial.println(yAcc - accZero);
   Serial.print("zAcc ");
   Serial.println(zAcc - accZero);
   //Serial.print("IGNORE ME");      These two commented out lines are legacy from when I was having issues
   //Serial.println(xRate);          This was trying to read in xRate from A5... was not working at all
   Serial.print("yRate:");
   Serial.println(yRate);
   Serial.print("xRate");           // This was formerly "Vref" but it was causing issues, or possibly pin A5 was causing issues
   Serial.println(xRate);           // This used to print in Vref, but I've made changes since then and now this sketch should work
   Serial.println(" ");
   delay(500);//wait
 }

Results Can see readings changing as it is moved around by hand.

Operate

edit
  1. Find screwdriver that works
  2. Put batteries in (8 AA batteries)
  3. Turn on
  4. Push head down
  5. Turn off
  6. Take batteries out
Creating Program to go in a Square
Starting with the Demo Program
/*
  BallBot Exercise
  This is test code to exercise the WowWee Tri-Bot capabilities
  Have to push down the head to get the robot to move 
  This example code is in the public domain.
 */

// constants won't change. They're used here to 
// set pin numbers:
const int buttonPin = 3;     // the number of the pushbutton pin
const int ledPin =  13;      // the number of the LED pin

// variables will change:
int buttonState = 0;         // variable for reading the pushbutton status
int headPush=0;  //if 0 means execute any instructions and wait, if 1 then do and check if headpushed regularly

void setup() {
  // initialize the digital pin as an output.
  pinMode(12, OUTPUT); //yellow wire to motor enable 1
  pinMode(11, OUTPUT); //teal wire to motor enable 2
  pinMode(10, OUTPUT); //blue wire to motor enable 3
  pinMode(9, OUTPUT); // white wire to motor direction 1
  pinMode(8, OUTPUT); //gray wire to motor direction 2
  pinMode(7, OUTPUT); //purple wire to motor direction 3
  pinMode(6, INPUT); //orange encoder from motor 1
  pinMode(5, INPUT); //red encoder from motor 1
  pinMode(4, INPUT); //brown encoder from motor 1
  pinMode(ledPin, OUTPUT);   // initialize the LED pin as an output:     
  pinMode(buttonPin, INPUT); // initialize the pushbutton pin as an input:    
}

void loop(){
  while (headPush == 0) {
  // wait for head push before starting
     buttonState = digitalRead(buttonPin);
     if (buttonState == HIGH) {     
        // turn LED on:    
        digitalWrite(ledPin, HIGH);  
        headPush = 1;
     }
  } 
//  oneMotorAtATime();
//  spinTightCCW();
  oneMotorAtATime();
  delay(1000);
  spinTightCCW();
  delay(1000);
  spinTightCW();
  delay(1000);
  gradualTurn();
  delay(1000);
  forWard();
  delay(1000);
  backWard();
  delay(1000);
  rightForward();
  delay(1000);
  rightBackward();
  delay(1000);
  headPush=0;  
}

void oneMotorAtATime() {

  //motors turning individually
  delay(1000);              // wait for a second
  digitalWrite(12, HIGH);   // set the LED on
  delay(2000);              // wait for a second
  digitalWrite(12, LOW);    // set the LED off
  delay(2000);              // wait for a second
  digitalWrite(11, HIGH);   // set the LED on
  delay(2000);              // wait for a second
  digitalWrite(11, LOW);    // set the LED off
  delay(2000);              // wait for a second
  digitalWrite(10, HIGH);   // set the LED on
  delay(2000);              // wait for a second
  digitalWrite(10, LOW);    // set the LED off
  headPush=0;
}

void spinTightCCW() {
  delay(1000);
  digitalWrite(9, HIGH);   // reverse motor 1
  digitalWrite(8, HIGH);   // reverse motor 2
  digitalWrite(7, HIGH);   // reverse motor 3
  delay(100);
  digitalWrite(12, HIGH);   // turn motor 1 on 
  digitalWrite(11, HIGH);   // turn motor 1 on
  digitalWrite(10, HIGH);   // turn motor 3 on
  delay(840);
  digitalWrite(12, LOW);   // turn motor 1 off 
  digitalWrite(11, LOW);   // turn motor 2 off
  digitalWrite(10, LOW);   // turn motor 3 off
  digitalWrite(9, LOW);   // normal motor 1
  digitalWrite(8, LOW);   // normal motor 2
  digitalWrite(7, LOW);   // normal motor 3 
  headPush=0;  
}

void spinTightCW() {
  delay(1000);
  digitalWrite(12, HIGH);   // turn motor 1 on 
  digitalWrite(11, HIGH);   // turn motor 1 on
  digitalWrite(10, HIGH);   // turn motor 3 on
  delay(840);
  digitalWrite(12, LOW);   // turn motor 1 off 
  digitalWrite(11, LOW);   // turn motor 2 off
  digitalWrite(10, LOW);   // turn motor 3 off
  headPush=0;  
}


void forWard() {
  delay(1000);
  digitalWrite(12, HIGH);   // turn motor 1 on 
  digitalWrite(8, HIGH);   // reverse direction of motor 2
  digitalWrite(11, HIGH);   // turn motor 2 on
  delay(2000);
  digitalWrite(12, LOW);   // turn motor 1 off
  digitalWrite(8, LOW);   // make direction of motor 2 normal
  digitalWrite(11, LOW);   // turn motor 2 off
  headPush=0;
}

void backWard() {
  delay(1000);
  digitalWrite(9, HIGH);   // reverse direction of motor 1
  digitalWrite(12, HIGH);   // turn motor 1 on   
  digitalWrite(11, HIGH);   // turn motor 2 on
  delay(2000);
  digitalWrite(12, LOW);   // turn motor 1 off
  digitalWrite(9, LOW);   // make direction of motor 2 normal
  digitalWrite(11, LOW);   // turn motor 2 off
  headPush=0;
}

void rightForward() {
  delay(1000);
  digitalWrite(11, HIGH);   // turn motor 1 on 
  digitalWrite(7, HIGH);   // reverse direction of motor 2
  digitalWrite(10, HIGH);   // turn motor 2 on
  delay(2000);
  digitalWrite(11, LOW);   // turn motor 1 off
  digitalWrite(7, LOW);   // make direction of motor 2 normal
  digitalWrite(10, LOW);   // turn motor 2 off
  headPush=0;
}

void rightBackward() {
  delay(1000);
  digitalWrite(11, HIGH);   // turn motor 1 on 
  digitalWrite(8, HIGH);   // reverse direction of motor 2
  digitalWrite(10, HIGH);   // turn motor 2 on
  delay(2000);
  digitalWrite(11, LOW);   // turn motor 1 off
  digitalWrite(8, LOW);   // make direction of motor 2 normal
  digitalWrite(10, LOW);   // turn motor 2 off
  headPush=0;
}

void gradualTurn() {
  delay(1000);
  digitalWrite(12, HIGH);   // turn motor 1 on 
  digitalWrite(8, HIGH);   // reverse direction of motor 2
  digitalWrite(11, HIGH);   // turn motor 2 on
  delay(200);
  digitalWrite(10,HIGH); // turn motor 3 on
  delay(200);
  digitalWrite(10,LOW); // turn motor 3 on
  delay(200);
  digitalWrite(10,HIGH); // turn motor 3 on
  delay(200);
  digitalWrite(10,LOW); // turn motor 3 on
  delay(200);
  digitalWrite(10,HIGH); // turn motor 3 on
  delay(200);
  digitalWrite(10,LOW); // turn motor 3 on
  delay(200);
  digitalWrite(10,HIGH); // turn motor 3 on
  delay(200);
  digitalWrite(10,LOW); // turn motor 3 on
  delay(200);  
  digitalWrite(12, LOW);   // turn motor 1 off
  digitalWrite(8, LOW);   // make direction of motor 2 normal
  digitalWrite(11, LOW);   // turn motor 2 off
  headPush=0; 
}

Use the Motor test to see a "skeleton" of what the coding in Tribot should look like. The setup() tells you which pins are wired to what. The loop() tells you all of the commands Tribot will follow. In this case it's

-one motor at a time
-spin tight CCW
-one motor at a time
-spin tight CCW
-spin tight CW
-gradual turn
-forward
-backward
-right forward 
-right backward

Each command is followed by a delay of 1000 miliseconds

Decide what new pattern will be

 
the path that Tribot follows to go in a square using the different commands

Envision what you want the Tribot to do. In this case, it needs to go in a square. A square looks like the graphic above. This new pattern begins with a starting point, then a forWard command from the point then a gradualTurn then forWard then gradualTurn then forWard then gradualTurn and lastly one more forWard command.

Change the original

 
The new commands inserted into the loop() section of the Arduino code. The new commands allow Tribot to go in a square pattern.

Copy the original code into a word document. Decide what you want in the new code. In the loop() part of the code, erase what you do not want. At the end, insert the new commands that will make a square. The new commands come from the graphic of the path. Each command is followed by a 1000 millisecond delay. After the loop comes the individual sections for each command. They're titled "void (insert name)". Keep only the commands that you will be using. Erase the rest of the sections.

The final code The final code should look like this:

Tribot Square Move Code

void setup() {

 // initialize the digital pin as an output.
 pinMode(12, OUTPUT); //yellow wire to motor enable 1
 pinMode(11, OUTPUT); //teal wire to motor enable 2
 pinMode(10, OUTPUT); //blue wire to motor enable 3
 pinMode(9, OUTPUT); // white wire to motor direction 1
 pinMode(8, OUTPUT); //gray wire to motor direction 2
 pinMode(7, OUTPUT); //purple wire to motor direction 3
 pinMode(6, INPUT); //orange encoder from motor 1
 pinMode(5, INPUT); //red encoder from motor 1
 pinMode(4, INPUT); //brown encoder from motor 1

}

void loop() // oneMotorAtATime(); // spinTightCCW();

 {
 oneMotorAtATime();
 delay(1000);
 spinTightCCW();
 delay(1000);
 gradualTurn();
 delay(1000);
 rightForward();
 delay(1000);
 gradualTurn();
 delay(1000);
 forWard();
 delay(1000);
 gradualTurn();
 delay(1000);
 forWard();
 delay(1000);
 gradualTurn();
 delay(1000);
 forWard();
 delay(1000);
 

}

void oneMotorAtATime() {

 //motors turning individually
 delay(1000);              // wait for a second
 digitalWrite(12, HIGH);   // set the LED on
 delay(2000);              // wait for a second
 digitalWrite(12, LOW);    // set the LED off
 delay(2000);              // wait for a second
 digitalWrite(11, HIGH);   // set the LED on
 delay(2000);              // wait for a second
 digitalWrite(11, LOW);    // set the LED off
 delay(2000);              // wait for a second
 digitalWrite(10, HIGH);   // set the LED on
 delay(2000);              // wait for a second
 digitalWrite(10, LOW);    // set the LED off
 

}

void spinTightCCW() {

 delay(1000);
 digitalWrite(9, HIGH);   // reverse motor 1
 digitalWrite(8, HIGH);   // reverse motor 2
 digitalWrite(7, HIGH);   // reverse motor 3
 delay(100);
 digitalWrite(12, HIGH);   // turn motor 1 on 
 digitalWrite(11, HIGH);   // turn motor 1 on
 digitalWrite(10, HIGH);   // turn motor 3 on
 delay(840);
 digitalWrite(12, LOW);   // turn motor 1 off 
 digitalWrite(11, LOW);   // turn motor 2 off
 digitalWrite(10, LOW);   // turn motor 3 off
 digitalWrite(9, LOW);   // normal motor 1
 digitalWrite(8, LOW);   // normal motor 2
 digitalWrite(7, LOW);   // normal motor 3 

} void forWard() {

 delay(1000);
 digitalWrite(12, HIGH);   // turn motor 1 on 
 digitalWrite(8, HIGH);   // reverse direction of motor 2
 digitalWrite(11, HIGH);   // turn motor 2 on
 delay(2000);
 digitalWrite(12, LOW);   // turn motor 1 off
 digitalWrite(8, LOW);   // make direction of motor 2 normal
 digitalWrite(11, LOW);   // turn motor 2 off

}

void rightForward() {

 delay(1000);
 digitalWrite(11, HIGH);   // turn motor 1 on 
 digitalWrite(7, HIGH);   // reverse direction of motor 2
 digitalWrite(10, HIGH);   // turn motor 2 on
 delay(2000);
 digitalWrite(11, LOW);   // turn motor 1 off
 digitalWrite(7, LOW);   // make direction of motor 2 normal
 digitalWrite(10, LOW);   // turn motor 2 off

}

void gradualTurn() {

 delay(1000);
 digitalWrite(12, HIGH);   // turn motor 1 on 
 digitalWrite(8, HIGH);   // reverse direction of motor 2
 digitalWrite(11, HIGH);   // turn motor 2 on
 delay(200);
 digitalWrite(10,HIGH); // turn motor 3 on
 delay(200);
 digitalWrite(10,LOW); // turn motor 3 on
 delay(200);
 digitalWrite(10,HIGH); // turn motor 3 on
 delay(200);
 digitalWrite(10,LOW); // turn motor 3 on
 delay(200);
 digitalWrite(10,HIGH); // turn motor 3 on
 delay(200);
 digitalWrite(10,LOW); // turn motor 3 on
 delay(200);
 digitalWrite(10,HIGH); // turn motor 3 on
 delay(200);
 digitalWrite(10,LOW); // turn motor 3 on
 delay(200);  
 digitalWrite(12, LOW);   // turn motor 1 off
 digitalWrite(8, LOW);   // make direction of motor 2 normal
 digitalWrite(11, LOW);   // turn motor 2 off

}

Troubleshooting

Powering Tribot If batteries are left in the tribot, they will corrode the battery case. The problem can be solved by scrapping off the corrosion. Corrosion is mostly found on the removable red lid, but it also occurs at the top of the battery, deep inside the base.

There is a black button in the base of the Tribot that has to be pressed to turn it on.

If the batteries are good, an LED on the arduino will glow.

If the head switch is jammed or not connected, then pressing the head will not start the program.

Wheels spin when turning on Send motor test to the arduino. It probably has another program loaded.

Demo

edit

Presentation

Seminar Presentation 2014MAR20

A demonstration of a working tribot with the Motor test installed is shown on the following video: Tribot Demo Test

Next Steps

edit
  1. Explore possibilities of line-following tribot
  2. Apply power to the head and try to control it's features with arduion
  3. Start capturing wheel turning information from the encoder
  4. Test new base to see if tribot can work equally well on ground and ball
  5. Define working, test all 5 and document current status
  6. Add simple mechanism so that all 5 spill out of a door when is opened
  7. Add remote controller
  8. Add speakers
  9. add a camara
  10. Determine if accelerometer and gyro have to be calibrated, start testing with PID software