 # plotclock with more detailed instructions

Jul 18, 2015

### Thing Apps Enabled

Hi, i am using 3 SG90 servos and i can´t put the left and right servos on the holes, can anyone help me? What do i have to do?

void set_XY(double Tx, double Ty) {
...
servo2.writeMicroseconds(floor(((a2 + a1 - M_PI) SERVOFAKTORLEFT) + SERVOLEFTNULL));
//What do SERVOFAKTORLEFT and SERVOLEFTNULL do here ?
...
// calculate joint arm point for triangle of the right servo arm
a2 = return_angle(L2, L1, c);
Hx = Tx + L3
cos((a1 - a2 + 0.621) + M_PI); //36,5Â° ? 35.6
Hy = Ty + L3 * sin((a1 - a2 + 0.621) + M_PI);
// Can anyone explain in detailed these 3 line please

hi. how to write character's instead of writing numbers. for my case i need to write "hai". i need code for this please help me... thank you

since you put stl files in a different page I find this more confusing
why do you do so ?

Thanks for the comment, Phil. I made this post only to add to Joo's and other's great work. The servohorn here is the only thing I created myself, and the rest of the items I used were created by others, so I posted links to them in the instructions.

hello!!!

Thanks for this great idea. I builded up this project and since 1 week I have a hard time to figure out

how to make this arms move exactly to the eraser and also for it to wipe and write correctly without going off the white board.

the more I increased the value on drawing surface the more it goes off the white board.

all what I succeeded to do is to calibrate it to go 90 degree. Please please can anyone help me with the code values that works perfect???
Right now I am just crazy that I will present this idea next week. I am really desperate about it.

thanks in advance for any help!!! this is my modified code so far

// Plotclock
// cc - by Johannes Heberlein 2014
// v 1.01
// thingiverse.com/joo wiki.fablab-nuernberg.de

// units: mm; microseconds; radians
// origin: bottom left of drawing surface

// time library see http://playground.arduino.cc/Code/time

// delete or mark the next line as comment when done with calibration

define CALIBRATION

// When in calibration mode, adjust the following factor until the servos move exactly 90 degrees

define SERVOFAKTOR 500

// Zero-position of left and right servo
// When in calibration mode, adjust the NULL-values so that the servo arms are at all times parallel
// either to the X or Y axis

define SERVOLEFTNULL 2250

define SERVORIGHTNULL 500

define SERVOPINLIFT 2

define SERVOPINLEFT 3

define SERVOPINRIGHT 4

// lift positions of lifting servo

define LIFT0 11000 // on drawing surface

define LIFT1 1925 // between numbers

define LIFT2 725 // going towards sweeper

// speed of liftimg arm, higher is slower

define LIFTSPEED 1500

// length of arms

define L1 35

define L2 55.1

define L3 13.2

// origin points of left and right servo

define O1X 22

define O1Y -25

define O2X 47

define O2Y -25

include // see http://playground.arduino.cc/Code/time

include

int servoLift = 1500;

Servo servo1; //
Servo servo2; //
Servo servo3; //

volatile double lastX = 75;
volatile double lastY = 47.5;

int last_min = 0;

void setup()
{
// Set current time only the first to values, hh,mm are needed
setTime(19,38,0,0,0,0);

drawTo(75.2, 47);
lift(0);
servo1.attach(SERVOPINLIFT); // lifting servo
servo2.attach(SERVOPINLEFT); // left servo
servo3.attach(SERVOPINRIGHT); // right servo
delay(1000);

}

void loop()
{

ifdef CALIBRATION

// Servohorns will have 90° between movements, parallel to x and y axis
drawTo(-3, 29.2);
delay(500);
drawTo(74.1, 28);
delay(500);

else

int i = 0;
if (last_min != minute()) {
if (!servo1.attached()) servo1.attach(SERVOPINLIFT);
if (!servo2.attached()) servo2.attach(SERVOPINLEFT);
if (!servo3.attached()) servo3.attach(SERVOPINRIGHT);

lift(0);

hour();
while ((i+1)*10 <= hour())
{
i++;
}

number(3, 3, 111, 1);
number(5, 25, i, 0.9);
number(19, 25, (hour()-i*10), 0.9);
number(28, 25, 11, 0.9);

i=0;
while ((i+1)10 <= minute())
{
i++;
}
number(34, 25, i, 0.9);
number(48, 25, (minute()-i
10), 0.9);
lift(2);
drawTo(74.2, 47.5);
lift(1);
last_min = minute();

servo1.detach();
servo2.detach();
servo3.detach();

}

endif

}

// Writing numeral with bx by being the bottom left originpoint. Scale 1 equals a 20 mm high font.
// The structure follows this principle: move to first startpoint of the numeral, lift down, draw numeral, lift up
void number(float bx, float by, int num, float scale) {

switch (num) {

case 0:
drawTo(bx + 12 scale, by + 6 scale);
lift(0);
bogenGZS(bx + 7 scale, by + 10 scale, 10 scale, -0.8, 6.7, 0.5);
lift(1);
break;
case 1:
drawTo(bx + 3
scale, by + 15 scale);
lift(0);
drawTo(bx + 10
scale, by + 20 scale);
drawTo(bx + 10
scale, by + 0 * scale);
lift(1);
break;

case 2:
drawTo(bx + 2 scale, by + 12 scale);
lift(0);
bogenUZS(bx + 8 scale, by + 14 scale, 6 scale, 3, -0.8, 1);
drawTo(bx + 1 scale, by + 0 scale);
drawTo(bx + 12 scale, by + 0 scale);
lift(1);
break;
case 3:
drawTo(bx + 2 scale, by + 17 scale);
lift(0);
bogenUZS(bx + 5 scale, by + 15 scale, 5 scale, 3, -2, 1);
bogenUZS(bx + 5 scale, by + 5 scale, 5 scale, 1.57, -3, 1);
lift(1);
break;
case 4:
drawTo(bx + 10 scale, by + 0 scale);
lift(0);
drawTo(bx + 10 scale, by + 20 scale);
drawTo(bx + 2 scale, by + 6 scale);
drawTo(bx + 12 scale, by + 6 scale);
lift(1);
break;
case 5:
drawTo(bx + 2 scale, by + 5 scale);
lift(0);
bogenGZS(bx + 5 scale, by + 6 scale, 6 scale, -2.5, 2, 1);
drawTo(bx + 5 scale, by + 20 scale);
drawTo(bx + 12 scale, by + 20 scale);
lift(1);
break;
case 6:
drawTo(bx + 2 scale, by + 10 scale);
lift(0);
bogenUZS(bx + 7 scale, by + 6 scale, 6 scale, 2, -4.4, 1);
drawTo(bx + 11 scale, by + 20 scale);
lift(1);
break;
case 7:
drawTo(bx + 2 scale, by + 20 scale);
lift(0);
drawTo(bx + 12 scale, by + 20 scale);
drawTo(bx + 2 scale, by + 0);
lift(1);
break;
case 8:
drawTo(bx + 5 scale, by + 10 scale);
lift(0);
bogenUZS(bx + 5 scale, by + 15 scale, 5 scale, 4.7, -1.6, 1);
bogenGZS(bx + 5 scale, by + 5 scale, 5 scale, -4.7, 2, 1);
lift(1);
break;

case 9:
drawTo(bx + 9 scale, by + 11 scale);
lift(0);
bogenUZS(bx + 7 scale, by + 15 scale, 5 scale, 4, -0.5, 1);
drawTo(bx + 5 scale, by + 0);
lift(1);
break;

case 111:
lift(0);
drawTo(70, 46);
drawTo(65, 43);

drawTo(65, 49);
drawTo(5, 49);
drawTo(5, 45);
drawTo(65, 45);
drawTo(65, 40);

drawTo(5, 40);
drawTo(5, 35);
drawTo(65, 35);
drawTo(65, 30);

drawTo(5, 30);
drawTo(5, 25);
drawTo(65, 25);
drawTo(65, 20);

drawTo(5, 20);
drawTo(60, 44);

drawTo(75.2, 47);
lift(2);

break;

case 11:
drawTo(bx + 5 scale, by + 15 scale);
lift(0);
bogenGZS(bx + 5 scale, by + 15 scale, 0.1 scale, 1, -1, 1);
lift(1);
drawTo(bx + 5 scale, by + 5 scale);
lift(0);
bogenGZS(bx + 5 scale, by + 5 scale, 0.1 scale, 1, -1, 1);
lift(1);
break;

}
}

void lift(char lift) {
switch (lift) {
// room to optimize !

case 0: //850
if (servoLift >= LIFT0) {
while (servoLift >= LIFT0)
{
servoLift--;
servo1.writeMicroseconds(servoLift);
delayMicroseconds(LIFTSPEED);
}
}
else {
while (servoLift <= LIFT0) {
servoLift++;
servo1.writeMicroseconds(servoLift);
delayMicroseconds(LIFTSPEED);

}

}

break;

case 1: //150
if (servoLift >= LIFT1) {
while (servoLift >= LIFT1) {
servoLift--;
servo1.writeMicroseconds(servoLift);
delayMicroseconds(LIFTSPEED);

}
}
else {
while (servoLift <= LIFT1) {
servoLift++;
servo1.writeMicroseconds(servoLift);
delayMicroseconds(LIFTSPEED);
}

}

break;

case 2:
if (servoLift >= LIFT2) {
while (servoLift >= LIFT2) {
servoLift--;
servo1.writeMicroseconds(servoLift);
delayMicroseconds(LIFTSPEED);
}
}
else {
while (servoLift <= LIFT2) {
servoLift++;
servo1.writeMicroseconds(servoLift);
delayMicroseconds(LIFTSPEED);
}
}
break;

}
}

void bogenUZS(float bx, float by, float radius, int start, int ende, float sqee) {
float inkr = -0.05;
float count = 0;

do {
drawTo(sqee radius cos(start + count) + bx,
radius * sin(start + count) + by);
count += inkr;
}
while ((start + count) > ende);

}

void bogenGZS(float bx, float by, float radius, int start, int ende, float sqee) {
float inkr = 0.05;
float count = 0;

do {
drawTo(sqee radius cos(start + count) + bx,
radius * sin(start + count) + by);
count += inkr;
}
while ((start + count) <= ende);
}

void drawTo(double pX, double pY) {
double dx, dy, c;
int i;

// dx dy of new point
dx = pX - lastX;
dy = pY - lastY;
//path lenght in mm, times 4 equals 4 steps per mm
c = floor(4 sqrt(dx dx + dy * dy));

if (c < 1) c = 1;

for (i = 0; i <= c; i++) {
// draw line point by point
set_XY(lastX + (i dx / c), lastY + (i dy / c));

}

lastX = pX;
lastY = pY;
}

double return_angle(double a, double b, double c) {
// cosine rule for angle between c and a
return acos((a a + c c - b b) / (2 a * c));
}

void set_XY(double Tx, double Ty)
{
delay(1);
double dx, dy, c, a1, a2, Hx, Hy;

// calculate triangle between pen, servoLeft and arm joint
// cartesian dx/dy
dx = Tx - O1X;
dy = Ty - O1Y;

// polar lemgth (c) and angle (a1)
c = sqrt(dx dx + dy dy); //
a1 = atan2(dy, dx); //
a2 = return_angle(L1, L2, c);

servo2.writeMicroseconds(floor(((a2 + a1 - M_PI) * SERVOFAKTOR) + SERVOLEFTNULL));

// calculate joinr arm point for triangle of the right servo arm
a2 = return_angle(L2, L1, c);
Hx = Tx + L3 cos((a1 - a2 + 0.621) + M_PI); //36,5°
Hy = Ty + L3 sin((a1 - a2 + 0.621) + M_PI);

// calculate triangle between pen joint, servoRight and arm joint
dx = Hx - O2X;
dy = Hy - O2Y;

c = sqrt(dx dx + dy dy);
a1 = atan2(dy, dx);
a2 = return_angle(L1, 45, c);

servo3.writeMicroseconds(floor(((a1 - a2) * SERVOFAKTOR) + SERVORIGHTNULL));

} 