Roamer, The Self Charging Companion Robot

About the project

Roamer is a self-charging, switch free, capacitor powered, wandering robot companion.

Project info

Difficulty: Moderate

Platforms: Arduino

Estimated time: 1 day

License: GNU General Public License, version 3 or later (GPL3+)

Items used in this project

Hardware components

Breadboard Breadboard Electronic Components / Misc. Electronic Components x 1
Spring, 5.5 mm x 38 mm Spring, 5.5 mm x 38 mm https://www.amazon.com/gp/product/B076XKY3JM/ref=ppx_yo_dt_b_search_asin_title?ie=UTF8&psc=1 x 1
4.7 k resistor 4.7 k resistor x 3
One amp diode One amp diode x 1
Arduino motor shield Arduino motor shield x 1
Arduino Arduino x 1
Lever switch, momentary Lever switch, momentary Development Kits, Boards anhttps://www.amazon.com/gp/product/B06WRN7FQB/ref=ppx_yo_dt_b_search_asin_title?ie=UTF8&psc=1d Systems / Development Kits and Boards x 1
500 farad, 2.8 volt capacitor 500 farad, 2.8 volt capacitor https://www.amazon.com/gp/product/B07H981BGV/ref=ppx_yo_dt_b_search_asin_title?ie=UTF8&psc=1 x 3
Bench power supply Bench power supply https://www.amazon.com/gp/product/B00ZBCLJSY/ref=ppx_yo_dt_b_search_asin_title?ie=UTF8&psc=1 x 1
Steel sheet, 12" x 12" Steel sheet, 12" x 12" https://www.amazon.com/gp/product/B000W6ZMQY/ref=ppx_yo_dt_b_search_asin_title?ie=UTF8&psc=1 x 1
Aluminum duct tape Aluminum duct tape x 1
Jumper cables Jumper cables x 1
Boost converter Boost converter https://www.amazon.com/gp/product/B00DWX8PM2/ref=ppx_yo_dt_b_search_asin_title?ie=UTF8&psc=1 x 1
Servo motor--no end stops Servo motor--no end stops https://www.amazon.com/gp/product/B07569WJ1M/ref=ppx_yo_dt_b_search_asin_title?ie=UTF8&psc=1 x 2

View all

Story

Initially, set Roamer on a charging station. Like a pet bug, she will wander around, feed herself and rest at night. The next day, she’ll do it again. To me, a personal companion robot should have the functionality of an ant or better: no programming, setting controls or recharging batteries. She can run about 20 minutes between charges. The charging station is simply an energized floor plate and energized bump rail. A spring on the bottom of Roamer contacts the floor plate and Roamer’s front bumper contacts the bump rail. The floor plate and bump rail are energized by a bench power supply set at 9 volts dc with current limited to .8 amps. When Roamer makes contact with the bump rail, she turns off her motors and evaluates the voltage between her bumper and spring. If the voltage is greater than 2 volts and less than 8.5 volts, she sits and waits until the voltage rises to 8.5 volts, then she backs up and is on her way--unless it is dark.


Details

---------- Redefine Robots ----------

Set Roamer on a charging station. When charged, she wanders around randomly, sometimes coming into the charging station and topping off. When the room gets dark (night), Roamer “rests” on the charging station. At dawn (light), she resumes her journey to nowhere, charging at every opportunity.

Here is a real time view in action.

Here's the schematic.



Project Logs

Stepper Motor to Drive Wheels

Now I'm trying a thin Nema 17 stepper motor to replace the geared dc wheel driver motor--it works!

I'm driving the motor with an Arduino motor shield--motor pin 1 to B-; motor pin 4 to B+; motor pin 6 to A-; motor pin 3 to A+.

Code (stepper motor short) follows:


int delaylength=10;
int volt=220;

void setup() {
  pinMode(12,OUTPUT);
  pinMode(13,OUTPUT);
  pinMode(9,OUTPUT);
  pinMode(8,OUTPUT);

}

void loop() {

  //round 1
  digitalWrite(9,LOW);
  digitalWrite(8,HIGH);

  digitalWrite(12,HIGH);
  analogWrite(3,volt);

  delay(delaylength);
 

  digitalWrite(9,HIGH);
  digitalWrite(8,LOW);

  digitalWrite(13,LOW);
  analogWrite(11,volt);

  delay(delaylength);

 digitalWrite(9,LOW);
  digitalWrite(8,HIGH);

  digitalWrite(12,LOW);
  analogWrite(3,volt);

  delay(delaylength);

  digitalWrite(9,HIGH);
  digitalWrite(8,LOW);

  digitalWrite(13,HIGH);
  analogWrite(11,volt);

  delay(delaylength); 

//end round 1

}


I supplied 10 volts dc with one amp capacity to the motor shield power input.


Good News/Bad News

The good news is that Roamer has run for quite a while, with never a failure to find the charging station.  Like a turtle, Roamer has wound up with wheels off the ground a few times (I think I know how to solve that issue). 

The bad news is that running for many hours takes a toll on little dc motors--shall we say failure? 

There are no brushes in these little motors, merely little "fingers" that wear out rather quickly.

A dc motor with genuine brushes would probably last longer--but a robot that buzzes around twelve to fourteen hours a day is going to strain a brushed motor.

I'm testing a stepper motor to see if that might provide the reliability I want.  A companion robot needs to run a long time without serious maintenance. I have more work to do.


Software

When Roamer's bumper is depressed, there are five possible "backup and turn" scenarios--the activation choice is random.

After 30 seconds of forward movement (stuck spinning wheels without depressing the bumper or long distance), she backs up and tries another direction.


unsigned long timestart;
unsigned long timeend;
unsigned long timetotal;

int a=95;//speed for left? motor, increased from 80
int b=85;
int c=650;//value for photoresistor day/night higher = less light to keep going
int d=820;//upper voltage value

int t1=1;

int volt=A1;//bumper input pin
int val=0;//initial bumper value
int val1=100;//initial value for photocell

int bumper=1;//setup bumper not pressed
long randNumber;
int x=1;//current read value to be determined in setup
int x1=0;//first of multiple reads
int x2=0;
int x3=0;
int x4=0;
int x5=0;

int y=0;//counts for overcurrent rather than spike
int z=0;//storage area for temporary current reads

const int pwmA=3;
const int pwmB=11;
const int brakeA=9;
const int brakeB=8;
const int dirA=12;
const int dirB=13;

void setup() {
  
  pinMode (dirA,OUTPUT);
  pinMode (brakeA,OUTPUT);
  pinMode (dirB,OUTPUT);
  pinMode (brakeB,OUTPUT);
  pinMode (A1,INPUT);
  

  pinMode (2,INPUT);
  digitalWrite (2,HIGH);
  randomSeed (analogRead(0));
  
  digitalWrite(brakeA,LOW);
  digitalWrite(brakeB,LOW);
  
   digitalWrite(dirA,HIGH);
  digitalWrite(dirB,HIGH);
  analogWrite(pwmA,0);//changed to reflect no overcurrent mode
  analogWrite(pwmB,0);
  //delay(2000);//get motors started
  //x1=analogRead(A0);//set normal motor value
  //delay(10);
  //x2=analogRead(A0);
  //delay(10);
  //x3=analogRead(A0);
  //delay(10);
  //x4=analogRead(A0);
  //delay(10);
  //x5=analogRead(A0);
  
  //x=((x1+x2+x3+x4+x5)/5);
  x=500;//arbitray number
  
  timestart=millis();
  
}

void loop() {
  
  bumper=digitalRead(2);
  if (bumper==0) {//bumper depressed
  randNumber=random(1,5);//changed august 12 from 1,4
  
  if(randNumber==1) {
    
    analogWrite(pwmB,0);//check for power station
    analogWrite(pwmA,0);
    delay(500);//stop to read
    val=analogRead(A2);
    if (val>100) {
      val1=analogRead(A3);
      while ((val<d && val>100) || (val1>c)) {//was 815 instead of 600
       val1=analogRead(A3);
        val=analogRead(A2);
        delay(100);
      }}
      
    
    
    digitalWrite(dirA,LOW);
    digitalWrite(dirB,LOW);//reverse
    analogWrite(pwmA,120);//was 150
    analogWrite(pwmB,70);//reverse power
    delay(500);
    analogWrite(pwmB,0);
    delay(750);
    analogWrite(pwmA,0);//stop
    
    digitalWrite(dirA,HIGH);
  digitalWrite(dirB,HIGH);
  analogWrite(pwmA,a);
  analogWrite(pwmB,b);
  delay(1000);
  
  t1=0;
  timestart=millis();
  
  }
  
  if (randNumber==2) {
    
    analogWrite(pwmB,0);//check for power station
    analogWrite(pwmA,0);
    delay(500);//stop to read
    val=analogRead(A2);
    if (val>100) {
      val1=analogRead(A3);
      while ((val<d && val>100) ||(val1>c)) {
         val1=analogRead(A3);
       val=analogRead(A2);
        delay(100);
      }}
    
    digitalWrite(dirA,LOW);
    digitalWrite(dirB,LOW);//reverse
    analogWrite(pwmA,70);//was 150
    analogWrite(pwmB,120);//reverse power
    delay(600);
    analogWrite(pwmA,0);
    delay(1000);
    analogWrite(pwmB,0);//stop
    
    digitalWrite(dirA,HIGH);
  digitalWrite(dirB,HIGH);
  analogWrite(pwmA,a);
  analogWrite(pwmB,b);
  delay(1000);
  
  t1=0;
  timestart=millis();
  }
  
  if (randNumber==3) {
    
    analogWrite(pwmB,0);//check for power station
    analogWrite(pwmA,0);
    delay(500);//stop to read
    val=analogRead(A2);
    if (val>100) {
      val1=analogRead(A3);
      while ((val<d && val>100) || (val1>c)) {
         val1=analogRead(A3);
        val=analogRead(A2);
        delay(100);
      }}
    
    digitalWrite(dirA,LOW);
    digitalWrite(dirB,LOW);//reverse
    analogWrite(pwmA,a);//was 150
    analogWrite(pwmB,b);//reverse power
    delay(600);
    digitalWrite(dirB,HIGH);
    analogWrite(pwmB,150);
    delay(800);
    analogWrite(pwmA,0);//stop
    analogWrite(pwmB,0);
    
    digitalWrite(dirA,HIGH);
  digitalWrite(dirB,HIGH);
  analogWrite(pwmA,a);
  analogWrite(pwmB,b);
  delay(1000);
  
  t1=0;
  timestart=millis();
  }

 if(randNumber==4) {
    
    analogWrite(pwmB,0);//check for power station
    analogWrite(pwmA,0);
    delay(500);//stop to read
    val=analogRead(A2);
    if (val>100) {
      val1=analogRead(A3);
      while ((val<d && val>100) || (val1>c)) {//was 815 instead of 600
       val1=analogRead(A3);
        val=analogRead(A2);
        delay(100);
      }}
      
    
    
    digitalWrite(dirA,LOW);
    digitalWrite(dirB,LOW);//reverse
    analogWrite(pwmA,a);//was 150
    analogWrite(pwmB,b);//reverse power
    delay(500);
    analogWrite(pwmB,0);
    delay(1000);
    analogWrite(pwmA,0);//stop
    
    digitalWrite(dirA,HIGH);
  digitalWrite(dirB,HIGH);
  analogWrite(pwmA,a);
  analogWrite(pwmB,b);
  delay(1000);
  
  t1=0;
  timestart=millis();
  
  }
  
   if(randNumber==5) {
    
    analogWrite(pwmB,0);//check for power station
    analogWrite(pwmA,0);
    delay(500);//stop to read
    val=analogRead(A2);
    if (val>100) {
      val1=analogRead(A3);
      while ((val<d && val>100) || (val1>c)) {//was 815 instead of 600
       val1=analogRead(A3);
        val=analogRead(A2);
        delay(100);
      }}
      
    
    
    digitalWrite(dirA,LOW);
    digitalWrite(dirB,LOW);//reverse
    analogWrite(pwmA,a);//was 150
    analogWrite(pwmB,b);//reverse power
    delay(400);
    analogWrite(pwmB,0);
    delay(800);
    analogWrite(pwmA,0);//stop
    
    digitalWrite(dirA,HIGH);
  digitalWrite(dirB,HIGH);
  analogWrite(pwmA,a);
  analogWrite(pwmB,b);
  delay(1000);
  
  t1=0;
  timestart=millis();
  
  }
  
  

}
  
  
  //main body of action
  if (t1=0) {
    timestart = millis();
    t1=1;
  }
  if (t1=1) {
    timeend = millis();
    timetotal= (timeend-timestart);
  }
    if (timetotal>30000) {
     digitalWrite(dirA,LOW);
    digitalWrite(dirB,LOW);//reverse
    analogWrite(pwmA,a);//was 150
    analogWrite(pwmB,b);//reverse power
    delay(1000);
    digitalWrite(dirB,HIGH);
    analogWrite(pwmB,150);
    delay(1000);
    analogWrite(pwmA,0);//stop
    analogWrite(pwmB,0);
    
    digitalWrite(dirA,HIGH);
  digitalWrite(dirB,HIGH);
  analogWrite(pwmA,a);
  analogWrite(pwmB,b);
  delay(1000);
 
 t1=0;
 timestart=millis();
    } 
      
  digitalWrite(dirA,HIGH);
  digitalWrite(dirB,HIGH);
  analogWrite(pwmA,a);
  analogWrite(pwmB,b);
  
  z=analogRead(A0);//read current
  
  if (z>(x+210))  {//turn around and restart
      digitalWrite(dirA,LOW);
    digitalWrite(dirB,LOW);//reverse
    analogWrite(pwmA,150);
    analogWrite(pwmB,150);//reverse power
    delay(1000);
    digitalWrite(dirB,HIGH);
    analogWrite(pwmB,150);
    delay(600);
    analogWrite(pwmA,0);//stop
    analogWrite(pwmB,0);
    
    digitalWrite(dirA,HIGH);//go forward one second
  digitalWrite(dirB,HIGH);
  analogWrite(pwmA,a);
  analogWrite(pwmB,b);
  delay(1000);
  
  t1=0;
  timestart=millis();
    } 
    
  
}



Baseboard Charger

I set up a baseboard charging station--took about five minutes.

Start with an eighteen inch by six inch sheet of steel and an eighteen inch piece of 1 x 2 wood.

Drill holes (I drilled three) in the edge of the steel.

Screw the wood to the steel.

Add aluminum duct tape to the wood, making sure that the tape does not touch the base. 

Set against a wall and attach the bench power supply--it's ready to go!


How Roamer was Assembled

Start with the servo motors--I selected metal gear servos that do not have end stops.

Remove the circuit board.

Solder wires to the motor connections.

Put the motor back together. Place the vacuum belt (tire) on the wheel.

Attach the servo horn to the wheel using 3mm screws.

Install the servo motors.

Secure the wheels to the motor shaft.

Repeat.

Install the holder for the rear caster ball.

Insert the caster ball.

Insert a 3mm screw into one end of the spring.

Drill a hole in the base and put the screw through the hole.

On the other side of the base attach the pickup wire.

Secure the switch holder to the front of the frame.

Attach aluminum duct tape to the front bumper. Tape a wire (so that it connects to the foil electrically) to the bumper.

Install a lever switch in the switch holder.

Attach the bumper to the switch holder using 3mm screws.

Place the board/capacitor holder onto the frame. Glue together (or lightly melt using a soldering iron).

Attach two capacitors to the rear part of the frame using Velcro strips.

Place the boost converter on the electronics holder.

Secure the charge plate pole to the charge base using 3mm screws.

Place foil tape on the pole--not touching the base.

Add the breadboard and wire according to the schematic.

Add the Arduino and motor shield. Secure using Velcro.

Add the eyes and smile to the back.

The spring and the bumper are the contact points for charging. The bumper should receive positive voltage from the power supply and the spring receives negative.

The photocell enables Roamer to "know" that it is dark--then remain on the charger until morning.


Credits

Photo of electrouser778

electrouser778

I am an author and electrical engineer.

   

Leave your feedback...