口丁寫字童子

介紹

設計理念

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

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

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

材料

 

工具

製作過程

  1. 兩邊出力輪軸心  與筆 最好在同一圓週上,  可以簡化程式 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

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

另一支的影片:

https://youtu.be/gQGjqP5G1oE

整理:製造組裝說明手冊

運作方式

機構

連線與遙控

程式碼

penWriting

 //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

討論連結