口丁寫字童子

最後編輯:2015-06-30 建立:2015-02-10 歷史紀錄

 

鄭鴻旗介紹

 

MACH M設計理念

  1. 鄭鴻旗移動部份, 採容易取得&程式大家都比較熟的 RC Servo (1.5ms+-0.5ms)
  2. 最大挑戰是兩個輪子˙實際輸出, 會隨電壓負載衰退...etc 而偏移,所以才想用 Arduino 既有 PS2 mouse 的程式,搭配滾輪型X Y直接搭在輪子˙上迴饋即時輸出狀況,Arduino 主程式可以藉此修定輸出。
  3. 下筆輕重部份,捨去Z軸絕對距離方式,改採翹翹板移動中心方式,以利模仿真人下筆收筆。

MACH M 4. 轉彎部份,有一輪不動一輪動的 定軸轉彎,另一種是兩輪反向的定中心轉彎。

5. 筆跡會沾輪部份,除移動速度放慢,另外底座加個吹風風扇吹乾。

 

    鄭鴻旗材料

  • 鄭鴻旗減速馬達 *2顆 ( 9g 伺服馬達 )
  • 9g 伺服馬達 *1 顆
  • IRS01A IR Sensor 2 個
  • 帶有編碼器的輪子,如所示。
  • 底盤
  • MACH M風鼓風扇 (把墨吹乾)

 

鄭鴻旗工具

 

製作過程

  1. MACH M兩邊出力輪軸心 與筆 最好在同一圓週上, 可以簡化程式 center offset 的部份

 

    鄭鴻旗討論

鄭鴻旗使用編碼器精準控制移動的方式

使用 IRS01A IR Sensor 去讀取輪子的移動,輪子內會裝上雷切出來的板子,在板子邊緣有多個洞。

 

轉 G code 的程式碼參考:

https://github.com/dherrendoerfer/uCNC_controller/blob/master/uCNC_controller/uCNC_gcode.ino

G code 參考資料

 

what is g code ?

 

問題

 

    鄭鴻旗紀錄

鄭鴻旗20150502 進度

黃偉峻提供小車機構模組,章國俊兄已經把藍芽控制小車的方式完成,目前可以用藍牙來操縱了,不過真的一跑就歪了,因為還沒用到編碼器。XD,紀錄請見下方影片。

*

https://www.youtube.com/watch?v=uCvYBIGFheU

 

章國俊

20150502 進度2

後來把萬向輪上油潤滑之後,車子行進路立刻改善了,直很多了。

 

裝上遮斷開關,配合車子套件的碼盤。

 

計劃拿手機或筆電用藍芽和小車連線,指揮小車往前走多少公分、到定點後轉幾度、什麼地方要下筆。

小車接受指令並且自己修正。

 

20150506

馬爸把前輪換成這個。

原先的輪子在轉向時會因為本身旋轉歸位得時間差,而造成行進路線的誤差。

這個輪子就沒這個問題了。

 

20150507

用遮蔽膠帶量輪子圓周長:

 

 

20150511

  1. 改用3D列印的機構來固定馬達和光遮斷開關
  2. 換上抓地力比較好的輪子
  3. 換回原來的大顆萬象輪

車子的操控一整個改善了!

 

20150513

基本教練:第一課

其實是想要寫一個"口"字....

*

https://www.youtube.com/watch?v=36ZA0ze9PFw

還沒有做到校正的部份

 

 

以目前的機構沒有辦法做到精準,所以寫字應該會像是塗鴉。既然是塗鴉,就真的來塗鴉好了。

在手機上亂畫

 

因為用車子來寫字,也就是要用輪子走到定點,而車子的控制方式不像是CNC可以直接告訴它走到哪一個座標上面,而要轉方向盤、踩油門。

 

所以用手機計算:把在螢幕圖形的X,Y座標轉成極座標,然後再轉成轉方向盤、踩油門的指令,來控制車子。

 

 

 

 

 

用Android手機透過藍芽與Arduino控制的小車連線,讓小車以移動自身位置的方式畫出手機上面的圖形。

圖形可以運用APP以手指頭在螢幕上畫出,或是使用 APP中內建的特殊圖形(在影片中是個玫瑰線)。

目前小車還不能很準確的移動到所望位置,所以影片中的玫瑰線畫完之後首尾沒辦法連起來,差距很大。

 

手機上面可以同步顯示畫出的進度了

*

https://www.youtube.com/watch?v=oj6462PY5eQ

 

在2015的 maker faire 過後,完程度大約70%,機構還需要再做修改。看看運動可不可以再精確一點。

 

這樣的寫字方式,把筆放在兩個輪子之間較為適合。

筆可以做成模組,或可換成滴水的方式,我想在地上寫字啊!

鄭鴻旗滴水的方式可以參考:

https://vimeo.com/29306086

 

章國俊馬達考慮換成扭力更大或自帶編碼器的馬達,或是用步進馬達或是修改舵機(36)度旋轉來用。

 

 

MACH M另一支的影片:

https://youtu.be/gQGjqP5G1oE

    章國俊整理:製造組裝說明手冊

章國俊運作方式

 

機構

  • 輪子:圓周 218 mm
  • 碼盤:共有 20 孔
  • 光遮斷開關:

 

  • 說明:這樣的配合下,輪子轉一圈也就是行進218mm時,光遮斷開關會送出20個pulse;所以前進11mm大約是1個pulse。

 

  • 馬達與減齒輪組:
  • 馬達是玩具用的直流馬達,當兩個馬達都提供相同的電壓時,轉速並不會相等。因此,希望它走直線時並不會如我們所願,就是會歪掉。所以需要配合透過碼盤和光遮斷開關所回饋的pulse數量來修正。這部份需要用到PID,否則會變成蛇行。

 

連線與遙控

 

程式碼

 

MACH MpenWriting

//servo control

unsigned char servo = 6;

unsigned char count = 0;

unsigned char i = 0;

unsigned char servoTime = 0;

unsigned char servoValue = 0;

unsigned char flag = 0;

unsigned int secondT = 0;

 

unsigned int k = 0;

 

//pen

const unsigned int down = 50;

const unsigned int up = 100;

 

//motor

int L1 = 9;

int L2 = 7;

 

int R1 = 10;

int R2 = 8;

 

//speed and time

int dir = 0;

int speeds = 0;

unsigned long time = 0;

 

long serialValue = 0;

int length = 0;

 

unsigned char cmd[400];

 

void setup()

{

UBRRL=103; //16M baud 9600,8bit UART

UCSRB=0x18; //enable

 

pinMode(servo,OUTPUT);

digitalWrite(servo,LOW);

//pin for motor

pinMode(L1,OUTPUT);

pinMode(L2,OUTPUT);

pinMode(R1,OUTPUT);

pinMode(R2,OUTPUT);

 

timer2();

TIMSK &= ~(2 << 6);

digitalWrite(servo,LOW);

 

time = 300;

penWrite();

penRise();

}

 

void loop()

{

while(!(UCSRA&(1<<RXC)));

if(UDR == 170)

{

while(!(UCSRA&(1<<RXC)));

if(UDR == 85)

{

while(!(UCSRA&(1<<RXC)));

length = UDR;

length = length << 2;

 

for (k = 0;k<length;++k)

{

while(!(UCSRA&(1<<RXC)));

cmd[k] = UDR;

while(!(UCSRA&(1<<RXC)));

cmd[++k] = UDR;

while(!(UCSRA&(1<<RXC)));

cmd[++k] = UDR;

while(!(UCSRA&(1<<RXC)));

cmd[++k] = UDR;

}

 

while(!(UCSRA&(1<<RXC)));

if(UDR != 0xe0)

return;

while(!(UCSRA&(1<<RXC)));

if(UDR != 0x07)

return;

 

for (k = 0;k<length;++k)

{

dir = (cmd[k] & 0xf0) >> 4;

speeds = (cmd[k] & 0xf) * 17;

time = 0;

time = time | cmd[++k];

time = time << 8 | cmd[++k];

time = time << 8 | cmd[++k];

 

switch (dir)

{

case 8:

stoprun();

break;

case 0:

gforward();

break;

case 1:

gback();

break;

case 2:

turnLeft();

break;

case 3:

turnRight();

break;

case 4:

gLF();

break;

case 5:

gRF();

break;

case 6:

gLB();

break;

case 7:

gRB();

break;

case 9:

penWrite();

break;

case 10:

penRise();

break;

default: stoprun();

}

}

cmd[0] = UDR;

}

}

}

 

//timer2 for servo control

void timer2()

{

noInterrupts();

TCCR2 = 0x0f; //CTC,1024

OCR2 = 155;

TIMSK |= (2 << 6);

interrupts();

}

 

//each interrupt 25hz

ISR(TIMER2_COMP_vect)

{

 

//two intrupt as a circle

if(secondT == 0)

{

digitalWrite(servo,HIGH);

secondT++;

flag = 0;

}

else

{

secondT = 0;

}

 

//finished in 10ms

for(count = 0;count<127;count++)

{

if(flag == 1)

{

return;

}

 

//for(i = 0;i != 120;i++);

delayMicroseconds(76);

if(servoTime == servoValue)

{

digitalWrite(servo,LOW);

flag = 1;

servoTime = 0;

//secondT++;

return;

}

else

{

servoTime++;

}

}

}

 

 

//stop

void stoprun()

{

digitalWrite(L1,LOW);

digitalWrite(L2,LOW);

 

digitalWrite(R1,LOW);

digitalWrite(R2,LOW);

delay(time);

}

 

 

void gforward()

{

//leftmotor

analogWrite(L1,speeds);

digitalWrite(L2,LOW);

//right motor

analogWrite(R1,speeds);

digitalWrite(R2,LOW);

delay(time);

 

digitalWrite(L1,LOW);

digitalWrite(R1,LOW);

}

 

//goback

void gback()

{

//leftmotor

analogWrite(L1,speeds);

digitalWrite(L2,HIGH);

 

//right motor

analogWrite(R1,speeds);

digitalWrite(R2,HIGH);

delay(time);

 

digitalWrite(L1,LOW);

digitalWrite(L2,LOW);

 

digitalWrite(R1,LOW);

digitalWrite(R2,LOW);

}

 

void turnLeft()

{

analogWrite(L1,speeds);

digitalWrite(L2,HIGH);

 

analogWrite(R1,speeds);

digitalWrite(R2,LOW);

delay(time);

 

digitalWrite(L1,LOW);

digitalWrite(L2,LOW);

 

digitalWrite(R1,LOW);

digitalWrite(R2,LOW);

}

 

void turnRight()

{

analogWrite(L1,speeds);

digitalWrite(L2,LOW);

 

analogWrite(R1,speeds);

digitalWrite(R2,HIGH);

delay(time);

 

digitalWrite(L1,LOW);

digitalWrite(L2,LOW);

 

digitalWrite(R1,LOW);

digitalWrite(R2,LOW);

}

 

void gLF()

{

analogWrite(L1,speeds/2);

digitalWrite(L2,LOW);

 

analogWrite(R1,speeds);

digitalWrite(R2,LOW);

delay(time);

 

digitalWrite(L1,LOW);

digitalWrite(L2,LOW);

 

digitalWrite(R1,LOW);

digitalWrite(R2,LOW);

}

 

void gRF()

{

analogWrite(L1,speeds);

digitalWrite(L2,LOW);

 

analogWrite(R1,speeds/2);

digitalWrite(R2,LOW);

delay(time);

 

digitalWrite(L1,LOW);

digitalWrite(L2,LOW);

 

digitalWrite(R1,LOW);

digitalWrite(R2,LOW);

}

 

void gLB()

{

analogWrite(L1,speeds/2);

digitalWrite(L2,HIGH);

 

analogWrite(R1,speeds);

digitalWrite(R2,HIGH);

delay(time);

 

digitalWrite(L1,LOW);

digitalWrite(L2,LOW);

 

digitalWrite(R1,LOW);

digitalWrite(R2,LOW);

}

 

void gRB()

{

analogWrite(L1,speeds);

digitalWrite(L2,HIGH);

 

analogWrite(R1,speeds/2);

digitalWrite(R2,HIGH);

delay(time);

 

digitalWrite(L1,LOW);

digitalWrite(L2,LOW);

 

digitalWrite(R1,LOW);

digitalWrite(R2,LOW);

}

 

void penWrite()

{

TIMSK |= (2 << 6);

servoValue = 14;

delay(150);

delay(time);

}

 

void penRise()

{

TIMSK |= (2 << 6);

servoValue = 20;

delay(150);

delay(time);

}

 

 

 

 

 

鄭鴻旗參考資料

成大學生製作的寫字機器人

大人的科學自動手寫機

doodle bot

drawing delta

MURtle - Drawing Robot

piccolo

The Bipolar ORD Bot

http://www.trend.org/tech_info.php?pid=26

 

討論連結