2008年11月30日 星期日

機械手臂控制篇(8) -- 通訊連線動作篇

測試的過程不要急躁

先從改變一個SERVO的信號開始就好



1977649468

在AccessPort上鍵入"00" "FF"

再按下[發送資料]



1977649469

在示波器上會看到這樣的波形

黃色是UART的信號

而粉紅色是PWM改變後的寬度

這樣看也許體會不到

再看一張送"00" "01"的圖



1977649470

有看到了嗎?

SERVO的PWM寬度明顯縮小了!!!



有發現我送信號都是送"00" "XX"嗎?

這就是在程式中加入歸零的好處

我可以每次都改變SERVO1的PWM就好

不用一次都改變四個SERVO的值

當然如果要改到後面的SERVO還是要四個一起送

但在測試時

這樣就可以節省不少時間唷~~~



不過通訊碼當然不能只是這麼簡單

未來改版再慢慢考慮編碼的問題

現下先讓信號正確就好



1977649471

接下來把SERVO1~4的測棒都接上

實際看一下信號的改變

在這裡所輸入的數值都是16進位的唷

請自行用工程型的小算盤換算一下



1977649472

看到了嗎?

四組SERVO的信號改變了!!!



1977649473

再換一組數值看看



1977649474

不錯吧!!

連線成功~~~~

可以開始撰寫pc的操作介面了!!!



ps.

記得剛剛說過的嗎?

不要急躁!!

如果現在你急著接到SERVO上看動作

很可能還是會有災難發生唷~~~



驗證步驟是要按步就班的

今天先到此為止囉!!

機械手臂控制篇(7) -- 通訊硬體改裝篇

因為手邊沒有更完整的板子

所以只好自己拼裝

還記得之前介紹的USB轉UART工具嗎?



現在就要透過他來進行連線的測試囉

在這之前要先作個小改裝



1977649463

這一張是轉接板要焊上的跳線

記得要把TxD與GND都接上MCU的RxD與GND唷

這樣信號才有參考準位

不然如果只接TxD與MCU的RxD

那是一定不會通的!!!

(會亂入~~~)



1977649464

MCU這端的接線就是這樣

有空一點再把線路圖整理出來給大家看



1977649465

連好之後就像這樣

同時把示波器跟測棒也準備好





到此我們就可以開始進行測試了

在旗威論壇中有介紹一套很好用的[AccessPort]

底下就來試用一下

順便提供一下download的地方好了

[AccessPort下載]



1977649466

首先要設定一下COMPORT的位址

可以從裝置管理員中的連接埠找到

我的是COM4

所以就選COM4

鮑率按照前一篇程式所設定的9600,N,8,1



1977649467

從PC上送出資料後

確認TxD腳位上有信號出來

這樣就算OK了~~~~

接下來要測試SERVO信號囉!!!





ps.

如果您在示波器上看不到這個信號

那有下列幾種可能



1. 示波器的觸發準位設定不對



2. 確認MCU的程式中設定IO狀態是對的, UART的功能有確實被打開



3. 兩邊的GND是否有接上?沒有共地信號是會亂掉的....



4. 其它狀況請回應讓我知道, 我來幫您看看~~~  ^+++++^

機械手臂控制篇(6) -- 通訊測試MCU程式篇

終於要開始寫通訊了

相信這一段是很多人心中的痛

並不是通訊連不上

而是連上了卻不正確動作



其中有很多設定的部分是要重覆確認的(Double Check)

程式的中斷也是很重要的部分

更重要的是程式的編碼組成



為了簡化程式困難度

所以我採用四個Byte 的通訊

每個Byte以1~255來決定SERVO的角度

而0是一個特別指令

用來將信號歸零用

這個功能的優點

大家稍後就會知道了~~~



先來看看程式吧!!

//-----------------------------------------------------------------------------

// ROBO_ARM.c

//-----------------------------------------------------------------------------

// AUTH: Nichal

// DATE: 2008/11/30

//

// Target: C8051F30x

// Tool chain: KEIL C51 6.03 / KEIL EVAL C51

//



//-----------------------------------------------------------------------------

// Includes

//-----------------------------------------------------------------------------



#include // SFR declarations



//-----------------------------------------------------------------------------

// 16-bit SFR Definitions for 'F30x

//-----------------------------------------------------------------------------



sfr16 DP = 0x82; // data pointer

sfr16 TMR2RL = 0xca; // Timer2 reload value

sfr16 TMR2 = 0xcc; // Timer2 counter



//-----------------------------------------------------------------------------

// Global CONSTANTS

//-----------------------------------------------------------------------------



#define SYSCLK 24500000 // SYSCLK frequency in Hz

#define BAUDRATE 9600 // Baud rate of UART in bps

#define SAMPLE_RATE 50 // Sample frequency in Hz

#define SERVO1_PWM SERVO1=1

#define SERVO2_PWM SERVO2=1

#define SERVO3_PWM SERVO3=1

#define SERVO4_PWM SERVO4=1



#define TMH (65536-(SYSCLK/12/SAMPLE_RATE))/256

#define TML (65536-(SYSCLK/12/SAMPLE_RATE))%256



#define MAX_ANGLE 62200

#define MIN_ANGLE 12400

#define MID_ANGLE 37300



sbit SERVO1 = P0^0;

sbit SERVO2 = P0^1;

sbit SERVO3 = P0^2;

sbit SERVO4 = P0^3;



//-----------------------------------------------------------------------------

// Function PROTOTYPES

//-----------------------------------------------------------------------------



void SYSCLK_Init (void);

void UART0_Init (void);

void UART0_ISR (void);

void PORT_Init (void);

void Timer0_Init (void);

void Timer0_ISR (void);

void Timer2_Init (void);

void Timer2_Switch (unsigned int counts);

void Timer2_ISR (void);



//-----------------------------------------------------------------------------

// Global VARIABLES

//-----------------------------------------------------------------------------



bit start_flag;

bit change_flag;

unsigned char servo_counts;

unsigned int S[4]={MID_ANGLE,MID_ANGLE,MID_ANGLE,MID_ANGLE};

//-----------------------------------------------------------------------------

// MAIN Routine

//-----------------------------------------------------------------------------



void main (void)

{

// Disable Watchdog timer

PCA0MD &= ~0x40; // WDTE = 0 (clear watchdog timer enable)

SYSCLK_Init (); // initialize oscillator

PORT_Init (); // initialize crossbar and GPIO



Timer2_Init ();

Timer0_Init ();

start_flag=0;

change_flag=0;

servo_counts=0;

UART0_Init ();

EA=1;



while (1)

{

if (start_flag)

{

start_flag=0;

SERVO1_PWM;

Timer2_Switch(S[0]);



while (change_flag==0);

change_flag=0;

SERVO2_PWM;

Timer2_Switch(S[1]);



while (change_flag==0);

change_flag=0;

SERVO3_PWM;

Timer2_Switch(S[2]);



while (change_flag==0);

change_flag=0;

SERVO4_PWM;

Timer2_Switch(S[3]);



while (change_flag==0);

change_flag=0;

// add new servo here

}

}

}



//-----------------------------------------------------------------------------

// Initialization Subroutines

//-----------------------------------------------------------------------------

//-----------------------------------------------------------------------------

// SYSCLK_Init

//-----------------------------------------------------------------------------

//

// This routine initializes the system clock to use the internal 24.5MHz

// oscillator as its clock source. Also enables missing clock detector reset.

//

void SYSCLK_Init (void)

{

OSCICN |= 0x03; // configure internal oscillator for

// its maximum frequency}

RSTSRC = 0x04; // enable missing clock detector

}



//-----------------------------------------------------------------------------

// UART0_Init

//-----------------------------------------------------------------------------

//

// Configure the UART0 using Timer1, for and 8-N-1.

//

void UART0_Init (void)

{

SCON0 = 0x10; // SCON0: 8-bit variable bit rate

// level of STOP bit is ignored

// RX enabled

// ninth bits are zeros

// clear RI0 and TI0 bits

if (SYSCLK/BAUDRATE/2/256 < 1) {

TH1 = -(SYSCLK/BAUDRATE/2);

CKCON |= 0x10; // T1M = 1; SCA1:0 = xx

} else if (SYSCLK/BAUDRATE/2/256 < 4) {

TH1 = -(SYSCLK/BAUDRATE/2/4);

CKCON |= 0x01; // T1M = 0; SCA1:0 = 01

CKCON &= ~0x12;

} else if (SYSCLK/BAUDRATE/2/256 < 12) {

TH1 = -(SYSCLK/BAUDRATE/2/12);

CKCON &= ~0x13; // T1M = 0; SCA1:0 = 00

} else {

TH1 = -(SYSCLK/BAUDRATE/2/48);

CKCON |= 0x02; // T1M = 0; SCA1:0 = 10

CKCON &= ~0x11;

}



TL1 = 0xff; // set Timer1 to overflow immediately

TMOD |= 0x20; // TMOD: timer 1 in 8-bit autoreload

TMOD &= ~0xD0; // mode

TR1 = 1; // START Timer1

IP |= 0x10; // Make UART high priority

ES0 = 1; // Enable UART0 interrupts

}

//-----------------------------------------------------------------------------

// UART0_ISR

//-----------------------------------------------------------------------------

//

//

void UART0_ISR (void) interrupt 4

{

unsigned char x;



if(RI0)

{

RI0=0;

x=SBUF0;

if (x)

{

S[servo_counts]= ((unsigned int)(x)*190) + 12980;

servo_counts++;

if (servo_counts>3) servo_counts=0;

}

else servo_counts=0;

}



if (TI0) TI0=0;

}



//-----------------------------------------------------------------------------

// PORT_Init

//-----------------------------------------------------------------------------

//

void PORT_Init (void)

{

XBR0 = 0xdf;

XBR1 = 0x02;

XBR2 = 0x40;

P0MDOUT = 0xdf;

P0MDIN = 0xff;

P0 &= 0xf0;

}




//-----------------------------------------------------------------------------

// Timer0_Init

//-----------------------------------------------------------------------------

// 20mS Timer

//

void Timer0_Init (void)

{

TCON &= 0xcf; // Stop Timer0; Clear TF0

CKCON &= ~0x08; // Timer0 uses SYSCLK/12

TMOD |= 0x01; // Timer0 in 16-bit mode

TH0 = TMH; // 20mS interrupt

TL0 = TML;

ET0 = 1; // enable Timer0 interrupts

TR0 = 1; // Timer0 enabled

}



//-----------------------------------------------------------------------------

// Timer0_ISR

//-----------------------------------------------------------------------------

//

//

void Timer0_ISR (void) interrupt 1 // wheel signal off

{

TF0 = 0;

TH0 = TMH;

TL0 = TML;



start_flag=1;

}

//-----------------------------------------------------------------------------

// Timer2_Init

//-----------------------------------------------------------------------------

// PWM Timer

//



void Timer2_Init (void)

{

TMR2CN = 0x00;

CKCON |= 0x20;

ET2 = 0;

TR2 = 0;

}



void Timer2_Switch (unsigned int counts)

{

TMR2 = -counts; // set to reload immediately

ET2 = 1; // disable Timer2 interrupts

TR2 = 1;

}

//-----------------------------------------------------------------------------

// Timer2_ISR

//-----------------------------------------------------------------------------

//



void Timer2_ISR (void) interrupt 5

{

TF2H = 0; // clear Timer2 interrupt flag

TR2 = 0;

P0 &= 0xf0;

change_flag=1;

}





顏色與眾不同的

就是新加入或修改的部分

接下來談一談為啥要這樣規劃程式





1. 中位點的運算



大家都知道

所謂的一個Byte

指的是8 bit

由2的八次方來看

它可以代表1~256

然而實際上在MCU裡

並沒有256這個值

它所對應的是0~255



以中位點來說

(0+255)/2=127.5

如果程式碼要決定中位點

必須送出一個127.5的值

請問大家這個值要怎麼送???



答案是

我也不會!!! ^+++++++^



因為MCU的每一個值都只能定義整數

小數點是我們自己幫它加上去的!!!

如果要提高到127.5

就必須多一個Byte讓它變成65535之後

以1275去加小數點



為了讓中位點更中位

所以我用1~255來表示

又最大與最小值的間隔是62200-12400=49800

以49800/256會得到 194.xxxxxx

所以我直接取190做為每一個count的時間間隔

在UART0_ISR的程式中可以看到





2. 預防指令誤傳的法寶



同樣在UART0_ISR的程式中

有一個if (x)..... else servo_counts=0;

為什麼要加這個動作呢?



我們先分析一下這個UART的中斷裡

SERVO的值是如何被改變的:



首先是servo_counts=0

所以當你收到第一個Byte的資料後

你會把資料填在S[0]裡面

接著把servo_counts加1

再接收下一個byte

放在S[1]....

依序放完4個Byte後

servo_counts會自己歸零

完美的寫法!!!

????



如果不小心多送一個byte

會怎樣???

那災難就會發生了!!!!

因為往後所有的信號都會錯開一個Byte

送給第一個servo的信號會被第二個servo用

.......



你或許會問

怎麼可能會多送一個Byte?



我也覺得不可能

可是有時候因為信號線被誤觸

多一個或少一個信號是常有的事

這時候系統就要夠聰明

多一個防呆動作

利用0來將信號歸零後再繼續動作

確保就算這一次不小心送錯了

下一次也絕對不要一直錯下去





3. 其它部分



原則上多了一個數據陣列

用來儲存SERVO的角度

預設是停在中位點

大家看一下宣告就知道了



IO的設定要小心

F300在這方面很講究

設錯了就不會動作



大致上就這樣囉~~~

下一篇再來看看如何動作的

2008年11月29日 星期六

機械手臂控制篇(5) -- 通訊前的準備

機械手臂的前置作業已經做得差不多了

接下來就是通訊的部分了

在正式通訊之前

先來說明PC與MCU之間是如何溝通的



首先是MCU的部分

一般來說

MCU最常用的通訊功能是UART

它是透過RxD與TxD的通訊腳位進行通訊



然而PC雖然也有所謂的RxD與TxD

卻沒辦法與MCU直接溝通

因為PC的通訊界面稱為RS232

它的工作電壓是DC12V

而一般MCU是DC5V或DC3.3V

所以如果直接通訊的話

MCU馬上會罷工給你看!!!!!



那該怎麼辦?

這時候就有一種叫做RS232轉UART的工具

用來把RS232的信號準位轉變成UART的準位

這樣就可以通訊了



常見的轉換IC有MAX232 , HIN232....等等

底下提供他們的相關資料給大家參考

MAX232相關資料

HIN232相關資料





不過

隨著時代在進步

很多個人電腦已經放棄RS232介面

全面改成USB介面了

而MCU改朝換代後

很多也都內建USB的功能

這意謂著學通訊的人

要開始接受新的科技洗禮

不然很可能會慢慢變成古"懂"

(就是懂的東西都作古了!!)



雖然時代在轉變

但還是會有一些變遷性的產物

不然過去那麼多的MCU一下子失去支援

很可能全部都變成廢品

(就像無鉛的禁令一出, 很多有鉛品馬上變成廢料.....)

這比不做資源回收還恐怖!!!



這樣的產物叫做USB轉UART

在台灣最早出現的是PL-2303

這一個也是現在USB轉RS232用得最多的晶片

該晶片的驅動也已經通過微軟認證

只要上網執行Windows Update就可以完成驅動

PL-2303相關資料



全台灣第一台USB的AT89C2051燒錄器

用的也是這一個晶片

(就是小弟公司所生產的PGM2051啦)

此外

第一代的USB轉RS485轉接盒也是用這個晶片

換句話說

早期台灣很多標榜USB的產品

骨子裡並不真的是USB架構的東西

而是包了一個USB的轉換介面

讓它可以相容於USB的通訊格式

實際用的還是UART的通訊方式!!!



1977649462

這個就是第一代的USB轉RS485的片段照片

圖中黑黑的一顆SMD元件就是它的樣子



不過雖然它有這麼輝煌的豐功偉業

在公司裡也已經不再使用這個晶片了

畢竟科技真的是一直在進步

不是嗎?

現下用的晶片是Silicon Labs所出的

至於是哪一個

大家去查一查就知道啦~~~





好像又離題了

再回到主題.....





有了USB轉UART的功能

就可以讓電腦與MCU搭起友誼的橋樑

聽起來很神奇齁?

下一篇文章我們就來實際看看

到底PC與MCU到底是如何透過轉換介面通訊的

敬請拭目以待





ps.

對USB架構有興趣的朋友

有一個人你們一定要認識

讓我鄭重向各位推薦

chamber大大的網站

http://chamberplus.myweb.hinet.net/

他是USB界的神人

或者

說魔人更為恰當~~~

2008年11月26日 星期三

機械手臂控制篇(4) -- 程式基本功能PWM

下面這個程式是目前剛完成PWM基本測試的內容

使用的MCU大家應該不陌生-- C8051F300

大致上就是輪替送出PWM的功能





//-----------------------------------------------------------------------------

// ROBO_ARM.c

//-----------------------------------------------------------------------------

// AUTH: Nichal

// DATE: 2008/11/27

//

// Target: C8051F300

// Tool chain: KEIL C51 6.03 / KEIL EVAL C51

//



//-----------------------------------------------------------------------------

// Includes

//-----------------------------------------------------------------------------



#include // SFR declarations



//-----------------------------------------------------------------------------

// 16-bit SFR Definitions for 'F30x

//-----------------------------------------------------------------------------



sfr16 DP = 0x82; // data pointer

sfr16 TMR2RL = 0xca; // Timer2 reload value

sfr16 TMR2 = 0xcc; // Timer2 counter



//-----------------------------------------------------------------------------

// Global CONSTANTS

//-----------------------------------------------------------------------------



#define SYSCLK 24500000 // SYSCLK frequency in Hz

#define BAUDRATE 9600 // Baud rate of UART in bps

#define SAMPLE_RATE 50 // Sample frequency in Hz

#define SERVO1_PWM SERVO1=1

#define SERVO2_PWM SERVO2=1

#define SERVO3_PWM SERVO3=1

#define SERVO4_PWM SERVO4=1




#define TMH (65536-(SYSCLK/12/SAMPLE_RATE))/256

#define TML (65536-(SYSCLK/12/SAMPLE_RATE))%256



#define MAX_ANGLE 62200

#define MIN_ANGLE 12400

#define MID_ANGLE 37300



sbit SERVO1 = P0^0;

sbit SERVO2 = P0^1;

sbit SERVO3 = P0^2;

sbit SERVO4 = P0^3;




//-----------------------------------------------------------------------------

// Function PROTOTYPES

//-----------------------------------------------------------------------------



void SYSCLK_Init (void);

void PORT_Init (void);

void Timer0_Init (void);

void Timer0_ISR (void);

void Timer2_Init (void);

void Timer2_Switch (unsigned int counts);

void Timer2_ISR (void);



//-----------------------------------------------------------------------------

// Global VARIABLES

//-----------------------------------------------------------------------------



bit start_flag;

bit change_flag;

unsigned char servo_counts;



//-----------------------------------------------------------------------------

// MAIN Routine

//-----------------------------------------------------------------------------



void main (void)

{

// Disable Watchdog timer

PCA0MD &= ~0x40; // WDTE = 0 (clear watchdog timer enable)

SYSCLK_Init (); // initialize oscillator

PORT_Init (); // initialize crossbar and GPIO

Timer2_Init ();

Timer0_Init ();

start_flag=0;

change_flag=0;

servo_counts=0;

EA=1;



while (1)

{

if (start_flag)

{

start_flag=0;

SERVO1_PWM;

Timer2_Switch(MID_ANGLE);



while (change_flag==0);

change_flag=0;

SERVO2_PWM;

Timer2_Switch(MID_ANGLE);



while (change_flag==0);

change_flag=0;

SERVO3_PWM;

Timer2_Switch(MID_ANGLE);



while (change_flag==0);

change_flag=0;

SERVO4_PWM;

Timer2_Switch(MID_ANGLE);



while (change_flag==0);

change_flag=0;

// add new servo here



}

}

}



//-----------------------------------------------------------------------------

// Initialization Subroutines

//-----------------------------------------------------------------------------

//-----------------------------------------------------------------------------

// SYSCLK_Init

//-----------------------------------------------------------------------------

//

// This routine initializes the system clock to use the internal 24.5MHz

// oscillator as its clock source. Also enables missing clock detector reset.

//

void SYSCLK_Init (void)

{

OSCICN |= 0x03; // configure internal oscillator for

// its maximum frequency}

RSTSRC = 0x04; // enable missing clock detector

}



//-----------------------------------------------------------------------------

// PORT_Init

//-----------------------------------------------------------------------------

//

void PORT_Init (void)

{

XBR0 = 0xff;

XBR1 = 0x00;

XBR2 = 0x40;

P0MDOUT = 0xff;

P0MDIN = 0xff;

P0 = 0;

}



//-----------------------------------------------------------------------------

// Timer0_Init

//-----------------------------------------------------------------------------

// 20mS Timer

//

void Timer0_Init (void)

{

TCON &= 0xcf; // Stop Timer0; Clear TF0

CKCON &= ~0x08; // Timer0 uses SYSCLK/12

TMOD |= 0x01; // Timer0 in 16-bit mode

TH0 = TMH; // 20mS interrupt

TL0 = TML;

ET0 = 1; // enable Timer0 interrupts

TR0 = 1; // Timer0 enabled

}



//-----------------------------------------------------------------------------

// Timer0_ISR

//-----------------------------------------------------------------------------

//

//

void Timer0_ISR (void) interrupt 1 // wheel signal off

{

TF0 = 0;

TH0 = TMH;

TL0 = TML;



start_flag=1;

servo_counts=0;

}

//-----------------------------------------------------------------------------

// Timer2_Init

//-----------------------------------------------------------------------------

// PWM Timer

//



void Timer2_Init (void)

{

TMR2CN = 0x00;

CKCON |= 0x20;

ET2 = 0;

TR2 = 0;

}



void Timer2_Switch (unsigned int counts)

{

TMR2 = -counts; // set to reload immediately

ET2 = 1; // disable Timer2 interrupts

TR2 = 1;

}

//-----------------------------------------------------------------------------

// Timer2_ISR

//-----------------------------------------------------------------------------

//



void Timer2_ISR (void) interrupt 5

{

TF2H = 0; // clear Timer2 interrupt flag

TR2 = 0;

P0 = 0;

change_flag=1;

}





看完一大片程式碼

有沒有眼花撩亂

沒關係

改看看輸出的波形測試



1977649456

程式中的Timer0是用來產生歸零動作的

也就是所謂的20mS信號

不過因為內部振盪器的誤差

所以實際值只有19.7mS

這個值是可以調整的

只是因為我的需求到這樣就夠了

所以就沒有再修過



1977649457

看看這一張

非常準確的1.5mS

代表信號是真的可以修得非常準的

只是需不需要修到這麼準罷了!!

這個信號是用MID_ANGLE的參數所產生的波形



1977649458

而這一張0.5mS(500uS)

則是用MIN_ANGLE所產生的波形



1977649459

再來看一張2.5mS

是用MAX_ANGLE所產生的波形





1977649460

為了看看輪替輸出的樣子

把所有的測棒通通都接上控制板



1977649461

這就是最後輸出的樣子

因為只有四根測棒

所以先開4CH的PWM給大家看看就好



其實這一類的程式

很多網頁或書籍都有說明跟範例

不過絕大多數會用同一個埠來輪替輸出

以運算的方式強制從該埠的第0腳到第7腳輸出

然而對於腳位較少

而且腳位分布不固定的MCU

(例如一個埠只有0,3,4,6,7這幾隻腳)

這樣的寫法會比較有彈性

只要每增加一個 SERVO

在程式的最前方宣告一下

#define SERVOX_PWM SERVO1=1

sbit SERVOX=腳位;


然後再到主程式裡

標記// add new servo here的地方

再加上一段程式碼

************************************

SERVOX_PWM;

Timer2_Switch(MID_ANGLE);



while (change_flag==0);

change_flag=0;

************************************


這樣就可以再新增一組控制項(多一組PWM出來)

其中MID_ANGLE的參數是可以修正的

對應到的是實際需求的角度信號



有了這個基本功能後

接下來就要加入通訊功能

這樣才有辦法透過PC來控制多變的機械手臂動作

敬請期待~~~



ps.

最近工作比較忙

沒辦法天天更新

請大家多多包涵

2008年11月25日 星期二

MCU -- 2007市占率十大排行

這是最近參加研討會之後

才花了點時間了解一下現在MCU的市場分布狀況

以前一直知道在台灣以8051, PIC, AVR各佔苗頭

但全球的分布就不是很清楚

這個統計一出來

才發現台灣算是小眾市場

有一些市佔率很高的MCU

我們連聽都沒聽過

更别說用過了!!!





先來看一下排行榜吧

1. Renesas  瑞薩科技

2. Freescale 飛思卡爾

3. Microchip

4. NEC

5. Infineon 英飛凌

6. Toshiba 東芝

7. Atmel

8. samsung 三星

9. NXP

10. ST 意法半導體





看過瑞薩的datasheet

我一點都不意外它的市佔率達世界第一(23%)

因為從精準而詳盡的規格裡

我看到了有條不紊而且沒有模擬兩可的文字

那是我所看過最精采的datasheet



而Microchip與Atmel都上榜了

這說明8051, AVR, PIC 應該都榜上有名

比較意外的是Motorola不見了

(Freescale好像是由Moto所分出來的MCU部門)

(另外ON也是Moto的分支, 不過比較偏邏輯數位與被動元件)



很多人在用的飛利浦8051

看起來也不在榜單上....



而那些不太熟悉的廠商名字

有蠻多是應用在車用市場的!!!

這說明了什麼?



我唯一的感想是

台灣真的很小

雖然很厲害

但還是很渺小

在這樣一個渺小的地方

還搞一堆紛爭與分裂

真的是很丟臉



學學瑞薩

學學那些在商場上屹立不搖的鉅子們

我們連進步的時間都不夠用了

哪裡還有時間退步呢??



最後

有沒有人要預測一下2008年的排名?

如果猜中的有精美小禮物一份

只要前三名就好

範圍太大可能比樂透還難猜!!

截止日到聖誕節為限

請大家把握機會~~~





*********************************************

好像參加的人沒有很熱絡呀?!

放到置頂好了

免得都忘了這件要送禮物的事~~~~

(2008/12/9 更新)

2008年11月23日 星期日

充電一下 -- PID控制原理

在機器人的控制方法中

PID理論是被廣泛應用的

然而什麼叫PID?



可以參考一下這篇文章

PID控制的原理



文章中所提到的內容比較偏理論

讓我用實際動作的概念再解說一次



就拿最近在進行的SERVO測試當範例好了

SERVO的動作就直覺來看

就是我送給它PWM的寬度多少

它就停在對應的角度上

對吧?!



假設SERVO現在的位置在90度

而我送了一個1.5mS的信號要他回到0度

以PID的概念來解說

它會怎麼動作呢?



1. 比例控制(P)

如果用比例控制(P)

意思就是當誤差值有多大

我的驅動信號就送多大

現在是角度相差90度

所以我驅動信號就全開

(以PWM來說就是duty 100%)



過一小段時間後

我們會持續檢查SERVO現在的角度

如果第二次檢查發現它已經停在45度的位置了

所以驅動信號就變成原來的一半

(duty 50%)



等到SERVO停到定位了

因為沒有誤差了

所以驅動信號就關掉了....



2.比例控制(P) + 積分控制 (I)

不管是I或是D的控制

都必須搭配P的控制來進行

單純的I與D控制是沒有意義的

因為沒辦法將誤差值縮小

所以談到I控制

也就是談PI控制的意思



在SERVO中

PI控制很少用

因為當誤差進入0 之後

很少有機會自己把誤差值變大!!

也因此很多控制器並沒有加上這樣的控制方法

然而

當SERVO因為負載變動的關係

讓定位進入一種來回振盪的情況時

加入PI控制才能抑制這樣的現象



I的控制就是不斷地將振盪時產生的誤差累積

乘上一個積分常數後

產生一個驅動信號來逼近0誤差的位置



3.比例控制(P) + 微分控制(D)

文章中有提到

在慣性力遲滯現象較明顯的系統

一定要用PD的方式進行控制

原因在於驅動信號的增減效果並不會立即反應在動作上

如果按照比例的概念控制

會導致SERVO進入誤差0的位置時

系統還持續原來的慣性力

讓誤差加大

因為先前的驅動信號能量來得比較晚



拿原來P控制的例子

開始是90度

目標是0度

一開始全開duty 100%

第二次再檢查誤差的時候

發現是60度

然而依比例的概念

此時應該已經到達45度的位置

這就是系統的能量遲滯的效果

如果您根據原來P的概念

繼續送給它duty 67% (2/3) 的能量

那麼它就會多出 17%的能量

在越靠近誤差0的時候釋放出來!!



所以此時可以觀察誤差變化量

乘上一個微分常數

將多出來17%的能量拿掉

如此一來

SERVO就可以順利進入誤差0的位置

而不會衝過頭了!!!



4.比例控制(P) + 積分控制(I) +微分控制(D)

前面已經介紹過P, I, D 控制的方法

在什麼情況下會將這三種控制同時用在一個系統上呢?

就是系統具有慣性遲滯現象

同時負載又隨時在變動的系統!!!



一般來說

只是控制單一個SERVO

負載往往是固定的

可是機器人身上的SERVO一掛就是好幾個

當某幾個SERVO同時運作的時候

會產生機器人本身的動量負載改變

此時就不能再用固定負載的觀念來控制SERVO

不然機器人動起來就會卡卡不順



這時候

高階一點的SERVO或許一樣不會加入PID的控制

它還是原有的PD控制系統

管好自己的慣性力就好

但它會設法將位置回授給您的主控制系統

讓您的系統來計算這個動量的改變

進而把I的控制也加到系統中



這也就是KONDO SERVO與Hitec SERVO之所以會這麼貴的原因了!!!





以上

雖然還是純理論的敘述

但是我用比較實用一點的應用來說明

希望大家有聽懂....

如果我有說錯的地方

也請不吝批評指教



套句柯南常說的名言

真相永遠只有一個!!!

2008年11月21日 星期五

機械手臂控制篇(3) -- 控制電路的規劃

使用越低階的SERVO

電源的管制是越重要的

高階的SERVO會把電源的穩定性考慮進去

因而內建限流及穩壓的線路

但低階SERVO為了成本考量

在這方面的設計就變得比較粗糙

我們常抱怨的馬達抖動

很可能是在電源變動時造成的



1977649455

這是一個控制電路的示意圖

以8051來說

剛開機時的輸出一定是High(高位準)

透過反相器可以避開假信號所造成的誤動作(另一個抖動的原因)

不過信號要改成圖中反相送出的方式



電源端加上一個開關

是為了避開之前所提到的

當同時很多SERVO一起通電

會降低供應電壓

導致MCU的電壓不足

而當機發生誤動作



但是

如果您採用分開電源的管理

就是將MCU控制端與馬達出力端的電源分開

那這個影響就比較小

可以再省下開關元件(但就會多一組電源)



由於我的手臂有六個SERVO

而7414剛好也有六組反相器

不然單一SERVO可以用電晶體取代就好



這樣的電路設計

其實是針對目前我所用的SERVO所規劃

有些高階的SERVO只要單純灌一組pulse就可以了

其它都不用考慮

一分錢一分貨啦!!!

機械手臂控制篇(2) -- 活動角度的確認








在控制之前

確認機械手臂的活動角度是很重要的!!



放上一個影片給大家瞧瞧

我的手臂是全角度都沒有干涉的唷!!

(因為唯一會干涉的手掌昨天被我玩壞了!! Orz...)



測試的工具就是PWM測試儀

而且很猛的是

我只用一根pin的信號同時控制五個servo



不過請記得要開機前

所有的SERVO線要先移除

不然一開機災難就來了!!!

(我的手掌就是在這種情況下陣亡的)



開機後

請一個一個servo慢慢加上去

同軸的兩個SERVO要一起上

免得手臂被扯斷

2008年11月20日 星期四

機械手臂控制篇(1) -- MCU的選用

1977649452

這塊板子就是我即將用在手臂上的控制板

會有上下兩層

先給大家預覽一下~~~



1977649453

沒看到MCU??

在背面啦!!!



這個就是傳說中的F300

內容是8051 Base

有興趣的可以去查查看datasheet



電源的部分還沒確定

應該會用電池直接驅動



先到這裡

留給大家一些想像的空間~~~

^+++++++^

2008年11月19日 星期三

MCU -- Silicon Labs MCUs (2)

今天去參加了PIC的研討會

就像Edison所說的

真的收穫很多

然而這樣多的收穫裡

讓我更確定當初選用Silicon Labs的MCU是很明確的選擇!!

不過這並不是在說PIC不好唷~~

而是證明PIC很好很用心

看下去就知道為什麼了~~~





先來幾張研討會戰利品的特寫

1977649448

這個是有獎徵答的小禮物

挺有質感的計算尺

大廠在做廣告都不會手軟~~~

這很讓人欽佩!!



1977649449

這是研討會的主角 -- mTouch

我也買了一片~~~



1977649450

背面卯上了兩個PIC

這是mTouch的專用MCU



1977649451

這是debugger用的MCU





言歸正傳

話說近年來

PIC的8 bits MCU享有市佔率的龍頭老大地位

打破了Motorola長年來的領導地位

而且還持續在成長

小道消息說

ATxxx牌是即將收併的對象

這代表PIC是卯足了勁在衝

對使用者來說

是一項利多~~~



然而在8 bits MCU系列裡

PIC最近才打算進入量產的幾個時代性產品中

有幾項功能是Silicon Labs在一推出MCU時

就已經全系列通通都具備了

當然這不能怪PIC後知後覺

而是Silicon Labs出生得比PIC晚

所以PIC有的包袱他沒有而已

讓我依序說明這些內容吧!!





1. Low Pincount Serial Function (小包裝串列通訊功能)



PIC早期的MCU

只要是腳位不足20 pins的

應該都沒有串列功能

對於串列有重度使用的我來說

這是完全沒辦法接受的事實~~~

那就等於是一代武林高手被費了武功一樣痛不欲生



然而PIC最近announce的小包裝MCU

在明年第一季會正式量產的編號裡

串列已經被列進來了~~~

這證明PIC了解自己的市場弱點

並加以強化的第一彈





2. 硬體debug線路



這個功能也是最近幾年才被大量使用

最早期的名稱叫JTAG

是一種埋在MCU裡的硬體中斷電路

它可以透過通訊與硬體中斷的方式

即時抓取正在動作中的暫存器資料

這項技術在以往只存在高階的MCU中

一般8 bits的MCU根本就不可能有



所以開發者往往必須買價格昂貴的ICE來進行除錯

特別是針對剛入門的人來說

這是一個很重的負擔

過去幾年

我們公司都在教育使用者如何不透過ICE進行除錯的技巧

而UART就是我們最常用的功能之一



再回到主題



為了縮小開發成本

所以在MCU裡內建debug功能就變成了產品的優勢

一來大量降低下載工具的成本

二來縮短除錯的時程

這樣的硬體電路

在Silicon Labs的小包裝MCU中

是自家開發的叫做C2功能

換句話說

Silicon Labs的MCU也是全系列內建硬體除錯電路



有人質疑

這樣不是會增加die的成本

難怪MCU都賣得比人家貴?!

個人覺得

如果你把一萬支一元手機跟一支萬元手機比

那一支手機的性價比較高?



因為這樣的大環境趨勢

PIC也把這個功能加入全系列新推出的MCU裡

這也是大家現在可以用到很便宜的download工具的主要原因

因為電路通通利用半導體製程塞到MCU裡面去了



PIC唯一甩不開的包袱

是OTP的MCU

因為OTP只能燒寫一次

即便能抓bug也沒辦法修改

所以在OTP系列裡就沒有這樣的功能了

只有flash base的才有





3. Peripheral Pin Support(PPS) VS. Crosebar (XBR)



PIC在小包裝MCU中強力推打的重點功能裡

有一項PPS的功能

他是針對MCU功能夠多但IO pin無法靈活應用時

對這樣的需求進行補救的一項技術

它可以將有需要的功能指定到期望的腳位上

比方說

原來pin3的功能是UART-TX與SPI-DATA腳共用

如果我拿來當UART

SPI就被犧牲掉

但其它多餘的腳卻又用不上.....



此時透過PPS可以彌補這樣的缺憾

因為PPS可以把需求的功能

指定到自己想要的腳位上

充分應用每一隻IO



然而這樣的技術

Silicon Labs的MCU應該是首創先例

以Crossbar的技術將這樣的功能導入MCU裡

在已經慣用Silicon Labs的我來說

對這樣的功能並沒有特別的新意

卻有一種英雄所見略同的感受!!

大廠懂得積極將市面上最受歡迎的主流技術引入自己的產品線

用來確保自己的身家地位

這證明PIC是有心要做好MCU

像我這樣忠實的51使用者

都很心動想試試看

更別提可能是第一次聽過的初心者~~~





4. 無可比擬的超高速 25MIPS ~ 100MIPS



研討會中提到PIC在小包裝的MCU裡

已經有高達16MIPS的RISC MCU

對這樣的數據

在長時間被25MIPS的MCU洗禮過後

其實感受不到震撼

雖然PIC最高階的MCU有號稱高達80MIPS的超高時脈

但改版過的51(Silicon Labs MCUs)

推出之初就有亮眼的100MIPS MCU系列

雖然要價不菲

但卻是一個很強烈的指標展示

因為這樣的MCU

強悍度直逼DSP!!!





5. 開發工具超共用特好用



其實開發工具對每一個工程師所忠實的MCU來說

應該都是很好用的

但是Silicon Labs擺明不想賺你download工具的錢

因為現下一條USB download cable要價不到NT$1000

且全系列MCU通用

(PIC也做不到, 還是老話一句, 他有舊的包袱但Silicon Labs沒有)

除錯功能全部在IDE介面裡

而且C compiler還是老牌老字號的Keil C

處理出來的code超精簡

幾乎跟用組語寫的不相上下!!!

缺點是試用版有空間限制

但想必大家早就有正式版的在用了

直接把路徑順過去就好了



這就是MPLAB稍微落後一點的

因為程式的最佳化......

不覺得寫PIC的人

超多還是用組語在寫嗎?

特別是小包裝的......





*******************************************

好啦!!

看到這裡

PIC的愛用者請不要罵我

我說過

這不是PIC的錯

是因為PIC在MCU的亂世時代就已經在打滾

被Moto與Intel踢來踢去

好不容易才踏穩一條路

而且一直在堅持

一直在成長

這樣用心的公司

值得我們去投資

不是嗎?



然而對一個51的愛用者來說

長久以來被詬病的諸多缺點

在Silicon Labs裡找到了一條天堂之路

當然要好好表揚一下!!!





最近也會考慮投靠一下PIC

價格上

Silicon Labs的競爭性還是稍嫌不足呀!!





(2008/11/23更新)

再根據不可靠內部消息透露

收購ATxxx的計畫破盤

好像是價碼談不攏的原因

PIC在高階MCU的發展

果然還是會有點坎坷~~~~

2008年11月18日 星期二

我的DIY -- 機械手臂(結論)

要製作機器人

開始的動力很重要

如果只是一頭熱

很快熱情冷卻了

就只剩觀望的份了



為了不讓熱情冷卻

我選擇了一個有詳細機構的範例開始

從決定開始動手的那一刻

腦海裡就開始布局-- 

要買哪些材料? 

需要哪些工具?

要花多少時間?

想完成到什麼程度? 

底下就一一把這些規劃列出來給大家參考 





材料篇



這應該是大家最想知道的部分

我一共買了多少材料?



一塊2mm厚4開的壓克力板 (NT$120)

一包雙母六角柱20mm 10支裝(NT$25)

一包M3六角柱15mm 10支裝(NT$20)

一包M3六角柱10mm 10支裝(NT$20)

一包M3x6mm 塑膠螺絲  20支裝(NT$20)

一包M3x15mm 塑膠螺絲 20支裝(NT$20)

六個MG995 SERVO (NT$2100)

兩包金屬螺帽M3x2mm厚 20顆裝(NT$40)

兩包金屬螺絲M3x10mm長 20支裝(NT$40)

一包泡綿雙面膠 (NT$24)

一包捲式結束帶10M (NT$62)

一包束線 100入 (NT$15)



以上就是完整的材料清單





工具篇



之前的文章有報告過一小部分

在這裡重新再整理一次



鋼尺30CM長 (NT$30)

洞洞尺 16CM長 (NT$26)

銼刀組--圓, 半圓, 三角, 正方, 長方 各一把(NT$400)

手工小電鑽(NT$500)

壓克力刀(NT$125)

研磨組(NT$125)

線鋸含三鋸 (NT$95)

小鋼丸(NT$85)

小鑽頭1.5mm (NT$15)

鑽頭組 2.0 - 2.5- 3.0 - 3.2 - 3.5 - 4.0 - 4.5 - 4.8 - 5.0 - 6.0mm(NT$400)

砂紙兩張240目, 400目 (NT$20)

十字螺絲起子 (NT$35)

斜口鉗(NT$300)

平口鉗(NT$200)

投影片兩張(NT$6)

細字簽字筆(NT$15)

變形尺(NT$130)

圓規(NT$???)真的忘了....



PWM測試儀(NT$1000)



以上為總工具清單



如果有發現我漏掉沒寫

再提醒我一下





進度篇



其實我有給自己一個壓力

就是一個星期內完成

每天大約2~3小時的時間

利用下班後用完餐陪小孩子睡覺後

再挪出來的時間

所以動工的時間大概就在20小時左右

但思考所花費的時間更多

至少多一倍



圖的部分

是請太太用掃瞄器掃到電腦後

再排版印出來的

這部分大概要一個上午的時間



而找尋材料其實也挺耗時

大約10小時左右

簡單說

就是上網看看那些材料店離家近又開得晚

因為我要下班才有辦法去買

上班就是專心上班的事

這樣下班才不會有心理負擔~~~





加工組裝篇



有人問說

為什麼不把圖面發給人家加工

自己再回來組裝就好了?



為了想更清楚了解壓克力的加工特性

未來在畫圖時該如何設計機構外觀與鑽孔的位置比例

為了想更親近每一個工件

看著他們從無到有一個個由自己的手做出來的感覺

為了瞭解當加工工件發生誤差時

自己可以如何修補如何改正如何力挽狂瀾搶救雷恩大兵....



就這樣

我決定全部自己來

也因為這樣

我又多了不少的加工經驗

更懂得如何使用工具

更懂得如何即時修正需要更改的工件



雖然帶眼鏡

眼睛還是會被壓克力屑噴到

雖然皮很粗

還是會不小心被工件扎到流血

手指上滿是粗糙的刮痕

光腳踩著有的沒有碎屑



結果是甘甜的!!!

因為經過了那一連串的辛苦......



DIY才是王道!!!





以上

報告完畢~~~



ps. 

有興趣DIY完成這個加工組裝的人

可以和我交換一下心得唷~~~ 

祝您順利!!!

2008年11月17日 星期一

我的DIY -- 機械手臂(10)

昨天下班頭暈腦漲

休息了一晚

一早起來趕工

暫時先擱下新機構不談

決定還是先把原來的舊機構完成

哪怕變"獨指"夾具也無妨

至少先告一個段落



1977649442

先來看看"失敗"的加工作品吧



其實就加工步驟來說

這個程序應該是OK的

看看圖中的加工方式

我是先在齒根的地方先鑽孔(圖中下面的工件)

然後再切除多餘的部分進行修邊(圖中上面的工件)

很可惜的是

長牙的部分就是沒長好....

唉唉~~~ Orz...



1977649443

至於對稱加工法

這個是方法之一

先將切割下來的工件鑽一個孔(只要一個就好唷)

接下來將兩片工件對鎖

同時把另一個孔對齊後鎖死

再用鑽孔機鑽第二孔(兩片同時鑽)

接著再一片一片依序鑽孔(不是一直加上去唷, 是每加工一次就換一片)

直到所有的工件都鑽出相對位置一模一樣的時候才停



接下來再把第一個孔用長一點的螺絲鎖死

另一個孔應該會有一些工差

這時再用鑽孔機把對齊後有一點點誤差的孔重新鑽過

就算大功告成



邊緣呢?

既然都鎖在一起了

就一起放在砂紙上磨

怎麼磨都會長得一樣啦!!!

看圖就是最好的說明囉~~~



只要對稱工件是有兩個孔以上的

我都是這樣加工的!!





1977649444

組裝好的手掌與手指

因為另一邊不具傳動作用了

所以直接鎖死在固定的位置上



1977649445

看一下底面的構造

兩個傳動齒軸是不同平面的

所以齒軸只是裝飾用



1977649446

再靠近一點看看吧!!!







最後來張大特寫

謝謝收看

(程式部分與機構修改部分即將隆重登場, 敬請期待)



1977649447

2008年11月16日 星期日

我的DIY -- 機械手臂(9)

哎哎哎....

事情沒有那麼順利的啦!!!

終於讓我最擔心的事發生了.....



最後在加工齒輪傳動的部分

完全沒辦法把齒修在吻合的角度內

不是會干涉就是咬不到齒.....

這大概是手工DIY最困擾的地方!!



不過沒關係

山不轉路轉

改用兩個9G的SERVO當夾具的傳動軸

把手掌的工件稍微改一下

應該就可以擺上兩個SERVO

各動各的總沒問題了吧!!!



明天再繼續吧

感謝各位看倌這麼捧場一直來光顧~~~


********************************************



一整晚沒睡好

除了小朋友半夜不睡從三點玩到五點多之外

還有一直在思考夾具的問題

因為如果使用兩個9G SERVO

代表我的電壓要降壓

所以比較好的作法

是保留原機構概念

但改用連桿來完成

這個構想要感謝irobot大大所給的建議

因為我去看到了這個網站上夾具機構的設計

Robot Arm Testing with Gripper attached




這樣一來

要改的是手指連桿的作法

下班後再來驗證可行性吧~~~

我的DIY -- 機械手臂(8)

1977649440



亮個相

手掌完成了....

缺零件要再出去買!!

重心有點不穩

(金屬齒的SERVO真的挺重)

考慮要把底座黏死在某塊重物上



現在的進度已經到每個軸都能順利動作

也測試過轉動的角度了



手指的部分是我最擔心的

順利的話

今天就算第一階段完成啦

不然又要再等等了.....





1977649441

本來不太想放這張圖

不過還是放一下好了

這是將最後一個SERVO鎖上之後的圖

不過因為SERVO很重

手臂一定要通電才會舉著

不然會下垂

但這也是沒辦法的事



由於壓克力厚度的錯估(原來要3mm, 我的只有2mm)

所以組裝起來手掌有一點會搖



還在思考手指要不要直接用5mm厚的板子來做?!

或是兩塊貼在一起再加工?!



總之

看到下一張圖就應該是大功告成了

祈禱吧~~~

2008年11月15日 星期六

我的DIY -- 機械手臂(7)

上一篇提到加工的問題

這一篇來補充說明一下



1977649437

看到照片中的兩份工件嗎?

下面這一份就是先前提到的加工方式

要先把所有的開孔先完成

上面那一份則是開孔完成後進行輪廓加工



其實不管是壓克力工件

或是鋁板鐵板....

如果孔位離邊緣很近的時候

在加工前都要先考慮好適當的加工方式

避免在加工過程發生悲劇



不要小看壓克力斷裂的問題

因為壓克力很脆

斷裂時很可能噴出來

好在我是眼鏡一族

所以這樣的情況有眼鏡可以保護

一般人加工盡可能帶上護目鏡

除非您不用任何的電動工具.....



1977649438



1977649439



再來看看這兩張

所有工件當中

到目前為止

就屬這個工件最耗時

而耗時的並不是加工

而是等待.....



因為要加工這個工件

必須先確認可以吻合您的SERVO

再來要用瞬間膠(快乾)黏合

而黏合並不能一次就完成

第一次黏合乾了之後

最好再補上第二次甚至第三次

確保當手臂動作時

這個工件不會從黏合處斷裂




等一切黏合完成後

還必須修飾一下邊緣

順便用手扳看看是否牢固

(但請不要太用力, 我有折斷過兩次!! Orz.....)

我的DIY -- 機械手臂(6)

1977649433

繼續昨天的工作

今天真是多災多難

先看一下完成的樣子吧



1977649434

在臂柄上是有裂縫跟斷痕的

因為在加工的順序上出的點問題

正確的作法

應該先挖好內部的洞

把該摟空的部位先挖空

最後才修輪廓



可是昨天為了要先放上機構照

就先把輪廓加工好了

今天在挖內部就困難重重



好在就算斷了

也還是可以固定

這才完成了現在這個前手臂



現在只差用雙面膠跟底座加工好

就可以把前手臂跟後手臂接上



1977649435

接起來後大概會像這樣

(先放一下示意圖給大家想像一下)








剛剛完成的(11/16)

就是這樣囉~~~

1977649436

2008年11月14日 星期五

我的DIY -- 機械手臂(5)

1977649427

今天的進度比較少

因為在考慮組裝時的一些問題

暫時先把加工一半的零件放上來讓大家過過癮

同時也讓大家瞧瞧真的全部是純手工製作



1977649428

從頭到尾都是同兩張投影片在繪圖

這才發現

書在印刷機構圖時是有誤差的

1:1 對目前即將面臨的機構來說

可能會有動作上的問題!!!

所以在繪圖時要進行小幅度的調整

加工也必須更小心

不然很可能同一個零件要重做好幾遍......



因此

對稱的機構

我會用同一張圖描繪

僅修改些微差異的部分

這樣可以避開原圖誤差的問題



1977649429

昨天因為沒有塑膠柱

所以今天才把支撐樑給補上

我是用兩個規格的柱體組合的

因為買不到那麼長的柱體



中間的部分是20mm M3 雙母

左右兩邊是15mm M3 標準柱

最外面是兩根塑膠螺絲 M3 -- 8mm



總共要兩組

價格約NT$18



1977649430

前一張看起來不夠立體

來張立體一點的照片吧

今天比較偷懶

請各位多多見諒.....




最後最後

介紹一個神兵利器


1977649431

這是大一時候買的

為了上耗時又耗資源的圖學課特地選的

以往有一把工具一直都沒動過

今次亮相登場就有很好的表現

猜猜看是哪一把???





1977649432

登登登登

就是這一把

用來畫壓克力超好用

先把紋路刻出來

再用簽字筆從上面描過

搞定!!!

2008年11月13日 星期四

我的DIY -- 機械手臂(4)

1977649423

快點更新

不然就變隔天了!!!



今天新加的兩個臂柄

有用PWM測試儀測試

同步的情況挺好

應該可以把梁鎖上了



1977649424

使用的主要工具還多了這一樣 -- 砂紙

直線切割完成後

有一堆小缺角

整片放在砂紙上用力磨

直線就變得很平滑了!!



1977649425

剛剛那張是範本

這張才是我用的

目號越小

代表砂紙越粗唷



1977649426

這張是使用的情況