Eduardo The PlotBot


Eduardo is a (semi) accurate plotting robot. unconfined in space, Eduardo can roam around the world and plot on the ground.

Cad

full

Eduardo needs to have high friction wheels and a lot of weight to avoid slippage. This design can be improved. most importantly, the center of mass needs to be close to the wheels, rather than in the back.

front

Laser cutting acrylic for the body and 3d printing the marker holder.

naked

I used razor scooter wheels for the front and ball casters for the back.

Electronics

Components:

Custom circuitry to connect everything together

schema board front The circuit was hacked so that 5V are received externally rather than the SMD regulator and individual capacitors were placed on each of the step motor drivers.
back Oops. the usb jack is on the wrong side.

In the process I fried 7 step motor drivers. The grave yard: burnt (TODO: list all the ways you can burn a step motor driver)

Putting it all together complete

Embedded Software

Eduardo handles command packets comprised of 5 integers: MARKER_DOWN, LEFT_DIRECTION, RIGHT_DIRECTION, STEPS. these were meant to be fed via WiFi but the ESP8266 was not functioning well so for now these are fed initially via Serial.

#include <Servo.h>
#include "ESP8266.h"

int servoPin = 2;
int rightStepPin = 8;
int rightDirPin = 9;
int leftStepPin = 11;
int leftDirPin = 12;
int yellowLedPin = 13; 

int ANGLE_UP = 110; 
int ANGLE_DOWN = 45; 

Servo servo; 


void setup() 
{             
  servo.attach(servoPin);  
  servo.write(ANGLE_UP);
  pinMode(rightStepPin, OUTPUT);
  pinMode(rightDirPin, OUTPUT);
  pinMode(leftStepPin, OUTPUT);
  pinMode(leftDirPin, OUTPUT);
  pinMode(yellowLedPin, OUTPUT);
  Serial.begin(9600);
}

void stepTogether(int duration)
{
    digitalWrite(rightStepPin, HIGH);   
    digitalWrite(leftStepPin, HIGH);   
    delay(duration);               
    digitalWrite(rightStepPin, LOW);  
    digitalWrite(leftStepPin, LOW);  
    delay(duration);    
}

void move(int down, int leftDir, int rightDir, int steps, int pulse) {
  Serial.print("Pen Down: ");
  Serial.print(down);
  Serial.print(", Left Direction: ");
  Serial.print(leftDir);
  Serial.print(", Right Direction: ");
  Serial.print(rightDir);
  Serial.print(", Steps: ");
  Serial.print(steps);
  Serial.println();
  
  int angle = down ? ANGLE_DOWN : ANGLE_UP;
  if (servo.read()!=angle) {
    Serial.print("writing servo angle : ");
    Serial.println(angle);
    servo.write(angle);
    delay(500);
  }
  digitalWrite(leftDirPin, leftDir);  
  digitalWrite(rightDirPin, rightDir);
  for (int i=0; i<steps; i++){
    stepTogether(pulse); 
  }
}
    
void loop() {
  int i = 0;
  int commands [512];
  if (Serial.available() > 0) {
    while (Serial.available()){
      commands[i] = Serial.parseInt();
      i++;
      Serial.println(commands[i]);
    }
    digitalWrite(yellowLedPin, HIGH);
    delay(10000);
    Serial.print("Got commands: ");
    Serial.println(i);
    for (int j=0; j<(i/4-1); j++) {
      int b = j*4;
      move(commands[b], commands[b+1], commands[b+2], commands[b+3], 10);
    }
    digitalWrite(yellowLedPin, LOW);  
  }
  delay(100);
}

Path planning

Eduardo has a python script that accepts an svg file and a serial port. It parses the svg, create commands for eduardo and sends them via the serial port. It currently only translates objects

$ python eduardo.py new_svg.svg /dev/tty.usbmodem1411 9600
Start
127.6 648.0 864.0 1156.0
864.0 1156.0 864.0 95.6
864.0 95.6 1598.4 648.0
[[0, 127.6, 648.0], [1, 864.0, 1156.0], [1, 864.0, 95.6], [1, 1598.4, 648.0]]
marker:  0 , turn: 11.1397946575 , distance: 660.443608494
marker:  1 , turn: 44.2606446019 , distance: 894.622244302
marker:  1 , turn: 124.599560741 , distance: 1060.4
marker:  1 , turn: -126.949703677 , distance: 918.960891442
[0, 0, 1, 24, 0, 1, 1, 660, 1, 0, 1, 98, 1, 1, 1, 894, 1, 0, 1, 276, 1, 1, 1, 1060, 1, 1, 0, 282, 1, 1, 1, 918]

Results

Hardcoded octagon:

More to come...