[Robotics Studio] Sumo[IV] - 衝啊~相撲機器人 -- Day22
是的, 一旦我們知道辨識影像的結果, 相信對於如何改良 Tracking 就有底了吧!
昨天就是在
result = ProcessImage(cameraFrame.Size.Width, cameraFrame.Size.Height, cameraFrame.Frame);
這一行之後把畫面畫出來的, 所以你知道 ProcessImage 函式就是用來辨識敵人的位置,
你可以在 ProcessImage 函式當中找到
// only process bottom half of the image
for (int y = height / 2; y < height; y++)
這表示原本只處理畫面下半部的影像, 因為上半部是比較遠的影像, 但其實你可以改為處理全部的影像:
像下面這樣
for (int y = 0; y < height; y++)
就可以處理全部的影像囉.
接著就可以看 HandleProcessedImage 函式, 我在原本的程式當中加入註解:
/// <summary>
/// 根據辨認的影像結果來反應動作
/// </summary>
/// <param name="result"></param>
/// <returns>回傳是否有根據影像處理做出反應動作</returns>
private bool HandleProcessedImage(ImageProcessResult result)
{
bool processImage = false;
if (result != null)
{
_state.ImageResult = result;
if (_state.SumoMode < SumoMode.Pending)
return false;
if ((_state.SumoMode >= SumoMode.Tracking) &&
(result.TimeStamp > _state.LastImage))
{
processImage = true;
_state.LastImage = result.TimeStamp;
}
// 假如處理影像的目標超過 50 個點, 表示應該像是敵人了..
if (result.Area > 50)
{
if (processImage)
_state.SumoMode = SumoMode.Tracking;
if (result.XMean < 0x48)
{
// 敵人在左邊, 向左邊衝
LogVerbose(LogGroups.Console, "Enemy to the left: " + result.XMean);
if (processImage)
InternalDrivingMilliseconds(250, 400, 400.0);
_robotPort.RoombaSetLeds(irobot.RoombaLedBits.Off, 0, 255);
}
else if (result.XMean > 0x68)
{
// 敵人在右邊, 向右邊衝
LogVerbose(LogGroups.Console, "Enemy to the right: " + result.XMean);
if (processImage)
InternalDrivingMilliseconds(400, 250, 400.0);
_robotPort.RoombaSetLeds(irobot.RoombaLedBits.CreateAdvance, 0, 0);
}
else
{
// 敵人在正前方, 往前面衝
LogVerbose(LogGroups.Console, "Enemy Dead Ahead!: " + result.XMean);
if (processImage)
InternalDrivingMilliseconds(300, 300, 500.0);
_robotPort.RoombaSetLeds(irobot.RoombaLedBits.CreatePlay, 0, 0);
}
}
else
{
// 沒發現敵人, 切回鬼混模式
if ((processImage) && _state.SumoMode == SumoMode.Tracking)
{
_state.SumoMode = SumoMode.Wander;
_state.NextModeCheck = DateTime.Now;
LogVerbose(LogGroups.Console, "Enemy Not Visible");
}
_robotPort.RoombaSetLeds(irobot.RoombaLedBits.CreatePlay | irobot.RoombaLedBits.CreateAdvance, 0, 255);
}
}
return processImage;
}
如果你喜歡造成高一點的傷害力, 就是把那個 InternalDrivingMilliseconds 的前兩個參數加大, 你會發現你的機器人比較衝動, 暴力許多,
當然也就比較有可能衝過界線...
關於 Tracking mode 還有一部分的 code 是存在 TimerHandler 當中, 有需要的話也要修改:
...
else if (_state.SumoMode == SumoMode.Tracking)
{
// 繼續追上敵人
LogVerbose(LogGroups.Console, "Continue Tracking");
if ((_state.LeftSpeed + _state.RightSpeed) == 400)
InternalDrivingMilliseconds(100, 100, 250.0);
if ((_state.Direction & Direction.Left) == Direction.Left)
InternalDrivingMilliseconds(100, 300, 250.0);
else if ((_state.Direction & Direction.Right) == Direction.Right) // 原本是 Direction.Left, 應該是 bug, 改為 Direction.Right
InternalDrivingMilliseconds(300, 100, 250.0);
else
InternalDrivingMilliseconds(250, 250, 250.0);
}
...
其他像是想改 Contact mode 就要看 RobotUpdateBumpersHandler 函式, 還有 TimerHandler 的一小部分函式,
想改 AvoidBoundary mode 就看 RobotUpdateFloorSensorsHandler, TimerHandler
RobotUpdateFoolrSensorsHandler 當中也有關於切換到 Blind mode 的程式碼.
如果你想加模式, 當然也是可以, 不過我到目前為止也沒寫出甚麼必勝的密技...
不過這個相撲機器人程式還算是可以玩上一陣子的範例, 也提供足夠學習的技巧,
相信只要具備基本的 CCR, DSS 認知, 這個範例並不難以理解, 也應該可以加以修改.
可惜的是寫程式能做的變化就是只能跑來跑去, 如果實體機器人也可以改變, 相信就可以做出更多的變化,
也可以加上新的感測器來做不一樣的事情囉 (比如說, 前後左右都加上 Camera , 我看敵人往哪兒跑...哈哈).