相關資料連結
2010年11月23日 星期二
2010年11月19日 星期五
2010年11月18日 星期四
NXC 馬達角度Function
在NXC裡面有兩個驅動馬達角度讀取Function常常被使用 MotorTachocoCount()、MotorRotationCount(),這兩個Function差在哪裡呢???
首先看看MotorTachoCount定義:
Get motor tachometer counter.
Get the tachometer count value of the specified output.
再看看MotorRatationCount定義:
Get motor program-relative counter.
Get the program-relative position counter value of the specified output
都是取讀馬達目前位置的累計角度值這也是常被搞混的地方,但這一定有差異因為相同的Function何必寫兩次呢,其中最大的差異在
所以兩者的差異是我們在使用Function時要瞭解的地方。
以上的測試是用NXT傳送正負Power值或是正負角度值給RotateMotor函數使用時得到的結果。
如果你用手轉動驅動馬達順時針或逆時針時的結果會不一樣,因為這兩個函數讀取的角度值都相同而且是累計值加減,不會像MotorTachoCount一遇到反向就規零重新累計數值。
首先看看MotorTachoCount定義:
long MotorTachoCount | ( | byte | output | ) |
Get the tachometer count value of the specified output.
再看看MotorRatationCount定義:
long MotorRotationCount | ( | byte | output | ) |
Get the program-relative position counter value of the specified output
都是取讀馬達目前位置的累計角度值這也是常被搞混的地方,但這一定有差異因為相同的Function何必寫兩次呢,其中最大的差異在
- MotorTachoCount有方向性當馬達轉動角度一改變方向時「就會歸零」而重新累計角度值,例如當順時針轉動馬達讀取MotorTachoCount(OUT_A)的Value=500時再反向轉動30度,這時讀取MotorTachoCount(OUT_A)的Value會變成-30。
- MotorRotationCount也有方向性但當馬達轉動角度一改變方向時「不會歸零」而是減去角度值,例如當順時針轉動馬達讀取 MotorTachoCount(OUT_A)的Value=500時再反向轉動30度,這時讀取MotorTachoCount(OUT_A)的 Value會變成470。
所以兩者的差異是我們在使用Function時要瞭解的地方。
以上的測試是用NXT傳送正負Power值或是正負角度值給RotateMotor函數使用時得到的結果。
如果你用手轉動驅動馬達順時針或逆時針時的結果會不一樣,因為這兩個函數讀取的角度值都相同而且是累計值加減,不會像MotorTachoCount一遇到反向就規零重新累計數值。
2010年11月16日 星期二
驅動馬達的PID控制
樂高NXT的輸出目前是以馬達為主因此對於馬達的瞭解是非常重要的一課,實際在玩NXT有時候你對NXT下達轉90度的指令時馬達實際卻轉了100度這十度的誤差有可能影響很大,如果這類指令常用那累計的誤差值非常可觀,玩NXT想要精確的控制馬達一定要知道PID的控制原理。
研發養成所的這篇PID Speed Control 推薦一定要去看。
另外 文章中提到 NXC 沒有提供小數Float 資料型態在最新版的NXC已經支援了,以前在用NXC時也覺得不支援Float實在不方便要自己做轉換才能得到數據使用。
後來去研發養成所問了一個問題:
請問在NXC中讀取角度的Function:MotorRotationCount()、MotorTachoCount()..........都可以讀取馬達角度值...請問這兩者有何差異
再請問當我下達 RotateMotor(OUT_A,80,320) 指令後,再讀取馬達角度MotorTachoCount(OUT_A)時,往往不相同也就是馬達沒有精確的的停在320度.....請問要如何解決才能準確停在320度
-----------------------------------------------------------------
版主很熱心的回應:
MotorTachoCount()會因每次 RotateMotor 指令執行,而重置清除馬達角度值,但是 MotorRotationCount()不會,因此 MotorRotationCount()會一直累積馬達角度值,直到執行 ResetAllTachoCounts(OUT_A)才清除。
RotateMotor 指令,為 open loop 控制指令,它無法精確控制角度,會因電池電力大小或負載情形,造成角度有誤差。你可以嘗試 RotateMotorPID(OUT_A,80,320,P,I,D),P=50,I=50,D=50,這裡 PID 數值不是最佳值,您需要自行調整數值,PID控制後,才能修正回設定點。
看完回應後真是感謝版主的解釋........^_^
另一篇 J. Sluka PID 控制文章 也是一篇好文。
一定要去看看PID的計算原理你會獲益良多
研發養成所的這篇PID Speed Control 推薦一定要去看。
另外 文章中提到 NXC 沒有提供小數Float 資料型態在最新版的NXC已經支援了,以前在用NXC時也覺得不支援Float實在不方便要自己做轉換才能得到數據使用。
後來去研發養成所問了一個問題:
請問在NXC中讀取角度的Function:MotorRotationCount()、MotorTachoCount()..........都可以讀取馬達角度值...請問這兩者有何差異
再請問當我下達 RotateMotor(OUT_A,80,320) 指令後,再讀取馬達角度MotorTachoCount(OUT_A)時,往往不相同也就是馬達沒有精確的的停在320度.....請問要如何解決才能準確停在320度
-----------------------------------------------------------------
版主很熱心的回應:
MotorTachoCount()會因每次 RotateMotor 指令執行,而重置清除馬達角度值,但是 MotorRotationCount()不會,因此 MotorRotationCount()會一直累積馬達角度值,直到執行 ResetAllTachoCounts(OUT_A)才清除。
RotateMotor 指令,為 open loop 控制指令,它無法精確控制角度,會因電池電力大小或負載情形,造成角度有誤差。你可以嘗試 RotateMotorPID(OUT_A,80,320,P,I,D),P=50,I=50,D=50,這裡 PID 數值不是最佳值,您需要自行調整數值,PID控制後,才能修正回設定點。
看完回應後真是感謝版主的解釋........^_^
另一篇 J. Sluka PID 控制文章 也是一篇好文。
一定要去看看PID的計算原理你會獲益良多
2010年11月14日 星期日
樂高 NXT 敲音磚機器
前陣子買了 MindStorms NXT 8547 答應旺弟弟要組個敲音磚的機器人給他玩,因此在機構上花了許多時間一開使用直線來回的軌道方式來移動NXT到特定音階位置,實際組裝完成後發現移動的時間太久了,因此拆掉重新組裝成目前的外觀樣式,這種方式是用馬達旋轉的角度來作為特定音階位置所以速度比較快。
在琴槌方面為了要讓聲音有清脆感,所以在機械手臂上用橡皮筋綁住琴槌這樣在敲琴時有點彈性會聲音品質比較好。
這次NXT要表演「小星星」的曲目,相關樂譜的資料在維基百科有詳細說明,這首曲子好像是學樂器的入門指定曲,因為旋律簡單易懂 (只要6個音階) 相信應該難不倒樂高NXT的智慧 ...^_^
琴槌敲下的角度
琴槌舉起的樣子
在琴槌方面為了要讓聲音有清脆感,所以在機械手臂上用橡皮筋綁住琴槌這樣在敲琴時有點彈性會聲音品質比較好。
這次NXT要表演「小星星」的曲目,相關樂譜的資料在維基百科有詳細說明,這首曲子好像是學樂器的入門指定曲,因為旋律簡單易懂 (只要6個音階) 相信應該難不倒樂高NXT的智慧 ...^_^
琴槌敲下的角度
琴槌舉起的樣子
拍攝時背景音有錄到里長伯的廣播.....真是意外啊 另外NXT敲小星星時有些地方音階敲錯需要改進....但這樣的玩法蠻有趣的,第一段影片是音階定位這樣NXT機器人才知道所有的音階位置、第二段是「小星星」敲擊、最後一段很榮幸請到本次音樂指導教授旺弟弟示範正確的小星星敲法。
2010年11月10日 星期三
2010年11月8日 星期一
兩台樂高 NXT 透過藍芽傳資料
當你手上有兩台樂高 NXT 時如果可以互動的話應該會更有趣,在這個想法下又買了一台 NXT 8547 所以來試試看兩台NXT要如何互傳資料。
首先要區分誰要當Master與Slave而Master的代號是0、Slave的代號為1、2、3,因此Master只能有一台而Slave最多三台也就是連線時最多是一對三。
每一台NXT 可以接收訊息的MailBox有10個每個MailBox只能存一則訊息 ,雖然不多可是善加利用也可以做出許多不同的組合。
首先你必須先讓AB兩台NXT建立信任的藍芽連線,由A找B的話A就是Master(0)、B就是Slave(1)
再來就是Master與Slave程式碼
Master 範例
#define BT_CONN 1 //指定與第一台Slave連線
#define INBOX 1 //接收Slave傳來的資料位置
#define OUTBOX 2 //傳送到Slave的信箱位置
sub BTCheck (int conn){
if (!BluetoothStatus(conn)==NO_ERR){
TextOut(5,LCD_LINE2,"BT Error"); //無法找到 Slave時顯示錯誤訊息
Wait(1000);
Stop(true);
}
}
task main(){
BTCheck (BT_CONN); //檢查與slave之連線
int x1=0;
while(true){
if(ButtonPressed(BTNCENTER, false)){ //按下中間 Enter鈕時送出訊息 3 到Slave
TextOut(5,LCD_LINE1,"Send Slave=3");
SendRemoteBool(BT_CONN, OUTBOX, 3);
}
ReceiveRemoteBool(INBOX, true, x1); //接收Slave信息資料「x1」
if(x1!=0){
ClearScreen();
NumOut(5,LCD_LINE3,x1); //顯示Slave傳送的數值「x1」
Wait(1000);
x1=0;
ClearScreen();
TextOut(5,LCD_LINE1,"Waiting...");
}
}
}
-------------------------------------------------------------------------------------------------------------------
Slave 範例
#define BT_CONN 0 // 對Slave而言 Master 都是連接在 0
#define INBOX 2 //這必須是 Master的OutBox信箱位置
#define OUTBOX 1 //這必須是 Master的InBox信箱位置
sub BTCheck(int conn){
if (!BluetoothStatus(conn)==NO_ERR){
TextOut(5,LCD_LINE2,"BT Error"); //無法找到 Master 時顯示錯誤訊息
Wait(1000);
Stop(true);
}
}
task main(){
BTCheck(BT_CONN);
int x2=0;
while(true){
ReceiveRemoteBool(INBOX, true, x2); //檢查信箱是否有資料「x2」
if(x2!=0){
ClearScreen();
NumOut(5,LCD_LINE3,x2); //顯示資料「x2」
Wait(1000);
x2=0;
ClearScreen();
TextOut(5,LCD_LINE1,"Waiting...");
}
if(ButtonPressed(BTNCENTER, false)){ //按下中間 Enter鈕時送出訊息 6 到Master
TextOut(5,LCD_LINE1,"Send Master=6");
SendResponseBool(OUTBOX,6); //Slave回應主機要用SendRespone
}
}
}
首先要區分誰要當Master與Slave而Master的代號是0、Slave的代號為1、2、3,因此Master只能有一台而Slave最多三台也就是連線時最多是一對三。
每一台NXT 可以接收訊息的MailBox有10個每個MailBox只能存一則訊息 ,雖然不多可是善加利用也可以做出許多不同的組合。
首先你必須先讓AB兩台NXT建立信任的藍芽連線,由A找B的話A就是Master(0)、B就是Slave(1)
再來就是Master與Slave程式碼
Master 範例
#define BT_CONN 1 //指定與第一台Slave連線
#define INBOX 1 //接收Slave傳來的資料位置
#define OUTBOX 2 //傳送到Slave的信箱位置
sub BTCheck (int conn){
if (!BluetoothStatus(conn)==NO_ERR){
TextOut(5,LCD_LINE2,"BT Error"); //無法找到 Slave時顯示錯誤訊息
Wait(1000);
Stop(true);
}
}
task main(){
BTCheck (BT_CONN); //檢查與slave之連線
int x1=0;
while(true){
if(ButtonPressed(BTNCENTER, false)){ //按下中間 Enter鈕時送出訊息 3 到Slave
TextOut(5,LCD_LINE1,"Send Slave=3");
SendRemoteBool(BT_CONN, OUTBOX, 3);
}
ReceiveRemoteBool(INBOX, true, x1); //接收Slave信息資料「x1」
if(x1!=0){
ClearScreen();
NumOut(5,LCD_LINE3,x1); //顯示Slave傳送的數值「x1」
Wait(1000);
x1=0;
ClearScreen();
TextOut(5,LCD_LINE1,"Waiting...");
}
}
}
-------------------------------------------------------------------------------------------------------------------
Slave 範例
#define BT_CONN 0 // 對Slave而言 Master 都是連接在 0
#define INBOX 2 //這必須是 Master的OutBox信箱位置
#define OUTBOX 1 //這必須是 Master的InBox信箱位置
sub BTCheck(int conn){
if (!BluetoothStatus(conn)==NO_ERR){
TextOut(5,LCD_LINE2,"BT Error"); //無法找到 Master 時顯示錯誤訊息
Wait(1000);
Stop(true);
}
}
task main(){
BTCheck(BT_CONN);
int x2=0;
while(true){
ReceiveRemoteBool(INBOX, true, x2); //檢查信箱是否有資料「x2」
if(x2!=0){
ClearScreen();
NumOut(5,LCD_LINE3,x2); //顯示資料「x2」
Wait(1000);
x2=0;
ClearScreen();
TextOut(5,LCD_LINE1,"Waiting...");
}
if(ButtonPressed(BTNCENTER, false)){ //按下中間 Enter鈕時送出訊息 6 到Master
TextOut(5,LCD_LINE1,"Send Master=6");
SendResponseBool(OUTBOX,6); //Slave回應主機要用SendRespone
}
}
}
訂閱:
文章 (Atom)