(Fig-1)
在上圖中接上Touch Panel的為遙控端NXT,會將偵測到觸控筆在面板上的動作,製作成資料字串經由藍芽傳送給被控端的NXT機器人,而被控端NXT在接收到資料之後,會進行解析並轉換為馬達控制指令來執行。(Fig_2)
(video-1)(video-2)
在上圖中接上Touch Panel的為遙控端NXT,會將偵測到觸控筆在面板上的動作,製作成資料字串經由藍芽傳送給被控端的NXT機器人,而被控端NXT在接收到資料之後,會進行解析並轉換為馬達控制指令來執行。
(video-1)



在Arduino
I2C Wire.h Multi-Masters功能實作中以Arduino+Gravitech
7-SEG Shield組合成為一個I2C Slave Device,可以提供其它的Arduino使用I2C Master方式控制LED的顯示,藉以驗證Wire.h具備多重I2C Master的處理功能。
而原先的構想是任何可以進行I2C通訊的裝置,應該都可以控制這個I2C Slave Device,包含NXT在內,而事實上NXT對Arduino的I2C通訊也經由實際測試,運作正常。
不過經由多次的測試,NXT始終無法如同Arduino一般能夠正常的存取這個I2C Salve
Device,而比較之前的測試Case,唯一的差別就在於Gravitech 7-SEG
Shield擴充板所內建對於SDA及SCL的4.7k ohm pull-up,實在是百思不解問題真正所在。
Arduino Network Device建構
(Photo)
而為了讓NXT可以使用Gravitech 7-SEG Shield的功能,所以改造原來的I2C Slave
Device成為Network Device。
不再使用I2C而改為Ethernet TCP/IP方式,:
(1). 以Arduino UNO + Gravitech 7-SEG Shield +
Arduino Ethernet
Shield組合成為 Telnet Server。
(2). 另外使用 Arduino UNO + Arduino Ethernet Shield組合成為Telnet Client。
至於NXT則透過I2C傳送指令與資料給Telnet Client,由Client端UNO組合成封包之後經由網路線傳送至Telnet Server接收,而Server端的UNO解析之後再以I2C控制Gravitech 7-SEG Shield執行指定的功能,有點複雜但可玩性十足。
(架構圖)
(Demo Video)
NXT對於Network Device控制流程
整體架構共分成三個部份:
(1). NXT to Telnet Client:
將Telnet Client作為I2C Slave Device,規劃相關功能對應的Register Address及Data需求:
0x00
- 回傳裝置資訊,這是用來測試I2C通訊功能是否正常。
0x41+三色LED顯示指令(R/G/B) -
控制Gravitech 7-SEG
Shield顯示指定顏色。
0x42+英數字串 - 控制Gravitech 7-SEG
Shield將字串顯示在七段式LED。
0x43+整數值字串 - 控制Gravitech 7-SEG
Shield將數字顯示在七段式LED。
因此,NXT即將前述的指令以LowspeedWrite()傳送給Client端的UNO,而對於UNO即會觸發onReceive()的handler進行接收。
(2). Telnet Client to Server:
Client端UNO負責將接收到的NXT
request解析並製作成資料封包後,使用Ethernet.h library的功能,透過Arduino Ethernet Shield以網路線傳送至Server端,而Server端的UNO同樣也是以Ethernet.h的功能接收封包資料。
(3). Telnet Server to Gravitech 7-SEG Shield
Server端經解析來自Client端的資料之後,即分別使用Digital I/O控制三色LED的顏色顯示以及以I2C方式控制七段式LED顯示字串資料。
NXT High Speed Communication
NXT Firmware通訊模組(Comm module)支援的功能包含:Bluetooth、USB以及High Speed Communication,其中High Speed Communication指的是使用第四個Input port 以RS485進行全雙工的非同步傳輸通訊,用法則是以NXT Cable串接兩部NXT來進行雙向的資料傳輸。
RS485應用案例
Daniele Benedettelli在“Creating Cool MINDSTORMS NXT Robots”(2008 Apress)書中第八章的 JohnNXT機器人,在這個專案中共分成:機器人本體及遙控端兩部分,由於本體總共配置了6部馬達及5個sensor,所以需要以兩部NXT來進行協力控制,而因為藍芽通訊已經作為遙控端NXT對本體Main NXT傳送指令時所使用,於是本體的兩部NXT就採用High Speed Communication來進行串接溝通。
操作JohnNXT時會由本體的Master NXT接收來自遙控端NXT的藍芽指令,當需要由另一部Slave NXT協力來完成動作時,就會由Main NXT透過Port 4以RS485傳輸指令給Slave去執行所需的功能,而Slave NXT於完成工作之後就會回覆訊息給Main確認遙控端所下達的指令都已經執行完畢,接下來Main就會進入待命狀態準備接收下一個來自遙控端的藍芽指令。
這本書的NXC程式碼可以由官網下載,在Ch8本專案的資料夾裏有High Speed Communication的API程式庫 (HSlib.nxc),當初Danny在寫API時所用的都屬於較低階的NXC函數,所以需要對IO Buffer pointer作控制,而這些技術資料Mindstorms官方並沒有對外提供,一般人可能較不容易掌握確切的用法,還好John Hansen已經在最近版本的Bricxcc中封裝成較容易使用的高階函數,不過NXT需要更新成John Hansen所加持的enhanced firmware,以解除原有官方的功能限制。
Dexter NXTBee

而Dexter的 NXTBee則是提供NXT能夠結合High Speed Communication及XBee無線通訊功能的外接模組,在傳輸的效能與距離方面都有優於藍芽的表現。
使用方式為連接Port 4並透過RS485進行無線非同步序列通訊,相當於取代實體Cable且大大的延伸連線範圍。
使用NXTBee時可以幾乎完全做到無縫切換,也就是說即使目前正以實體Cable進行有線通訊,可隨時接上NXTBee換成無線而不致於在過程中造成連線的中斷,且若切換回有線時也是一樣的穩定與可靠。
至於程式部分只須處理Port 4之RS485初始設定以及資料之傳送與接收控制,完全不須撰寫任何NXTBee相關的程式碼,NXTBee會自動接手無線傳輸工作。

RS485 over XBee應用測試
測試時共使用兩部NXT,分別為Main及Slave,進行的過程為:
1. 首先由Main NXT的畫面選單中選擇顏色指令(“R”、 “G”、 “B”),然後傳送給Slave NXT,之後就會進入等待Slave回覆執行完成指令的狀態。
2. 而Slave會先處於待命狀態並持續監聽是否有來自Main NXT的指令,一旦接收到Main指令時會先閃爍Light sensor燈號三次確認,接著依據指令執行閃爍Color sensor指定顏色燈號10次,完成之後會傳送確認字串“DONE“回覆Main已經執行完畢,然後再度進入待命狀態。
3. 而Main一但接收到Slave字串“DONE“的確認回覆時,會先閃爍Light sensor燈號三次,接下來即可再度接受選單之指令選擇。
就如同邱老師在”超級有趣的NXT感應器!Dexter的dFlex”所提到的, dFlex應該就是「應變規(strain gauge)」,簡單講就是當感應器受力變形後影響電阻值產生變化,因此就可以用來反應彎曲的程度。
dFlex外觀就如同被剪掉一半的NXT Cable,尾端就是可以彎曲扳動的感應區。
<<
>>
因為測量值是為類比讀取方式,所以可以先用NXT內建的Light sensor來進行簡單測試,實際應用時還要要以Raw Value會比較精確。

John Hansen最近更新BricxCC非常勤,即使同一版次每隔幾天就有新的更新,所以就應眾人要求增加了日期的標示,而下載點頁面也一樣有了個分日期版本的壓縮檔了。
在最近一次20100606的版本多了NXC Programmer's Guide的PDF檔,非常大有兩千多頁,不過絕大多是API的清單。
Mindsensors NXTMMX的主要功能是提供NXT可以增加兩個馬達的輸出。
這是一個I 2C裝置,外觀上共具有四個RJ12 Ports以及一個外部電源輸入端子:
用途分別為:
l M1/M2:連接兩個馬達輸出。
NXTMMX所設計的輸出控制功能主要是以NXT Servo Motor為對象,提供運轉角度、時間與速度的控制,而同時也適用於Firgelli L12-NXT線性致動器,此外,透過適當的轉接線,PF Motor、Lamp、Technic Motor等同樣都可以連接使用,差別只在於沒有角度控制功能,所以,在運用上具有如同NXT Output Ports一樣的彈性。
l NXT:連接NXT Input Ports。
由NXT透過I 2C通訊方式操控裝置。
l Sensor:串接其他I 2C裝置(數位感應器)。
NXTMMX出廠預設I 2C Address為0x06,而串接在同一個Input Port的裝置位址須不一樣,還好除了NXTMMX之外,應該沒有其他數位裝置的位址是0x06,而若需要變更I 2C位址設定,可以使用Mindsensors所提供的程式修改。
l 9V電源輸入端子:連接外部電源供電給M1/M2 Ports的馬達。
外部電源的連接方式,在Mindsensors NXTMMX的產品網頁上有9V電池盒供選購,而我是使用舊款的Technic電源線。
再加上PF電源延長線(L8886)連接PF電池盒(L8881)作為供電 
電源輸入的極性必須正確,否則無法正常供電,所以若NXTMMX能夠提供電源指示燈,使用上應該會更便利。
NXTMMX的馬達操控
比較NXT Output Module對於Servo Motors的控制功能,NXTMMX同樣可以分別控制連接在M1/M2 Ports兩個Servo Motors的運轉角度與輸出速度,此外還增加了運轉時間的設定。
而不同於Output Module所使用的OnFwd()、RotateMotor()等指令, NXTMMX是透過I 2C通訊方式來操控馬達;在撰寫程式時,也許沒有那麼直覺與精簡,不過,若能瞭解清楚NXTMMX的特性與用法,相較於Output Module的主要功能大都具備了,同時還多了一些友善的輔助設計,所以應該是相當實用且好玩的裝置。
而運用I 2C通訊操控NXTMMX,首先即須要瞭解裝置的Register Layout與內建指令的用法。
NXTMMX Register Layout 與 指令用法
NXTMMX Register的主要用途為提供對兩個Output Ports的控制功能所需之設定值與馬達運轉過程中回饋的狀態值,所以用到的Registers數目並不少,因此須要先組織與整理Register Layout的配置與用法,這樣才有助於掌握各種運用情況下所相關之Register的設定方式以及內建指令的使用時機。
NXTMMX Register Layout說明文件可以參考Mindsensors所提供之Users Guide Page 5~7,而以下為依據用途所作的整理分類:
l 讀取裝置狀態值 / 寫入指令:
0x41 - 存放目前外部電源的電壓值(Voltage) 或 寫入所要執行的控制指令
讀取這個位址可以判斷外接電源的供電狀態,若極性接錯,回傳值為0,馬達即無法運轉。
目前已提供的控制指令清單在Users GuidePage7,而較常用的是:
R:Reset所有馬達參數設定值與狀態值,可以作為初始化Ports的動作。
S:讓兩個Motor的參數設定值同時生效,用來啟動同步運轉。
l 設定M1/M2 Port馬達運轉參數:
透過將馬達運轉設定值寫入以下控制參數的Registers位址,可以對馬達進行運轉控制:
■旋轉角度設定參數 - M1 0x42~0x45,M2 0x 4A~0x4D
■輸出速度設定參數 - M1 0x46 ,M2 0x4E
■運轉時間設定參數 - M1 0x47 ,M2 0x4F(以秒為單位)
■控制功能設定參數 - M1 0x49 ,M2 0x51(參考Users GuidePage8),
控制功能設定參數的作用就如同NXT Output Module的UpdateFlags Field Constant,用來確認所要使用的馬達控制方式,如:速度控制(bit 0)、角度控制(bit 3)、時間控制(bit 6)等。
必須要將對應的控制位元設成ON(1),馬達才會依據設定的目標值運轉,若同時設定角度與時間目標,則會以時間為優先,亦即如果沒有在指定的時間期限內旋轉至設定的角度目標,就會中止運轉的工作;而若同時將角度與時間控制位元設成OFF(0),則會連續運轉直到下一次改變設定值為止。
bit 7為設定讓控制方式生效,也可以使用S指令來讓M 1’ M 2兩個控制功能設定參數同時生效。
而由控制功能設定參數,可以使用兩個NXT Output Module所沒有的輔助功能:
※相對位置旋轉(bit 2) – 設定以目前位置作為參考點進行相對位移運轉。
※守住目前位置(bit 5) – 設定記住前次旋轉後位置,下次運轉前若有因外力影響而移位時,會先回復後再運轉。
而M1與M 2兩個Ports所有運轉參數的Registers位址正好連續(0x42~0x51) 且為16個Bytes,符合NXT I 2C Buffer的最大資料寫入量,因此可以全部一次寫入,然後執行S指令,來同步生效並啟動M1與M2 Port的馬達運轉。
l 回饋M1/M2運轉工作狀態:
透過讀取以下回應值所存放之Registers位址,可以取得馬達目前的執行狀態:
■旋轉角度位置 - M1 0x62~0x65,M2 0x66~0x69
■馬達運轉狀態 - M1 0x72 ,M2 0x73(參考Users GuidePage9)
■工作執行狀態 - M1 0x76 ,M2 0x77
旋轉角度位置回應值就如同NXT Output Module的MotorRotationCount()函數。
而運轉回饋狀態則讀取目前馬達運轉工作的執行情形,一旦按照設定目標完成,則所有的bit都會設成0,所以較為實用的用法是作為判斷馬達是否處於遲滯狀態(Stalled),詳細說明可以參考Users GuidePage11。
而工作執行狀態則作為判斷馬達是否按照目標設定完成運轉,功能有點重複。
l PID控制設定值:
分別有對於角度位置與輸出速度的PID控制參數以及微調參數,至於實際用法有待測試,希望Mindsensors能夠有進一步的說明文件。
簡單的測試結論
相較於NXT Output Module的四種控制模式,較確定的是synchronized mode沒有提供,而speed regulation mode因為沒有回饋Actual Speed,所以無法檢測,除此之外Tachometer limited Mode對於NXT Servo Motor的控制相當精確。
唯一到目前還沒搞定的是Firgelli L12-NXT線性致動器的位置控制功能不太正常,以50mm為例,完全伸展的設定值應該是-100,不過這樣的設定只伸展到-90就停止了,須要設成-125才會完全伸展,而且不同Speed狀況還不一樣,有待將問題回報原廠解決。
►範例程式:NXTMMX-tst01.nxc
<<>>
應該不致於才是,
建議先檢查一下外接電源, 可以讀 0x41位址的值, 乘以 37 就等於它的電壓值,
我使用 9V 的電池盒, 並不會有出力不足的情形(Speed設成最大 100)
NXTMMX兩個Motor Port各有5個控制參數且長度為8 Bytes,
它的位址連續,總長度16 bytes,剛好符合NXT I2C buffer的長度限制,
所以可以同時設定並且一起寫入NXTMMX,
接著再對於 Command register(0x41) 寫入”S”指令,
這樣就可以做到兩個馬達以不同方向同時運轉的動作。
以你的需求,需要設定的參數分別為:
(1) 輸出速度參數:Motor 1 - 0x46, Motor 2 - 0x4E,
將這兩個參數分別設成不同方向,如: 100 與 -100
(2) 控制功能參數的:Motor 1 - 0x49, Motor 2 - 0x51
將這兩個參數的 bit0設成1

在pbLua的官方部落格中有一系列的教學文(Tutorial), 編寫的內容相當有條理且程度適中, 即使未曾使用過pbLua, 也很容易就能理解文章中範例程式的邏輯, 因此也算是具有參考價值的資源.
而其中一篇關於HiTechnic Gyro sensor的使用教學, 是以Gyro所具有的功能特性介紹起, 接著藉由四種Gyro裝置典型應用時的需求層級, 由淺入深且循序漸進的導引與講解如何達成的方法與技巧,
而這四種應用層級分別是:
1. 偵測物體是否正在轉動
2. 偵測物體正往那個方位轉動
3. 測量物體目前正在轉動的速度(角速度) 與 方位
4. 測量物體已轉動的位移角度
對於前三種應用, 很單純的只要將所讀取到感應器的回應值減掉Gyro靜止狀態時的基準值(Zero Point), 就可以得到測量當時之物體轉動的角速度, 藉以判斷出當下轉動的狀態與方位.
至於第四種應用, 則因為速度是單位時間內位移的變化率, 逆運算即是將速度乘以時間以得到位移, 所以即可以透過於固定的取樣周期來計算平均速度, 再乘以取樣週期時間長度以推算出位移角度, 然後累計每次計算的結果, 就可以估計出角度的總位移, 以下是測試時的NXC程式碼:
currTick = CurrentTick();
currSpeed = SensorRaw(GYRO_PORT) * BIAS_SCALE * BIAS_WEIGHT - biasSpeed;
sampleTick = currTick;
lastSpeed = currSpeed;
do
{
currTick = CurrentTick();
if ((currTick - sampleTick) >= TRAVEL_SAMPLE_TICK)
{
currSpeed = SensorRaw(GYRO_PORT) * BIAS_SCALE * BIAS_WEIGHT -
biasSpeed;
relTravel + = (currTick - sampleTick) * (currSpeed + lastSpeed)/2;//位移計算
lastSpeed = currSpeed;
sampleTick = currTick;
}
} until (ButtonPressed(BTNCENTER, true));
最後所得到的結果雖然未必足夠精確, 不過拿來作為對Gyro sensor特性的教學說明, 還算是不錯的範例.
在實務上, 專業的導航系統確實也使用了第四種應用的概念來提供對GPS的輔助功能, 因為, 通常GPS會受到地理與天候等環境的影響, 並無法確保隨時隨地都能接收到衛星訊號來進行定位, 例如當天候不佳或處於都會區的大樓夾縫中以致衛星訊號收訊不良時, 這時候就需要透過Acceleration 與 Gyro sensor的輔助, 對於前者可以推算出移動距離, 而後者可以推算方位偏向角度, 若在加上Compass來校正, 就可以達成慣性導航系統(Inertial Navigation System, INS)的功能.
而以上所提到的Acceleration’ Gyro’ Compass等三種sensor剛好HiTechnic都有賣, 所以是否有機會結合這些裝置做出慣性導航系統? 個人覺得可能想太多了, 首先, 要將Acceleration sensor所讀到的線性加速度值轉換成位移距離, 就必須對時間做兩次積分, 所以累積的誤差會失真的很嚴重, 再者它是一個I2C裝置, 回應速度對於要成為導航系統而言實在不夠快, 也許, 如果有廠商能開發出All-in-One的裝置, 將三種功能作在一起, 並兼具位移推算的功能, 也許就真的有機會讓NXT具有慣性導航的功能.
改善Gyro基準值的準確度
最後, 在本篇教學文中最重要的內容就是如何改善Gyro基準值(Zero Point)的準確度, 因為, Gyro sensor的測量值會受到外在溫度的影響, 所以須要在每次使用前的熱機過程中先測量出靜止狀態下穩定的基準值, 一般的做法就是持續讀取數次之後再求出平均值, 不過, 再以前面所提的四種應用層級來考量, 前三種應用對於基準值的參考時機是獨立的, 並不會有誤差累積的情況, 而第四種應用, 則因為每次取樣時都會參考基準值來計算位移, 所以若基準值不夠準確, 累積的誤差會讓結果失真, 因此, 在這篇文章中就提到了兩個改善的方法:
l 首先以人為的方式擴大所讀取到感應器回應值的精確位數, 這裡會將每次的讀取值乘以一個常數64, 因此, 當進行平均值計算時就不會因為整數運算的關係被捨棄太多的準確位數.
l 接著會透過加權平均的概念, 來抑制取樣過程中突發的Noise影響基準值計算的準確度, 意即降低每一次取樣影響計算結果的敏感性,
作法的概念是這樣:
假設要針對流動中的水流測量出平均的生菌數, 為了避免突發的情況影響穩定的結果, 所以, 我們可以事先準備好一個一公升的容器, 然後裝滿純水(生菌數為0), 接著在固定的取樣週期時, 先從水桶中取出25ml的水之後, 再加入等量要測量之水流的水, 如此當取樣次數夠多時, 則水桶中平均的生菌數就會趨於穩定, 而同樣的概念若應用到基準值的計算過程, 就可以讓結果隨著取樣次數的增加而呈現平順的變動, 最後同樣會趨於穩定, 而得到了所需求的基準值了.
以下是NXC的程式碼範例:
long Get_Bias()
{
long biasVal, newVal, oldBias=0;
long xtick=0, sampleTick=0, dispTick=0;
do
{
xtick = CurrentTick();
if ((xtick - sampleTick) >= BIAS_SAMPLE_TICK)
{
newVal = SensorRaw(GYRO_PORT) * BIAS_SCALE;
biasVal= biasVal - (biasVal/BIAS_WEIGHT) + newVal;
sampleTick = xtick;
}
if ((xtick - dispTick) >= BIAS_WATCH_TICK)
{
NumOut(0, LCD_LINE3, biasVal);
TextOut(0, LCD_LINE4, " " );
NumOut(0, LCD_LINE4, biasVal-oldBias);
NumOut(0, LCD_LINE5, biasVal / (BIAS_SCALE * BIAS_WEIGHT));
dispTick = xtick;
oldBias = biasVal;
}
} until (ButtonPressed(BTNRIGHT, true));
return (biasVal);
}