???? 調試程序,運行調試程序,舵機會移動兩只懸臂分別停留在一只水平另一只垂直的位置上。如果差距非常大,可拆下懸臂調節,如果比較接近了,就修改程序第3~6行的四個參數 SERVOFAKTORLEFT 左懸臂垂直位置,SERVOFAKTORRIGHT 右懸臂垂直位置,SERVOLEFTNULL 左懸臂180度位置,SERVORIGHTNULL 右懸臂0度位置(右側為0度,逆時針畫圓),參數增加擺臂逆時針轉動,一般增幅50,才能看到比較明顯的變化。
???? 調節參數,直到擺臂停在下圖的標準位置上為止。

???? LIFT0、1、2參數原理相同調試方法略過
如果調試完畢,就可以安裝筆擦等附件,開始耍賤了!
標準程序需要時間模塊讀取時間,如果沒有模塊,可以修改函數,返回隨機數或者從00:00開始計時等辦法。
《Plotclock小賤鐘程序》
???? 調節參數,直到擺臂停在下圖的標準位置上為止。

???? LIFT0、1、2參數原理相同調試方法略過
??? 《調試擺臂用代碼》
//左右懸臂舵機的90度位置
#define SERVOFAKTORLEFT 550
#define SERVOFAKTORRIGHT 630 //此參數650是理論中間位置,需要看實際情況調節//左右懸臂舵機的 0或180度位置
#define SERVOLEFTNULL 1750
#define SERVORIGHTNULL 880//三只舵機的接口
#define SERVOPINLIFT 2
#define SERVOPINLEFT 3
#define SERVOPINRIGHT 4//升舉舵機的3個角度
#define LIFT0 1080 // on dr<span style="font-size:12px;">awing surface 寫的時候
#define LIFT1 925 // between numbers 字之間
#define LIFT2 725 // going towards sweeper 去筆擦高度</span>// 速度
#define LIFTSPEED 1500// 懸臂的長度,根據圖紙測量,無需改變
#define L1 35
#define L2 57.2
#define L3 14.2// 左右舵機軸心的位置
#define O1X 23
#define O1Y -25
#define O2X 49
#define O2Y -25#include <Time.h> // see [url=http://playground.arduino.cc/Code/time]http://playground.arduino.cc/Code/time[/url]
#include <Servo.h>int servoLift = 1500;Servo servo1; // Servo 類 聲明
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 neededsetTime(19,38,0,0,0,0);drawTo(38, 24);lift(0);servo1.attach(SERVOPINLIFT); // lifting servoservo2.attach(SERVOPINLEFT); // left servoservo3.attach(SERVOPINRIGHT); // right servodelay(1000);} void loop()
{ // 移動左右懸臂,讓兩只懸臂分別停留在水平和垂直的位置上。 通過修改 SERVOFAKTORLEFT , SERVOFAKTORRIGHT, SERVOLEFTNULL , SERVORIGHTNULL 四個參數來微調drawTo(-3, 29.2);delay(500);drawTo(74.1, 28);delay(500);} // 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: //850if (servoLift >= LIFT0) {while (servoLift >= LIFT0) {servoLift--;servo1.writeMicroseconds(servoLift); delayMicroseconds(LIFTSPEED);}} else {while (servoLift <= LIFT0) {servoLift++;servo1.writeMicroseconds(servoLift);delayMicroseconds(LIFTSPEED);}}break;case 1: //150if (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 pointdx = pX - lastX;dy = pY - lastY;//path lenght in mm, times 4 equals 4 steps per mmc = floor(4 * sqrt(dx * dx + dy * dy));if (c < 1) c = 1;for (i = 0; i <= c; i++) {// draw line point by pointset_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 areturn 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/dydx = 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) * SERVOFAKTORLEFT) + SERVOLEFTNULL));// calculate joinr arm point for triangle of the right servo arma2 = 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 jointdx = Hx - O2X;dy = Hy - O2Y;c = sqrt(dx * dx + dy * dy);a1 = atan2(dy, dx);a2 = return_angle(L1, (L2 - L3), c);servo3.writeMicroseconds(floor(((a1 - a2) * SERVOFAKTORRIGHT) + SERVORIGHTNULL));}</span>
如果調試完畢,就可以安裝筆擦等附件,開始耍賤了!
標準程序需要時間模塊讀取時間,如果沒有模塊,可以修改函數,返回隨機數或者從00:00開始計時等辦法。
《Plotclock小賤鐘程序》
//↓↓↓↓↓↓↓? 以下參數在調試程序中調節好后復制過來?? ↓↓↓↓↓↓↓//1.先調節0、180度的位置。調節到位后,再調節90度位置
//左右懸臂舵機的 0或180度位置,,數字增加,左側舵機逆時針調整,右側舵機順時針調整
//【此數值可能需要調節】
#define SERVOLEFTNULL 2030? //數值減小,順時針旋轉,加大則逆時針旋轉
//【此數值可能需要調節】
#define SERVORIGHTNULL 1100? //數值減小,順時針旋轉,加大則逆時針旋轉//2.調節到位0、180,再調節下面參數
//左右懸臂舵機的90度位置,,數字增加,左側舵機順時針調整,右側舵機逆時針調整
//【此數值可能需要調節】
#define SERVOFAKTORLEFT 580 //數值加大,順時針旋轉,減小則逆時針旋轉
//【此數值可能需要調節】
#define SERVOFAKTORRIGHT 610? //數值減小,順時針旋轉,加大則逆時針旋轉//升舉舵機的3個角度
//【此數值可能需要調節】
#define LIFT0 1620 //落筆寫字 on drawing surface
#define LIFT1 1320? //寫字時抬臂動作 between numbers
#define LIFT2 580? //高抬筆架? going towards sweeper
//【此數值可能需要調節】//
//以上參數,請運行調試程序 plotclockadj ,調整好位置后,將數據復制過來
////筆擦的坐標位置,如不能對準筆擦可以微調單位毫米
int? rubberx=72,rubbery=42;?? //【此數值可能需要調節】//三只舵機的接口號
#define SERVOPINLIFT? 2 //抬臂舵機
#define SERVOPINLEFT? 3 //左臂舵機
#define SERVOPINRIGHT 4 //右臂舵機// 速度? 數字越小越慢,太快了容易抖 1000~2000
#define LIFTSPEED 1500 // 懸臂的長度,根據圖紙測量,無需改變
#define L1 35
#define L2 57.2
#define L3 14.2// 左右舵機軸心的位置,根據圖紙測量,無需改變
#define O1X 22
#define O1Y -25
#define O2X 47
#define O2Y -25//需要的庫函數 ,如果編譯報告 time.h 錯誤請參考readme文檔
#include <Time.h> // see http://playground.arduino.cc/Code/time
#include <Servo.h>int servoLift = LIFT2;Servo servo1;? //
Servo servo2;? //
Servo servo3;? // volatile double lastX = rubberx;
volatile double lastY = rubbery;int last_min = 0;void setup()
{ // 設置一個模擬時間,(小時,分鐘,后面全填0)//如果此句編譯錯誤,請將文件包內的libraries庫放到Arduino文件夾內,具體操作辦法見說明文檔setTime(19,38,0,0,0,0); servo1.attach(SERVOPINLIFT);? //初始化抬臂舵機? lifting servoservo2.attach(SERVOPINLEFT);? //初始化左臂舵機? left servoservo3.attach(SERVOPINRIGHT); //初始化右臂舵機? right servolift(1); //抬筆drawTo(rubberx, rubbery); //停留在筆擦位置delay(1000);} void loop()
{ int i = 0;//下面代碼任選一行,進行不同模式的書寫//if (last_min != minute())? //每分鐘書寫一次時間//if? (1)????????????????? //反復不間斷的擦寫模式if (1) //如需修改請復制上面代碼{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()) //提取19:38時間部分的第一位,也就是19的1{i++;}number(3, 3, 111, 1); //擦黑板number(5, 25, i, 0.9); // 書寫19:38的第一位,也就是寫1number(19, 25, (hour()-i*10), 0.9); //提取并書寫19:38的第二位,也就是寫9number(28, 25, 11, 0.9);//書寫19:38的點 :i=0;while ((i+1)*10 <= minute()) //提取19:38時間部分的分鐘位,也就是38的3{i++;}number(34, 25, i, 0.9);//書寫19:38的第四位,也就是3number(48, 25, (minute()-i*10), 0.9);//提取并書寫19:38的第五位,也就是8lift(2);drawTo(70, 44); //移動到70,44lift(1);last_min = minute();servo1.detach();servo2.detach();servo3.detach();}} // 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(rubberx, rubbery);drawTo(58, 42);drawTo(58, 45);drawTo(2, 45);drawTo(2, 41);drawTo(58, 41);drawTo(60, 37);drawTo(2, 37);drawTo(2, 33);drawTo(60, 33);drawTo(60, 29);drawTo(2, 29);drawTo(2, 25);drawTo(60, 25);drawTo(60, 20);drawTo(2, 20);drawTo(60, rubbery);drawTo(rubberx + 3 , rubbery);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: 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: 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);}//cos?sin?
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 pointdx = pX - lastX;dy = pY - lastY;//path lenght in mm, times 4 equals 4 steps per mmc = floor(4 * sqrt(dx * dx + dy * dy));if (c < 1) c = 1;for (i = 0; i <= c; i++) {// draw line point by pointset_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 areturn acos((a * a + c * c - b * b) / (2 * a * c));
}//用各種三角函數把位置坐標換算成舵機的角度,具體咋算的,請參考
//Plotclock by joo - Thingiverse
//http://www.thingiverse.com/thing:248009/
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/dydx = 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) * SERVOFAKTORLEFT) + SERVOLEFTNULL));// calculate joinr arm point for triangle of the right servo arma2 = 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 jointdx = Hx - O2X;dy = Hy - O2Y;c = sqrt(dx * dx + dy * dy);a1 = atan2(dy, dx);a2 = return_angle(L1, (L2 - L3), c);servo3.writeMicroseconds(floor(((a1 - a2) * SERVOFAKTORRIGHT) + SERVORIGHTNULL));}