這裡將再運用前一篇“以瀏覽器控制Mindstorms NXT”的方式,以瀏覽器為操作介面,經由Arduino Web Server透過XBee無線方式傳送指令來對HTWay進行控制。
也因此會以NXTBee取代原來的IRReceiver作為接收遙控指令。
(Controlling HTWay via Browser)
(Video )
最主要的實作為:
●更改HTWay的接收遙控方式,這需要修改HTWay的NXC程式。
●變更Web page為圖形介面,這需要讓Arduino web server能夠傳送內嵌圖像給瀏覽器以及解決ATMmega328只有2K SRAM的問題。
修改HTWay的Control Code
HiTechnic HTWay的NXC程式碼將維持機器人平衡(Balance code)與控制機器人移動(Control code)兩部份區隔開來,可以分別依據自己的需求進行修改。例如,想要以其他的感應器取代原來的GYRO來偵測機器人的平衡狀態,則只需修改Balance code,而不會影響Control code。
同樣,在本次實作,控制方式以NXTBee取代IRReceiver,所以,就只需修改Control code,將接收到的指令,轉換成為更新控制機器人移動所用到的:motorControlDrive與motorControlSteer這兩個全域變數的值。
原來的IR版本會定期去讀取IRReceiver感應器暫存器值,並存到pfData八個元素的陣列中,而只使用前兩個元素值來更新全域變數值。本次實作在盡量不變更原程式碼的前提下,也同樣使用pfData陣列來存放控制指令的轉換值:●修改Control code中讀取控制值的呼叫function:
task taskControl()
{
Follows(main);
short control_wait_times;
char pfData[8];
while(true) {
// Mark原來的程式碼
// ReadSensorHTIRReceiver(IR_RECEIVER, pfData);
// if (pfData[IR_LEFT] == -128) pfData[IR_LEFT] = 0;
// if (pfData[IR_RIGHT] == -128) pfData[IR_RIGHT] = 0;
// 改為讀取RS485 port
ReadCommandFromRS485(pfData);
// Set control Drive and Steer. These are in motor degree/second
motorControlDrive = (pfData[IR_LEFT] + pfData[IR_RIGHT]) *
CONTROL_SPEED / 200.0;
motorControlSteer = (pfData[IR_LEFT] - pfData[IR_RIGHT]) *
CONTROL_SPEED / 200.0;
Wait(CONTROL_WAIT);
}
// Wait to allow user time to see screen.
Wait(10000);
{
Follows(main);
short control_wait_times;
char pfData[8];
while(true) {
// Mark原來的程式碼
// ReadSensorHTIRReceiver(IR_RECEIVER, pfData);
// if (pfData[IR_LEFT] == -128) pfData[IR_LEFT] = 0;
// if (pfData[IR_RIGHT] == -128) pfData[IR_RIGHT] = 0;
// 改為讀取RS485 port
ReadCommandFromRS485(pfData);
// Set control Drive and Steer. These are in motor degree/second
motorControlDrive = (pfData[IR_LEFT] + pfData[IR_RIGHT]) *
CONTROL_SPEED / 200.0;
motorControlSteer = (pfData[IR_LEFT] - pfData[IR_RIGHT]) *
CONTROL_SPEED / 200.0;
Wait(CONTROL_WAIT);
}
// Wait to allow user time to see screen.
Wait(10000);
●新增function,由RS485 port接收來自Arduino web server傳送的指令,並轉換為控制值:
void ReadCommandFromRS485(char &pfData[])
{
string strAction;
long lastTick = CurrentTick();
pfData[IR_LEFT] = 0;
pfData[IR_RIGHT] = 0;
while((CurrentTick() - lastTick) < 1000)
{
if(RS485DataAvailable())
{
strAction = "" ;
RS485Read(strAction);
if(StrLen(strAction)>0)
{
for(int xii=0; xii {
if(SubStr(strAction,xii,1) == "@" ) break;
else
if(SubStr(strAction,xii,1) == "F" )
{
pfData[IR_LEFT] = 100;
pfData[IR_RIGHT] = 100;
break;
}
else
if(SubStr(strAction,xii,1) == "B" )
{
pfData[IR_LEFT] = -100;
pfData[IR_RIGHT] = -100;
break;
}
else
if(SubStr(strAction,xii,1) == "L" )
{
pfData[IR_LEFT] = 100;
break;
}
else
if(SubStr(strAction,xii,1) == "R" )
{
pfData[IR_RIGHT] = 100;
break;
}
} // for loop
if((pfData[IR_LEFT] != 0) || (pfData[IR_RIGHT] != 0)) break;
} // if(StrLen(strAction)>0)
} // if(RS485DataAvailable())
Wait(100);
} // while loop}
{
string strAction;
long lastTick = CurrentTick();
pfData[IR_LEFT] = 0;
pfData[IR_RIGHT] = 0;
while((CurrentTick() - lastTick) < 1000)
{
if(RS485DataAvailable())
{
strAction = "" ;
RS485Read(strAction);
if(StrLen(strAction)>0)
{
for(int xii=0; xii {
if(SubStr(strAction,xii,1) == "@" ) break;
else
if(SubStr(strAction,xii,1) == "F" )
{
pfData[IR_LEFT] = 100;
pfData[IR_RIGHT] = 100;
break;
}
else
if(SubStr(strAction,xii,1) == "B" )
{
pfData[IR_LEFT] = -100;
pfData[IR_RIGHT] = -100;
break;
}
else
if(SubStr(strAction,xii,1) == "L" )
{
pfData[IR_LEFT] = 100;
break;
}
else
if(SubStr(strAction,xii,1) == "R" )
{
pfData[IR_RIGHT] = 100;
break;
}
} // for loop
if((pfData[IR_LEFT] != 0) || (pfData[IR_RIGHT] != 0)) break;
} // if(StrLen(strAction)>0)
} // if(RS485DataAvailable())
Wait(100);
} // while loop}
由Arduino Web server傳送內嵌圖片給瀏覽器
前一篇Web page的控制介面使用HTML form tag的Submit button。
本篇則是以四個箭頭圖像作為控制HTWay前進、後退以及左、右轉向的圖形介面。
此外,再加上NXT與Arduino兩個Icons。
(HTWay control panel)
因此在每次Arduino Web server回覆HTTP Response時,即需要傳送共六個圖像資料給瀏覽器顯示。然而因為Arduino無法處理內嵌式圖片物件,所以就需要先編碼成mime Base64格式字串,再以字元串流方式下載到瀏覽器顯示。
線上編碼轉換網址:http://www.motobit.com/util/base64-decoder-encoder.asp
●以向左箭頭圖像為submit button的Arduino程式碼為例,紅字部分為編碼後的字串:
P(left_arrow) =
"〈form action='/' method='POST'〉"
"〈input type='hidden' name='nxtControl' value='R'〉"
"〈input type='image' src='data:image/jpg;base64,"
"iVBORw0KGgoAAAANSUhEUgAAAD0AAAA3CAIAAAAwm9XYAAAAAXNSR0IArs4c6QAAAARnQU1BAACx"
"jwv8YQUAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAAAgNJREFU"
"aEPVmqGywjAQRSuRSD4BiUQikUgkn4DEIZFIJBKJRCKRSCQSiUTuu2/SCR2aNtmk090wVUwpJ2c2"
"zc22BYl/Ph/abun1YoEUrLO7P/lyofGYioKeT9bF5bh3OxoM/onNkQH39Vo6ttAZcKOOq7h5+N7v"
"aTjMh/v9drOqrpPDodGxUu7bjaZTv2ld95OQ2lDn+3ik0SjUtLxvrmMVvs9ntmNh7seD5nNeVdSX"
"nr7XeaS5asxwroWdf0kUm6ugJ91x9HgiuUUcVwcZw20Tc7St9B/yuBHlFovU+ZcOjSuEcmPFNrsS"
"JYefG45XKy241pqfuykuy4pv42aluZ6H4ebW6bjtPni/MxJzz47d3Ihy67W6+dek5lsn3LgsKLu8"
"fwfu/2RBf/699J2S90XG860T3PUmkwzr2zQVW/oyIl7989I2Q5v6YNq57QDQL1W7AHnyiVr3/lyl"
"YZdQL1E/N8oGu7KfHrt4rQdx24qHeyXLKo/buN9sBBoP7vWS9UQIJ6PRI1sqbN92hKeTZM3Ec9sB"
"iLjvgBsDiOgay/cHjfj0bUfffc3qnEaojJ6vktzWfUTLRZ7b0HPda+EGOitRKuIGOhLlchlU9Lq4"
"Tc3gRQLvfNXIbejb29B6uQ09QqXTvXZuoOOtpPqjrAy4gV5/rJUHt11lbZrPjNuk+dmM+37VH7L/"
"WySjImoPAAAAAElFTkSuQmCC' width='300' height='300' border='0'〉"
"〈/form〉";
"〈input type='hidden' name='nxtControl' value='R'〉"
"〈input type='image' src='data:image/jpg;base64,"
"iVBORw0KGgoAAAANSUhEUgAAAD0AAAA3CAIAAAAwm9XYAAAAAXNSR0IArs4c6QAAAARnQU1BAACx"
"jwv8YQUAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAAAgNJREFU"
"aEPVmqGywjAQRSuRSD4BiUQikUgkn4DEIZFIJBKJRCKRSCQSiUTuu2/SCR2aNtmk090wVUwpJ2c2"
"zc22BYl/Ph/abun1YoEUrLO7P/lyofGYioKeT9bF5bh3OxoM/onNkQH39Vo6ttAZcKOOq7h5+N7v"
"aTjMh/v9drOqrpPDodGxUu7bjaZTv2ld95OQ2lDn+3ik0SjUtLxvrmMVvs9ntmNh7seD5nNeVdSX"
"nr7XeaS5asxwroWdf0kUm6ugJ91x9HgiuUUcVwcZw20Tc7St9B/yuBHlFovU+ZcOjSuEcmPFNrsS"
"JYefG45XKy241pqfuykuy4pv42aluZ6H4ebW6bjtPni/MxJzz47d3Ihy67W6+dek5lsn3LgsKLu8"
"fwfu/2RBf/699J2S90XG860T3PUmkwzr2zQVW/oyIl7989I2Q5v6YNq57QDQL1W7AHnyiVr3/lyl"
"YZdQL1E/N8oGu7KfHrt4rQdx24qHeyXLKo/buN9sBBoP7vWS9UQIJ6PRI1sqbN92hKeTZM3Ec9sB"
"iLjvgBsDiOgay/cHjfj0bUfffc3qnEaojJ6vktzWfUTLRZ7b0HPda+EGOitRKuIGOhLlchlU9Lq4"
"Tc3gRQLvfNXIbejb29B6uQ09QqXTvXZuoOOtpPqjrAy4gV5/rJUHt11lbZrPjNuk+dmM+37VH7L/"
"WySjImoPAAAAAElFTkSuQmCC' width='300' height='300' border='0'〉"
"〈/form〉";
●HTML完整內容:WebPage_HTWayControlPanelHTML.html
以Program Memory(Flash memory)存放大量資料
因為在Arduino程式中有六個圖像編碼後的大量字串資料,可能會超過ATMmega328可用的2K SRAM容量,所以需要預先將資料存放到32K的Flash記憶體中,等到要使用時再讀取至SRAM。
沒有留言:
張貼留言