測試的過程不要急躁
先從改變一個SERVO的信號開始就好
在AccessPort上鍵入"00" "FF"
再按下[發送資料]
在示波器上會看到這樣的波形
黃色是UART的信號
而粉紅色是PWM改變後的寬度
這樣看也許體會不到
再看一張送"00" "01"的圖
有看到了嗎?
SERVO的PWM寬度明顯縮小了!!!
有發現我送信號都是送"00" "XX"嗎?
這就是在程式中加入歸零的好處
我可以每次都改變SERVO1的PWM就好
不用一次都改變四個SERVO的值
當然如果要改到後面的SERVO還是要四個一起送
但在測試時
這樣就可以節省不少時間唷~~~
不過通訊碼當然不能只是這麼簡單
未來改版再慢慢考慮編碼的問題
現下先讓信號正確就好
接下來把SERVO1~4的測棒都接上
實際看一下信號的改變
在這裡所輸入的數值都是16進位的唷
請自行用工程型的小算盤換算一下
看到了嗎?
四組SERVO的信號改變了!!!
再換一組數值看看
不錯吧!!
連線成功~~~~
可以開始撰寫pc的操作介面了!!!
ps.
記得剛剛說過的嗎?
不要急躁!!
如果現在你急著接到SERVO上看動作
很可能還是會有災難發生唷~~~
驗證步驟是要按步就班的
今天先到此為止囉!!
2008年11月30日 星期日
機械手臂控制篇(7) -- 通訊硬體改裝篇
因為手邊沒有更完整的板子
所以只好自己拼裝
還記得之前介紹的USB轉UART工具嗎?
現在就要透過他來進行連線的測試囉
在這之前要先作個小改裝
這一張是轉接板要焊上的跳線
記得要把TxD與GND都接上MCU的RxD與GND唷
這樣信號才有參考準位
不然如果只接TxD與MCU的RxD
那是一定不會通的!!!
(會亂入~~~)
MCU這端的接線就是這樣
有空一點再把線路圖整理出來給大家看
連好之後就像這樣
同時把示波器跟測棒也準備好
到此我們就可以開始進行測試了
在旗威論壇中有介紹一套很好用的[AccessPort]
底下就來試用一下
順便提供一下download的地方好了
[AccessPort下載]
首先要設定一下COMPORT的位址
可以從裝置管理員中的連接埠找到
我的是COM4
所以就選COM4
鮑率按照前一篇程式所設定的9600,N,8,1
從PC上送出資料後
確認TxD腳位上有信號出來
這樣就算OK了~~~~
接下來要測試SERVO信號囉!!!
ps.
如果您在示波器上看不到這個信號
那有下列幾種可能
1. 示波器的觸發準位設定不對
2. 確認MCU的程式中設定IO狀態是對的, UART的功能有確實被打開
3. 兩邊的GND是否有接上?沒有共地信號是會亂掉的....
4. 其它狀況請回應讓我知道, 我來幫您看看~~~ ^+++++^
所以只好自己拼裝
還記得之前介紹的USB轉UART工具嗎?
現在就要透過他來進行連線的測試囉
在這之前要先作個小改裝
這一張是轉接板要焊上的跳線
記得要把TxD與GND都接上MCU的RxD與GND唷
這樣信號才有參考準位
不然如果只接TxD與MCU的RxD
那是一定不會通的!!!
(會亂入~~~)
MCU這端的接線就是這樣
有空一點再把線路圖整理出來給大家看
連好之後就像這樣
同時把示波器跟測棒也準備好
到此我們就可以開始進行測試了
在旗威論壇中有介紹一套很好用的[AccessPort]
底下就來試用一下
順便提供一下download的地方好了
[AccessPort下載]
首先要設定一下COMPORT的位址
可以從裝置管理員中的連接埠找到
我的是COM4
所以就選COM4
鮑率按照前一篇程式所設定的9600,N,8,1
從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在這方面很講究
設錯了就不會動作
大致上就這樣囉~~~
下一篇再來看看如何動作的
相信這一段是很多人心中的痛
並不是通訊連不上
而是連上了卻不正確動作
其中有很多設定的部分是要重覆確認的(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的通訊方式!!!
這個就是第一代的USB轉RS485的片段照片
圖中黑黑的一顆SMD元件就是它的樣子
不過雖然它有這麼輝煌的豐功偉業
在公司裡也已經不再使用這個晶片了
畢竟科技真的是一直在進步
不是嗎?
現下用的晶片是Silicon Labs所出的
至於是哪一個
大家去查一查就知道啦~~~
好像又離題了
再回到主題.....
有了USB轉UART的功能
就可以讓電腦與MCU搭起友誼的橋樑
聽起來很神奇齁?
下一篇文章我們就來實際看看
到底PC與MCU到底是如何透過轉換介面通訊的
敬請拭目以待
ps.
對USB架構有興趣的朋友
有一個人你們一定要認識
讓我鄭重向各位推薦
chamber大大的網站
http://chamberplus.myweb.hinet.net/
他是USB界的神人
或者
說魔人更為恰當~~~
接下來就是通訊的部分了
在正式通訊之前
先來說明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的通訊方式!!!
這個就是第一代的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;
}
看完一大片程式碼
有沒有眼花撩亂
沒關係
改看看輸出的波形測試
程式中的Timer0是用來產生歸零動作的
也就是所謂的20mS信號
不過因為內部振盪器的誤差
所以實際值只有19.7mS
這個值是可以調整的
只是因為我的需求到這樣就夠了
所以就沒有再修過
看看這一張
非常準確的1.5mS
代表信號是真的可以修得非常準的
只是需不需要修到這麼準罷了!!
這個信號是用MID_ANGLE的參數所產生的波形
而這一張0.5mS(500uS)
則是用MIN_ANGLE所產生的波形
再來看一張2.5mS
是用MAX_ANGLE所產生的波形
為了看看輪替輸出的樣子
把所有的測棒通通都接上控制板
這就是最後輸出的樣子
因為只有四根測棒
所以先開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.
最近工作比較忙
沒辦法天天更新
請大家多多包涵
使用的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;
}
看完一大片程式碼
有沒有眼花撩亂
沒關係
改看看輸出的波形測試
程式中的Timer0是用來產生歸零動作的
也就是所謂的20mS信號
不過因為內部振盪器的誤差
所以實際值只有19.7mS
這個值是可以調整的
只是因為我的需求到這樣就夠了
所以就沒有再修過
看看這一張
非常準確的1.5mS
代表信號是真的可以修得非常準的
只是需不需要修到這麼準罷了!!
這個信號是用MID_ANGLE的參數所產生的波形
而這一張0.5mS(500uS)
則是用MIN_ANGLE所產生的波形
再來看一張2.5mS
是用MAX_ANGLE所產生的波形
為了看看輪替輸出的樣子
把所有的測棒通通都接上控制板
這就是最後輸出的樣子
因為只有四根測棒
所以先開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 更新)
才花了點時間了解一下現在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之所以會這麼貴的原因了!!!
以上
雖然還是純理論的敘述
但是我用比較實用一點的應用來說明
希望大家有聽懂....
如果我有說錯的地方
也請不吝批評指教
套句柯南常說的名言
真相永遠只有一個!!!
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為了成本考量
在這方面的設計就變得比較粗糙
我們常抱怨的馬達抖動
很可能是在電源變動時造成的
這是一個控制電路的示意圖
以8051來說
剛開機時的輸出一定是High(高位準)
透過反相器可以避開假信號所造成的誤動作(另一個抖動的原因)
不過信號要改成圖中反相送出的方式
電源端加上一個開關
是為了避開之前所提到的
當同時很多SERVO一起通電
會降低供應電壓
導致MCU的電壓不足
而當機發生誤動作
但是
如果您採用分開電源的管理
就是將MCU控制端與馬達出力端的電源分開
那這個影響就比較小
可以再省下開關元件(但就會多一組電源)
由於我的手臂有六個SERVO
而7414剛好也有六組反相器
不然單一SERVO可以用電晶體取代就好
這樣的電路設計
其實是針對目前我所用的SERVO所規劃
有些高階的SERVO只要單純灌一組pulse就可以了
其它都不用考慮
一分錢一分貨啦!!!
電源的管制是越重要的
高階的SERVO會把電源的穩定性考慮進去
因而內建限流及穩壓的線路
但低階SERVO為了成本考量
在這方面的設計就變得比較粗糙
我們常抱怨的馬達抖動
很可能是在電源變動時造成的
這是一個控制電路的示意圖
以8051來說
剛開機時的輸出一定是High(高位準)
透過反相器可以避開假信號所造成的誤動作(另一個抖動的原因)
不過信號要改成圖中反相送出的方式
電源端加上一個開關
是為了避開之前所提到的
當同時很多SERVO一起通電
會降低供應電壓
導致MCU的電壓不足
而當機發生誤動作
但是
如果您採用分開電源的管理
就是將MCU控制端與馬達出力端的電源分開
那這個影響就比較小
可以再省下開關元件(但就會多一組電源)
由於我的手臂有六個SERVO
而7414剛好也有六組反相器
不然單一SERVO可以用電晶體取代就好
這樣的電路設計
其實是針對目前我所用的SERVO所規劃
有些高階的SERVO只要單純灌一組pulse就可以了
其它都不用考慮
一分錢一分貨啦!!!
機械手臂控制篇(2) -- 活動角度的確認
在控制之前
確認機械手臂的活動角度是很重要的!!
放上一個影片給大家瞧瞧
我的手臂是全角度都沒有干涉的唷!!
(因為唯一會干涉的手掌昨天被我玩壞了!! Orz...)
測試的工具就是PWM測試儀
而且很猛的是
我只用一根pin的信號同時控制五個servo
不過請記得要開機前
所有的SERVO線要先移除
不然一開機災難就來了!!!
(我的手掌就是在這種情況下陣亡的)
開機後
請一個一個servo慢慢加上去
同軸的兩個SERVO要一起上
免得手臂被扯斷
2008年11月20日 星期四
機械手臂控制篇(1) -- MCU的選用
2008年11月19日 星期三
MCU -- Silicon Labs MCUs (2)
今天去參加了PIC的研討會
就像Edison所說的
真的收穫很多
然而這樣多的收穫裡
讓我更確定當初選用Silicon Labs的MCU是很明確的選擇!!
不過這並不是在說PIC不好唷~~
而是證明PIC很好很用心
看下去就知道為什麼了~~~
先來幾張研討會戰利品的特寫
這個是有獎徵答的小禮物
挺有質感的計算尺
大廠在做廣告都不會手軟~~~
這很讓人欽佩!!
這是研討會的主角 -- mTouch
我也買了一片~~~
背面卯上了兩個PIC
這是mTouch的專用MCU
這是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的發展
果然還是會有點坎坷~~~~
就像Edison所說的
真的收穫很多
然而這樣多的收穫裡
讓我更確定當初選用Silicon Labs的MCU是很明確的選擇!!
不過這並不是在說PIC不好唷~~
而是證明PIC很好很用心
看下去就知道為什麼了~~~
先來幾張研討會戰利品的特寫
這個是有獎徵答的小禮物
挺有質感的計算尺
大廠在做廣告都不會手軟~~~
這很讓人欽佩!!
這是研討會的主角 -- mTouch
我也買了一片~~~
背面卯上了兩個PIC
這是mTouch的專用MCU
這是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完成這個加工組裝的人
可以和我交換一下心得唷~~~
祝您順利!!!
開始的動力很重要
如果只是一頭熱
很快熱情冷卻了
就只剩觀望的份了
為了不讓熱情冷卻
我選擇了一個有詳細機構的範例開始
從決定開始動手的那一刻
腦海裡就開始布局--
要買哪些材料?
需要哪些工具?
要花多少時間?
想完成到什麼程度?
底下就一一把這些規劃列出來給大家參考
材料篇
這應該是大家最想知道的部分
我一共買了多少材料?
一塊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)
昨天下班頭暈腦漲
休息了一晚
一早起來趕工
暫時先擱下新機構不談
決定還是先把原來的舊機構完成
哪怕變"獨指"夾具也無妨
至少先告一個段落
先來看看"失敗"的加工作品吧
其實就加工步驟來說
這個程序應該是OK的
看看圖中的加工方式
我是先在齒根的地方先鑽孔(圖中下面的工件)
然後再切除多餘的部分進行修邊(圖中上面的工件)
很可惜的是
長牙的部分就是沒長好....
唉唉~~~ Orz...
至於對稱加工法
這個是方法之一
先將切割下來的工件鑽一個孔(只要一個就好唷)
接下來將兩片工件對鎖
同時把另一個孔對齊後鎖死
再用鑽孔機鑽第二孔(兩片同時鑽)
接著再一片一片依序鑽孔(不是一直加上去唷, 是每加工一次就換一片)
直到所有的工件都鑽出相對位置一模一樣的時候才停
接下來再把第一個孔用長一點的螺絲鎖死
另一個孔應該會有一些工差
這時再用鑽孔機把對齊後有一點點誤差的孔重新鑽過
就算大功告成
邊緣呢?
既然都鎖在一起了
就一起放在砂紙上磨
怎麼磨都會長得一樣啦!!!
看圖就是最好的說明囉~~~
只要對稱工件是有兩個孔以上的
我都是這樣加工的!!
組裝好的手掌與手指
因為另一邊不具傳動作用了
所以直接鎖死在固定的位置上
看一下底面的構造
兩個傳動齒軸是不同平面的
所以齒軸只是裝飾用
再靠近一點看看吧!!!
最後來張大特寫
謝謝收看
(程式部分與機構修改部分即將隆重登場, 敬請期待)
休息了一晚
一早起來趕工
暫時先擱下新機構不談
決定還是先把原來的舊機構完成
哪怕變"獨指"夾具也無妨
至少先告一個段落
先來看看"失敗"的加工作品吧
其實就加工步驟來說
這個程序應該是OK的
看看圖中的加工方式
我是先在齒根的地方先鑽孔(圖中下面的工件)
然後再切除多餘的部分進行修邊(圖中上面的工件)
很可惜的是
長牙的部分就是沒長好....
唉唉~~~ Orz...
至於對稱加工法
這個是方法之一
先將切割下來的工件鑽一個孔(只要一個就好唷)
接下來將兩片工件對鎖
同時把另一個孔對齊後鎖死
再用鑽孔機鑽第二孔(兩片同時鑽)
接著再一片一片依序鑽孔(不是一直加上去唷, 是每加工一次就換一片)
直到所有的工件都鑽出相對位置一模一樣的時候才停
接下來再把第一個孔用長一點的螺絲鎖死
另一個孔應該會有一些工差
這時再用鑽孔機把對齊後有一點點誤差的孔重新鑽過
就算大功告成
邊緣呢?
既然都鎖在一起了
就一起放在砂紙上磨
怎麼磨都會長得一樣啦!!!
看圖就是最好的說明囉~~~
只要對稱工件是有兩個孔以上的
我都是這樣加工的!!
組裝好的手掌與手指
因為另一邊不具傳動作用了
所以直接鎖死在固定的位置上
看一下底面的構造
兩個傳動齒軸是不同平面的
所以齒軸只是裝飾用
再靠近一點看看吧!!!
最後來張大特寫
謝謝收看
(程式部分與機構修改部分即將隆重登場, 敬請期待)
2008年11月16日 星期日
我的DIY -- 機械手臂(9)
哎哎哎....
事情沒有那麼順利的啦!!!
終於讓我最擔心的事發生了.....
最後在加工齒輪傳動的部分
完全沒辦法把齒修在吻合的角度內
不是會干涉就是咬不到齒.....
這大概是手工DIY最困擾的地方!!
不過沒關係
山不轉路轉
改用兩個9G的SERVO當夾具的傳動軸
把手掌的工件稍微改一下
應該就可以擺上兩個SERVO
各動各的總沒問題了吧!!!
明天再繼續吧
感謝各位看倌這麼捧場一直來光顧~~~
********************************************
一整晚沒睡好
除了小朋友半夜不睡從三點玩到五點多之外
還有一直在思考夾具的問題
因為如果使用兩個9G SERVO
代表我的電壓要降壓
所以比較好的作法
是保留原機構概念
但改用連桿來完成
這個構想要感謝irobot大大所給的建議
因為我去看到了這個網站上夾具機構的設計
Robot Arm Testing with Gripper attached
這樣一來
要改的是手指連桿的作法
下班後再來驗證可行性吧~~~
事情沒有那麼順利的啦!!!
終於讓我最擔心的事發生了.....
最後在加工齒輪傳動的部分
完全沒辦法把齒修在吻合的角度內
不是會干涉就是咬不到齒.....
這大概是手工DIY最困擾的地方!!
不過沒關係
山不轉路轉
改用兩個9G的SERVO當夾具的傳動軸
把手掌的工件稍微改一下
應該就可以擺上兩個SERVO
各動各的總沒問題了吧!!!
明天再繼續吧
感謝各位看倌這麼捧場一直來光顧~~~
********************************************
一整晚沒睡好
除了小朋友半夜不睡從三點玩到五點多之外
還有一直在思考夾具的問題
因為如果使用兩個9G SERVO
代表我的電壓要降壓
所以比較好的作法
是保留原機構概念
但改用連桿來完成
這個構想要感謝irobot大大所給的建議
因為我去看到了這個網站上夾具機構的設計
Robot Arm Testing with Gripper attached
這樣一來
要改的是手指連桿的作法
下班後再來驗證可行性吧~~~
我的DIY -- 機械手臂(8)
亮個相
手掌完成了....
缺零件要再出去買!!
重心有點不穩
(金屬齒的SERVO真的挺重)
考慮要把底座黏死在某塊重物上
現在的進度已經到每個軸都能順利動作
也測試過轉動的角度了
手指的部分是我最擔心的
順利的話
今天就算第一階段完成啦
不然又要再等等了.....
本來不太想放這張圖
不過還是放一下好了
這是將最後一個SERVO鎖上之後的圖
不過因為SERVO很重
手臂一定要通電才會舉著
不然會下垂
但這也是沒辦法的事
由於壓克力厚度的錯估(原來要3mm, 我的只有2mm)
所以組裝起來手掌有一點會搖
還在思考手指要不要直接用5mm厚的板子來做?!
或是兩塊貼在一起再加工?!
總之
看到下一張圖就應該是大功告成了
祈禱吧~~~
2008年11月15日 星期六
我的DIY -- 機械手臂(7)
上一篇提到加工的問題
這一篇來補充說明一下
看到照片中的兩份工件嗎?
下面這一份就是先前提到的加工方式
要先把所有的開孔先完成
上面那一份則是開孔完成後進行輪廓加工
其實不管是壓克力工件
或是鋁板鐵板....
如果孔位離邊緣很近的時候
在加工前都要先考慮好適當的加工方式
避免在加工過程發生悲劇
不要小看壓克力斷裂的問題
因為壓克力很脆
斷裂時很可能噴出來
好在我是眼鏡一族
所以這樣的情況有眼鏡可以保護
一般人加工盡可能帶上護目鏡
除非您不用任何的電動工具.....
再來看看這兩張
所有工件當中
到目前為止
就屬這個工件最耗時
而耗時的並不是加工
而是等待.....
因為要加工這個工件
必須先確認可以吻合您的SERVO
再來要用瞬間膠(快乾)黏合
而黏合並不能一次就完成
第一次黏合乾了之後
最好再補上第二次甚至第三次
確保當手臂動作時
這個工件不會從黏合處斷裂
等一切黏合完成後
還必須修飾一下邊緣
順便用手扳看看是否牢固
(但請不要太用力, 我有折斷過兩次!! Orz.....)
這一篇來補充說明一下
看到照片中的兩份工件嗎?
下面這一份就是先前提到的加工方式
要先把所有的開孔先完成
上面那一份則是開孔完成後進行輪廓加工
其實不管是壓克力工件
或是鋁板鐵板....
如果孔位離邊緣很近的時候
在加工前都要先考慮好適當的加工方式
避免在加工過程發生悲劇
不要小看壓克力斷裂的問題
因為壓克力很脆
斷裂時很可能噴出來
好在我是眼鏡一族
所以這樣的情況有眼鏡可以保護
一般人加工盡可能帶上護目鏡
除非您不用任何的電動工具.....
再來看看這兩張
所有工件當中
到目前為止
就屬這個工件最耗時
而耗時的並不是加工
而是等待.....
因為要加工這個工件
必須先確認可以吻合您的SERVO
再來要用瞬間膠(快乾)黏合
而黏合並不能一次就完成
第一次黏合乾了之後
最好再補上第二次甚至第三次
確保當手臂動作時
這個工件不會從黏合處斷裂
等一切黏合完成後
還必須修飾一下邊緣
順便用手扳看看是否牢固
(但請不要太用力, 我有折斷過兩次!! Orz.....)
我的DIY -- 機械手臂(6)
2008年11月14日 星期五
我的DIY -- 機械手臂(5)
今天的進度比較少
因為在考慮組裝時的一些問題
暫時先把加工一半的零件放上來讓大家過過癮
同時也讓大家瞧瞧真的全部是純手工製作
從頭到尾都是同兩張投影片在繪圖
這才發現
書在印刷機構圖時是有誤差的
1:1 對目前即將面臨的機構來說
可能會有動作上的問題!!!
所以在繪圖時要進行小幅度的調整
加工也必須更小心
不然很可能同一個零件要重做好幾遍......
因此
對稱的機構
我會用同一張圖描繪
僅修改些微差異的部分
這樣可以避開原圖誤差的問題
昨天因為沒有塑膠柱
所以今天才把支撐樑給補上
我是用兩個規格的柱體組合的
因為買不到那麼長的柱體
中間的部分是20mm M3 雙母
左右兩邊是15mm M3 標準柱
最外面是兩根塑膠螺絲 M3 -- 8mm
總共要兩組
價格約NT$18
前一張看起來不夠立體
來張立體一點的照片吧
今天比較偷懶
請各位多多見諒.....
最後最後
介紹一個神兵利器
這是大一時候買的
為了上耗時又耗資源的圖學課特地選的
以往有一把工具一直都沒動過
今次亮相登場就有很好的表現
猜猜看是哪一把???
登登登登
就是這一把
用來畫壓克力超好用
先把紋路刻出來
再用簽字筆從上面描過
搞定!!!