Microsoft Robotics Studio中文教程1
- 格式:doc
- 大小:3.59 MB
- 文档页数:52
robot studio 教程Robot Studio教程第一章概述1.1 介绍本教程旨在向用户提供有关Robot Studio的全面指南。
Robot Studio是一款强大的仿真软件,可以帮助用户设计、模拟和优化系统。
1.2 安装在本章节中,将介绍如何和安装Robot Studio软件。
包括软件的系统要求,安装步骤以及常见问题解答。
第二章界面导览2.1 主界面这一章节将详细介绍Robot Studio的主界面,包括菜单栏、工具栏、快捷键等,以及如何切换视图,访问不同的功能模块。
2.2 视图控制在本章节中,将提供一些关于如何调整和控制Robot Studio的视图,包括缩放、旋转、平移等操作。
第三章创建模型3.1 建立基本模型这一章节将展示如何在Robot Studio中创建基本的模型,包括添加机械臂、关节、夹爪等组件。
3.2 导入CAD模型在本章节中,将介绍如何导入现有的CAD模型,并将其转换为Robot Studio可识别的格式。
第四章仿真与调试4.1 运行仿真这一章节将详细介绍如何运行仿真,并演示一些常见的操作,如的移动、捡取物体等。
4.2 调试程序在本章节中,将学习如何使用Robot Studio调试程序,检查错误和调整程序逻辑。
第五章路径规划与优化5.1 路径规划算法这一章节将介绍Robot Studio中使用的路径规划算法,包括最短路径、最优路径等。
并提供一些优化建议和技巧。
5.2 优化参数在本章节中,将讨论如何优化的工作参数,如速度、加速度等,以提高的性能和效率。
第六章系统集成6.1 外部设备集成这一章节将介绍如何与其他外部设备进行集成,包括传感器、相机、控制器等。
6.2 与PLC通信在本章节中,将学习如何与PLC(可编程逻辑控制器)通信,实现与生产线的无缝连接。
第七章高级功能7.1 机器学习这一章节将探讨如何在Robot Studio中应用机器学习技术,提高的智能水平和自适应能力。
2. Dispatcher, DispatcherQueue, Task就好比Thread 執行程式碼, 在CCR 當中, 程式的運行是以ITask 作為執行的單位, 而DispatcherQueue 就是以Queue 的方式來存放許多的Tasks (以下我提到Task, 就是代表該class 有支援/實作ITask 的意思) , 最後, Dispatcher 就像是Thread, 用來執行運作DispatcherQueue (當中的Tasks). 不過在極少數的狀況下, DispatcherQueue 也可以被.NET Thread Pool 來運作.而Task 最重要的就是Handler, 就是Programmer 寫的delegate function.至於這許多的Tasks 從何而來, 如何產生, Handler (你的程式碼, delegate function) 何時要被執行, 就是要靠接下來介紹的Arbiter class.3. Arbiter class這是CCR 寫好的一組函式庫, 負責用來撰寫處理訊息所需要用到的協同處理函式. 通常使用者(programmer) 就是透過撰寫delegate function, 然後指定當某種情境發生時(比方說, Receive Task 就是某個Port 收到訊息時), CCR 就會執行該delegate function (透過ITask).以下我開始介紹Arbiter 的所有Member (都是static function, 所以都是直接使用), 這可是CCR 的重頭戲(不過我只介紹基本使用方法, 進階的使用方法就太多了):Arbiter.Recive產生一個Receive Task , 就是當某一個port 收到訊息時, 就執行Handler (某段程式碼).比方說, 以下的程式產生一個Receive Task, 就是當一個Port<int> 收到int 訊息時就把它從Console 輸出. (但是該Task 還不會被執行, 因為我們只是產生了Recive Task)var myport = new Port<int>();var mytask = Arbiter.Receive(true, myport, i => Console.WriteLine(i));其中, 第一個參數如果是true, 表示這個Task 一直都要存在, 不會消失, 如果是false, 則表示僅僅執行一次, 這個Task 就消失.Arbiter.Activate使用某個DispatcherQueue 來執行一系列的Tasks.比方說我們要產生一個DispatcherQueue, 然後利用該DispatcherQueue 來執行一個Receive Task, 就可以寫成下面這樣的code :var taskQueue = new DispatcherQueue("myqueue", new Dispatcher());var myport = new Port<int>();Arbiter.Activate(taskQueue, Arbiter.Receive(true, myport, msg => Console.WriteLine(msg)));如果接下來有程式執行myport.Post(3) , 就會啟動執行Receiver Task, 也就是在Console 印出3 .Arbiter.Choice有點像是switch case , 是屬於Task 的分支流程處理用的, 它會產生一個Choice Task , 而只會處理眾多Handlers 的其中之一(或眾多Tasks 的其中之一個Handler).14. // Persisted Get handler, runs in parallel with all other activations of itself15. // but never runs in parallel with Update or Stop16. Arbiter.Receive<GetState>(true, _mainPort, GetStateHandler)17. ))18.);// activate an Interleave Arbiter to coordinate how the handlers of the service// execute in relation to each other and to their own parallel activationsArbiter.Activate(_taskQueue,Arbiter.Interleave(new TeardownReceiverGroup(// one time, atomic teardownArbiter.Receive<Stop>(false, _mainPort, StopHandler)),new ExclusiveReceiverGroup(// Persisted Update handler, only runs if no other handler runningArbiter.Receive<UpdateState>(true, _mainPort, UpdateHandler)),new ConcurrentReceiverGroup(// Persisted Get handler, runs in parallel with all other activations of itself// but never runs in parallel with Update or StopArbiter.Receive<GetState>(true, _mainPort, GetStateHandler))));而CCR 實現這個Arbiter.Interleave 不是靠傳統的lock, 或是ReaderWriterLock, 而是靠內部的TaskQueue 來實作的, 它也不需要知道哪些資料是你所要保護的, 它只是負責避免哪些程式不可同時執行, 以及允許哪些程式可以同時執行.Arbiter.JoinedReceive假如你想要等候兩個Port 都分別收到訊息時才要作處理(執行Handler) 的話, 這個就是你要的.比方說下面的code:Arbiter.JoinedReceive<int, string>(false, myport, myport2, (intmsg,strmsg) =>Console.WriteLine(intmsg+","+strmsg))就是表示產生一個JoinedReceive Task, 當myport 收到int 訊息, myport2 收到string 訊息, (不管先後順序, 會一直等到兩個都收到訊息), 就在Console 作輸出.Arbiter.MultipleItemReceive跟Arbiter.JoinedReceive 不太一樣的地方在於, 它是看訊息的數量, 當一定數量的訊息送到一個或多個Port 的時候, 就會啟動Handler.比方說下面這個code 就是當累積五個int 訊息送到portInt 的時候, 就會啟動Handler, 把這五個int 輸出到螢幕上.Arbiter.MultipleItemReceive(true, portInt, 5,intArray => Console.WriteLine(string.Join(",", new List<int>(intArray).ConvertAll<string>(i =>i.ToString()).ToArray())));一旦你了解了Arbiter 的函式, 還有DSSP 的類型, 相信你再去看documentation 當中的。
[Robotics Studio] 操控虚拟Kuka LBR3 机器人手臂-- Day23 2009/1/10 21:39 | 阅读数: 4294 | 我要推荐 | One Comment | 订阅玩完车子, 换玩机器人手臂吧.照例用简单的VPL , 使用GenericArticulatedArm 以及SimpleDashboard 两个service 就可以玩:在GenericArticulatedArm 当中我们可以选用manifest -KUKA.LBR3.simulation.Manifest.xml :就可以开始啦:Dashboard 的使用方法跟操控机器车子很像, 先点选Remote Node 里面的Connect, 再点选Articulated Arm 里面的Connect:你会看到一堆JointJoint在医学上就是骨头的关节...当然也可以翻译成为缝合点,接合点... 在此就是机器手臂可以旋转的关节点.Joint在XNA当中可以如下旋转(来自官方说明文件):换句话说, Local Axis 旋转的, 称之为TwistMode (Roll) , Normal Axis 的叫做SwingMode1 , Binormal Axis 称之为SwingMode2.在KUKA LBR3 当中, 每个Joint 都只有开放TwistMode (unlock) , 所以只能绕着Local axis 旋转.由下(基座) 一直到最上面(手臂尾端) 分别为Joint0 ~ Joint 6想要推倒骨牌,很简单,将Joint0设定为120 (先双击Joint0 ,然后输入angle : 120 ,再点选Apply Changes)然后把Joint1设为280 ,你就会看到下面的画面啰:那要怎么写VPL 来控制刚刚的动作?先将120 (注意type是double) ,然后丢给MathFunctions计算Radians (因为GenericArticulatedArm只吃这种,型态还要float!)所以再转成float ,丢给GenericArticulatedArm的SetJointTargetPose (JointName = "Joint0"),同时在资料产生时设定Timer (我设定为1000 ms)之后timer 的TimerComplete 发生通知时, 改丢280 的Radian 给GenericArticulatedArm 的SetJointTargetPose (JointName = "Joint1").而SetJointTargetPose 的其他参数设定如下:主要是设定TargetOrientation以及JointName,注意TargetOrientation的Axis只能是x = 1, y = 0, z = 0,因为KAKU LBR3的每个Joint只有TwistMode可以旋转,所以只能x有值(当然是1,如果你设定其他值, Angle就不是这样计算了)。
2./// This is the default drive configuration for wander mode3./// </summary>4.private void SetWanderDrive()5.{6. _state.SumoMode = SumoMode.Wander;7. InternalDrivingMilliseconds(250, 175, 250.0);8.}/// <summary>/// This is the default drive configuration for wander mode/// </summary>private void SetWanderDrive(){_state.SumoMode = SumoMode.Wander;InternalDrivingMilliseconds(250, 175, 250.0);}是不是很簡單呢, 它只做一個小幅度的繞圈圈...設定左輪的速度為250, 右輪的速度為175 , 然後等到250 ms 之後再進行新的決定.怎麼改會比較好?老實說我也不知道, 不過可以隨便亂改啊, 所以先改為原地順時鐘繞圈圈看看:InternalDrivingMilliseconds(250, -250, 250.0);然後讓mysumo 跟SumoPlayer (原本內定的機器人) 對打...有沒有發現我們的機器人大半的時候都是在原地旋轉呢?!有沒有發現我們的機器人似乎明明看到對手, 卻往前衝一下就停止, 繼續旋轉??所以, 下次我們來試試看Tracking Mode 到底在幹啥...在此之前, 你可以亂改SetWanderDrive 玩看看...你應該會有一些心得, 像是速度太快的話, 根本看不到對手... 就算你把反應時間調快也沒用.這是因為架構上是利用TimerHandler 這個函式去處理的, 而該函式預設是200 ms /4 = 50 ms 觸發一次...更何況預設是每200 ms 才去處理一次圖像...(這樣fps 才5 ... 你能想像5 fps 的射擊遊戲是甚麼樣子吧?)-->。
現在你已經有一個自訂的活動了, 看起來就像是這樣:對它點兩下, 你會進入編輯畫面,讓我們回到剛剛的Diagram , 把原本中間的一堆元件複製過來這個RobotControl Activity. 如下:現在你看到一堆驚嘆號了, 這代表有些小問題需要解決.移動到每一個小驚嘆號, 都會告訴你發生了甚麼問題, 首先, 我們要先宣告這個活動的介面,也就是定義這個活動的輸出以及輸入. 點擊上方的紅色編輯紐, 或者使用下拉選單的Edit/ Actions and Notifications, 你會看到這個對話框:主要分為兩大區塊, Actions 代表你可以定義的反應, 所謂的Action, 是指需要輸入一個訊息, 然後該Activity 會經過一些處理以後(包括做了一些整體環境上的改變), 最後吐出一個訊息, 而Notifications 就比較簡單, 是自動自發的吐出訊息, 不需要輸入訊息. 所以通常一個流程的最前面的元件往後吐出訊息的是Notification.再回到Actions, 我們可以看到下方有三排Add,Delete, 由左至右分別代表你新增刪除定義的Actions, 新增刪除輸入的訊息組合內容, 新增刪除輸出的訊息組合內容. 每一個Action 你都可以定義個別的輸出入內容, 而且每一個Action 都是一個獨立的編輯元件畫面歐.讓我們定義一個Action, 取名為ControlDirection, Input values 需要一個PressButton, Type 是String, Output values 則是LeftDriverPower, RightDriverPower, Type 都是double, 如下:之後, 我們把左邊的輸入拉到原本的Calculate 這個元件.為了要統一輸出, 所以我們還要多拉一個Join, 把"Stop", "Fowards", "Backwords" 產生出來的訊息經由Merge 後再一次Join, 一樣在Join 裡面填入left, right , 如下:然後把這個Join 輸出給"Left", "Right" 的 Merge,最後把這個Merge 輸出給Result, 整體的流程就像下面這樣:當你把Merge 的結果輸出給Result 時, 會跳出Data Connections 對話框, 此時你要指定輸出的LeftDriverPower, RightDriverPower 為何,因為透過Merge, Visual Programming Language Express Edtion 無法計算出正確的下拉選單給你選(你只能選value), 但是其實要輸入的值應該是value.left, value.right (因為Merge 之前的訊息是Join 吐出來的), 所以你要勾選下方的Edit Values Directly, 自己輸入正確值(但系統會提示你),如下:這樣你就完成了一個Activity (其中的一個Action) 的定義囉!讓我們回到原本的Diagram, 刪除那些被你複製到Activity 當中的元件, 改用這個Activity 取代,當你把DirectionDialog 的Notifications 拖到這個RobotControl 的Activity 時, 會出現Connections 對話框,我們當然選擇ButtonPress , 如下:接著出現Data Connections 對話框, 要選而當你把這個RobotControl Activity 的輸出丟給GenericDifferentialDrive 的時候,又出現Connections 對話框, 輸出要選SetDrivePower,Data Connections 對話框設定如下:現在整體的元件流程就像下圖:這樣看起來清爽多了吧.那我們之前複製的一個分身GenericDifferentialDrive 也就不需要了.不過, 暫且不要刪掉它, 還記得昨天你玩車子的時候, 按下去就一直跑了, 直到按Stop, 是有點不方便.現在我們改為放開就停止, 這樣還不錯玩.所以我們再複製一個DirectionDialog (請注意, 它還是該DirectionDialog 的分身囉),然後把Notification 直接拖到另一個分身GenericDifferentialDrive,在Connections 對話框設定ButtonRelease 給SetDrivePower,在Data Connections 對話框設定兩個值都是0這樣你的整體元件流程如下:好啦, 可以試玩看看是不是好多了? 比較不會翻車囉?撞到東西還是會翻啦XD有了自訂Activity, 就像是可以自己定義積木, 我們就可以邁向更複雜的人生啦...(啊?!)-->。
然後我們要做一些設定, 把Data 的類別改為String,
, 然後在中間填入Hello World , 變成如下的畫面.
接著, 我們把這個資料輸出到一個Service, 選擇左邊的Service, 找到Simple Dialog 這個元件.如果你覺得不好找, 可以在Find Service 當中輸入Simple , 如下:
這樣就只會過濾到剩下有Simple 文字的元件,
就可以容易找到Simple Dialog 這個元件.
把Simple Dialog 拖到右邊的Diagram 當中.
現在我們要做最後一步啦, 把這兩個元件串起來, 點選Data 元件的右邊(Outgoing Response) , 拖到Simple Dialog,
就會彈出Connections (Simple Dialog 的)對話框啦, From 沒得挑, 因為就是DataValue, To 我們選"AlertDialog",
點選OK , 又彈出Data Connections 的對話框, 這次我們要把Value 下拉, 選出value 這個值.
再一次點選OK,
噹噹! 我們寫完了Hello World 程式了.
雖然沒啥大用處, 但是還是可以執行看看囉,
執行之前Visual Programming Language Express Edition 會要求你存檔, 執行結果如下:
OK. 很簡單的程式, 所以我相信應該沒甚麼問題的.
一步一步來, 這樣很快就可以玩到機器人了?!(應該吧)。
CCR 用户指南微软机器人技术工作室Microsoft Robotics Studio 资料来源:目录CCR 用户指南 (1)目录 (2)1 CCR介绍 (4)1.1 问题领域 (4)1.1.1 异步 (4)1.1.2 并发 (4)1.1.3 协调和失败处理 (4)1.2 应用模型 (4)2 CCR API概览 (5)2.1 Port和PortSet队列原语。
(5)2.2 协调原语,也被称为仲裁器(Arbiter)。
(5)2.3 Dispatcher、DispatcherQueue和Task原语。
(5)3 Ports和PortSets (6)3.1 Ports (6)3.1.1 投递元素(Posting Items) (6)3.1.2 检索元素(Retrieving Items) (6)3.1.3 查看Port的状态 (7)3.2 Port Sets (8)3.2.1 构造一个PortSet实例 (8)3.2.2 类型安全(Type Safety) (10)4 协调原语(Coordination Primitives) (11)4.1 Arbiter静态类 (11)4.1.1 单元素接收器(Single Item Receiver) (11)4.1.2 选择仲裁器(Choice Arbiter) (12)4.1.3 连接和多元素接收器 (12)4.1.4 多元素接收器 (15)4.2 用于面向服务组件的协调 (16)4.2.1 持久化的单元素接收器 (16)4.2.2 交替(Interleave)仲裁器 (18)5 任务调度 (21)5.1 速度控制 (22)5.1.1 任务执行策略枚举 (22)5.1.2 策略场景 (24)6 迭代器 (25)6.1 通过本地变量隐式的传递参数 (26)6.2 部分返回到协调原语 (26)7 失败处理 (28)7.1 因果关系(Causalities) (28)7.2 连接和因果关系(Joins and Causalities) (31)8 与非CCR代码互操作 (34)8.1 线程套间约束 (34)8.2 与应用的主线程协调 (34)8.3 .NET异步编程模型适配器 (35)8.4 参考 (35)9 其它并发方法 (36)9.1 .net中的异步编程模型(APM) (36)9.2 Futures (36)9.3 连接(joins) (36)9.4 传统的线程原语,例如读写锁、锁和监控器(monitors) (36)1 CCR介绍并发与协调运行时(Concurrency and Coordination Runtime)是一个可以从任意.net 2.0程序语言进行访问的托管代码库。
newRobot.InsertEntity(sumoCam);恩, 就這樣, 雙方的機器人上面都有一個攝影機的畫面啦!決鬥過程也都可以看到...11. public string FontFamily12. {13. get { return _fontFamily; }14. set { _fontFamily = value; }15. }16.17. /// <summary>18. /// The font size of the font to use19. /// </summary>20. [DataMember]21. public float FontSize22. {23. get { return _fontSize; }24. set { _fontSize = value; }25. }26.27. /// <summary>28. /// Default constructor29. /// </summary>30. public TextSprite() { }31.32. /// <summary>33. /// Initialization constructor34. /// </summary>35. /// <param name="width"></param>36. /// <param name="height"></param>37. /// <param name="textureWidth"></param>38. /// <param name="textureHeight"></param>39. /// <param name="pivot"></param>40. /// <param name="initialPos"></param>41. /// <param name="family"></param>42. /// <param name="fontSize"></param>43. public TextSprite(string text, float width, float height, int textureWidth, int textureHeight,SpritePivotType pivot, Vector3 initialPos, string family, float fontSize)44. : base(width, height, textureWidth, textureHeight, pivot, initialPos)45. {46. _text = text;47. _fontFamily = family;48. _fontSize = fontSize;49. }50.51. /// <summary>52. /// Initialize53. /// </summary>54. /// <param name="device"></param>55. /// <param name="physicsEngine"></param>56. public override void Initialize(Microsoft.Xna.Framework.Graphics.GraphicsDevice device,PhysicsEngine physicsEngine)57. {58. try59. {60. InitError = string.Empty;61. Font nameFont = new Font(_fontFamily, _fontSize);62. base.Initialize(device, physicsEngine);63. Bitmap target = GetBitmap();64. Graphics g = Graphics.FromImage(target);65. g.FillRectangle(Brushes.DarkBlue, 0, 0, target.Width, target.Height);66. StringFormat nameFormat = new StringFormat();67. nameFormat.Alignment = StringAlignment.Center;68. nameFormat.LineAlignment = StringAlignment.Center;69. g.DrawString(_text, nameFont, Brushes.White, new Rectangle(0, 0, target.Width,target.Height), nameFormat);70. SetBitmap(target);71. }72. catch (Exception ex)73. {74. HasBeenInitialized = false;75. InitError = ex.ToString();76. }77. }78.}public class TextSprite : SpriteEntity{private string _fontFamily;private float _fontSize;private string _text;/// <summary>/// The font family name of the font to use/// </summary>[DataMember]public string FontFamily{get { return _fontFamily; }set { _fontFamily = value; }}/// <summary>/// The font size of the font to use/// </summary>[DataMember]public float FontSize{get { return _fontSize; }set { _fontSize = value; }}/// <summary>/// Default constructor/// </summary>public TextSprite() { }/// <summary>/// Initialization constructor/// </summary>/// <param name="width"></param>/// <param name="height"></param>/// <param name="textureWidth"></param>/// <param name="textureHeight"></param>/// <param name="pivot"></param>/// <param name="initialPos"></param>/// <param name="family"></param>/// <param name="fontSize"></param>public TextSprite(string text, float width, float height, int textureWidth, int textureHeight, SpritePivotType pivot, Vector3 initialPos, string family, float fontSize): base(width, height, textureWidth, textureHeight, pivot, initialPos){_text = text;_fontFamily = family;_fontSize = fontSize;}這個TextSprite 比原本的EntityNameSprite 好用多了, 不但可以顯示任何字(要考慮字型), 還可以不限定要加在某個Entity 當中(直接加到VSE).(因為原本的 EntityNameSprite 一定要掛在某個Entity 下面, 用來顯示該Entity 的名稱)-->。
現在開始構思該如何寫裡面的流程, 根據GenericDifferentialDrive 可以接受的指令, 只有前進一段距離, 以及旋轉一個角度,所以我們的L 型路徑應該由1.前進, 2.旋轉90 度, 3 前進, 4.旋轉90 度(為了下一次的L) 四個部分來組成.而每一個部分的完成都是靠通知來完成, 並不是靠當下GenericDifferentialDrive 的輸出, 所以當我們收到通知時, 有必要知道目前我們處於哪一個狀態, 而決定應該如何進行下一個步驟, 這個在離散數學上就算是Finite State Machine , 在VPL 處理FSM的問題就是靠變數(Variables) , 所以, 除了1. 前進是靠外部輸入驅動以外, 2,3,4 都是靠GenericDifferentialDrive 的完成通知囉.然後我們再靠一個CurrentState 的變數, 來決定我們該進行哪一個動作.當我們拖拉一個Variable 到RunL 裡面時, 看右邊的屬性表, 可以從那裏新增一個變數, 我們新增一個CurrentState,類別是int, 如下然後在輸入資料時, 就把一個Data 值為1 的作為該變數的SetValue,再把輸入的size 輸入給GenericDifferentialDrive 的DriveDistance, 設定如下:意思是以100% 的速度前進value 這樣的距離.因為等一下還需要知道使用者輸入的size, 所以也順便把size 儲存為CurrentSize (用Variable 的屬性表當中的Add 就可以新增一個變數)現在RunL 的內容應該如下:然後我們在Digram 輸入一個0.5 的值給這個RunL 的size, 如下現在請記得把RunL 裡面的GenericDifferentialDrive 設定為use a Manifest, 我們仍然可以使用LEGO.NXT.Tribot.Simulation.Manifest.xml 這個設定,你可以試跑看看, 是否會跑一個小直線呢?現在我們要接著完成2. 旋轉, 3. 前進, 4. 旋轉, 5. 通知完成這樣的步驟,對於每一個使用者自訂的Activity, 都有一個特定的稱為"Start" 的Activity, 這個的目的就是用來做為通知, 或是啟動等等的流程撰寫,在Start 裡面的流程都沒有輸出以及輸入, 但是裡面的元件可以有Notification, (Diagram 裡面的也可以有).為了要收到GenericDifferentialDrive的通知, 所以我們要把GenericDifferentialDrive 的元件放到Start 這個Activity 當中,你可以在活動編輯紅色按鈕左邊看到Action 下拉按鈕, 當中就有"Start" , 如下:建議先從原本(Action) 當中複製GenericDifferentialDrive 元件, 切換到Start Action 後, 貼上GenericDifferntialDrive 元件(當然也可以拖拉一個GenericDifferentialDrive 元件上來, 但是要注意設定要選為use a Manifest, LEGO.NXT.Tribot.Simualtion.Manifest.xml ), 你會注意到元件右邊有紅色圈圈, 那個就是Notification (通知),由於我們要打算只收到兩種通知, 分別是完成前進(DriveDistance) 動作以及完成旋轉(RotationDegrees)動作, 所以我們放兩個If 來判斷這兩種通知.接收DriveDistance 的If 要寫value.DriveDistanceStage == pleted , 而接受RotationDegrees 的If 就寫value.RotateDegreesStage == pleted , 然後將這兩個If 的判斷Merge 以後輸出給一個Calculate, 當中填入state.CurrentState + 1 , 再把這個Calculate 的結果餵給CurrentState 變數, 如下:這樣我們就完成了"收到通知以後, 將狀態+ 1 " 這件事情.但我們還要完成一件事情就是"將狀態+ 1 以後, 根據目前狀態決定該做甚麼事"所以, 設完變數以後, 再餵給另一個Calculate, 此次我們填入state.CurrentState , 然後後面再加上Switch 判斷,2 的時候就餵給GenericDifferentialDrive 一個全力(power=1)旋轉90 度,3 的時候就餵給GenericDifferentialDrive 一個全力(power=1)前進(Distance= state.CurrentSize)4 的時候就餵給GenericDifferentialDrive 一個全力(power=1)旋轉90 度,5 的時候餵給RunL (建議可以去Diagram 複製一個來用) 一個size = -1 的值, 當作結束.現在程式如下:因為我們設定了size=-1 為完成, 所以還要去Action 裏頭多做一個判斷, 當Size=-1 就發一個通知(Notification)值可以設為state.CurrentSize , 如下:最後, 我們再去Diagram 設定RunL 的通知再透過Calculate 將原本的Size + 0.3 再餵給RunL 如下:終於趕在午夜12:00 以前完成今天的程式(我又不是灰姑娘)等一下可以緊接著在明天做更好的修正囉^ ^-->。
目录i目录第一章绪论 (1)1.1 机器人开发平台现状 (1)1.2 Microsoft Robotic Studio 概述 (3)1.3 Microsoft Robotic Studio的组成 (4)1.2.1 Visual Programming Language(VPL) (4)1.2.2 Microsoft DSS Manifest Editor(DDSME) (5)1.4 本文主要研究成果与内容安排 (5)第二章 VPL的组件与功能 (7)2.1 数据类组件 (7)2.1.1 Variable(变量组件) (7)2.1.2 Calculate(计算组件) (7)2.1.3 Data(数据组件) (8)2.1.4 Math Function(数学组件) (8)2.2 逻辑类组件 (9)2.2.1 If组件 (9)2.2.2 Switch组件 (9)2.2.3 Join组件 (9)2.2.4 Merge组件 (10)2.3 输出类组件 (10)2.3.1 Simple Dialog组件 (10)2.3.2 Flexible Dialog组件 (11)2.3.3 Log组件 (12)2.3.4 TexttoSpeechTSS组件 (12)2.4 通用器件 (13)2.4.1 Generic Contact Sensors (13)2.4.2 Sick Laser Range Finder (14)2.4.3 Generic Differential Driver (14)目录ii2.5 输入类器件 (15)2.5.1 Desktop Joystick组件 (15)2.5.2 Direction Dialog组件 (15)2.5.3 Game Controller组件 (16)2.5.4 Webcam组件 (16)2.6 定义类组件 (16)2.7 本章小结 (17)第三章机器人运动规划 (19)3.1 避障规划(避障行为) (19)3.1.1 基于接触传感器的避障实现 (19)3.1.2 测距传感器的避障实现 (21)3.2 运动规划中会出现的问题 (22)3.2.1 抖动问题 (22)3.2.2 峡谷效应问题 (24)3.3 本章小结 (25)第四章基于Microsoft Robotic Studio的机器人避障的实现 (27)4.1 采用模型的选择 (27)4.2 基于激光测距传感器的避障程序实现 (30)4.3 基于接触传感器的避障程序实现 (35)4.4 本章小结 (38)第五章虚拟环境的实现与测试 (39)5.1虚拟环境简介 (39)5.2 虚拟环境的组成 (40)5.3 试验环境的设定 (41)5.4 机器人避障在虚拟环境中的实测 (44)第六章总结与展望 (47)6.1 本文总结 (47)6.2 下一步的试验方向 (48)致谢 (49)参考资料 (50)第一章绪论 1第一章绪论当今,随着低成本开发平台变得日益唾手可得,人们将机器人用于教育与最终应用的机会也在不断增加。
在这个过程中,开发环境也随着机器人的发展而发展。
开发环境如今正在不断提升自己的应用性和兼容性,一个好的开发平台将能完成机器人开发的大部分工作,包括程序设计、虚拟测试、驱动设定等。
在2006年,Microsoft®公司发布了新一代的机器人开发平台Microsoft Robotics Studio,并广泛的与机器人厂商合作,如LEGO®公司,iRobot®公司等,使该平台兼容更多机器人平台。
该平台还使用了虚拟环境进行机器人的调试,使开发成本大大降低。
其中提供的Visual Programming Language编程环境使机器人开发的进入门坎降低,使更多的学生、开发人员、爱好者能够投入到机器人开发中,在微软大旗的号召下,这个平台发展迅速,越来越多的厂商与其合作,在2008年初,微软公司正式发布了新的开发平台Microsoft Robotics Developer Studio 2008。
1.1 机器人开发平台现状“机器人软件开发平台”指的是用来给多种机器人设备开发程序的软件包。
它一般包括下列内容:·统一的编程环境·统一的编译执行环境·可重用的组建库·完备的调试/仿真环境·对多种机器人硬件设备的“驱动”程序支持通用的常用功能控制组件,例如计算机视觉技术、导航技术和机械手臂控制等[1]。
机器人控制软件的花费在整个机器人应用系统预算中占据了很大比例。
比如,一个自动控制项目的80%工作量都集中在系统集成方面,包括软件的发开和定制。
所以机器人开发平台的作用就是减少软件工程师的工作量,同时减少项目开支。
基于Microsoft Robotics Studio的机器人设计2除了软件工程的问题外,在一个真正的机器人项目中还要涉及大量的人工智能。
一个集成了许多现成的、可靠的组件库的统一软件开发平台,在应付各种机器人工程时能帮上大忙。
最后的问题是“行为协作”。
许多文献中都有对行为协作的讨论。
正因为这是一个普遍存在的问题,所以一些平台提供了统一的解决方案。
目前,主流的机器人软件开发平台有10种,见下表:表1.1 各软件开发环境第一章绪论 3表1.2 功能评测综上所述,由费用和功能方面考虑,我们选择了MSRS作为这次论文的软件开发环境,MSRS具有免费,支持硬件范围大,有部分硬件虚拟且可以重复使用自定义模块、有虚拟环境的特点,所以非常适合我们这次试验。
1.2 Microsoft Robotic Studio 概述Microsoft Robotic Studio 是一款基于Windows操作系统,为机器人爱好者、学术研究和商业开发人员对不同机器人硬件设计应用程序的平台。
这个平台包含了一些简单的REST-style程序,实时的基础服务,部分虚拟硬件和虚拟工具。
这个平台可以让开发人员为各种各样的机器人设计程序。
基于Microsoft Robotics Studio的机器人设计4Microsoft Robotic Studio包含了Visual Programming Language(VPL),这是一种基于C# 程序的新的开发软件,是机器人的开发变得非常简单。
只需要拖动框体并连接起来就可以完成自己特有的服务[2]。
同时在这个开发环境中包含了3D图形虚拟程序,可以用3D虚拟模型仿真机器人的运动。
开发环境中的虚拟工具包括AGEIA科技公司出产的AGEIA™ PhysX™ Technology,这是一种硬件加速的图形环境,可以模拟真实世界的机器人物理环境。
Microsoft Robotic Studio使用了Windows窗口或者网页作为控制界面,开发人员或操作人员可以连接网络直接控制机器人的行为。
该开发环境还自带有多种传感器的数据和驱动,在编程中可以方便的调用,同时Microsoft还与多家大型机器人开发厂商进行合作,越来越多的机器人和传感器的数据将会添加到这个开发环境里,使开发过程更加方便。
1.3 Microsoft Robotic Studio的组成Microsoft Robotic Studio包含了许多组件,主要由Visual Programming Language(VPL)、Microsoft DSS Manifest Editor(组件加载程序DDSME)、虚拟环境组成。
下面将逐一介绍这三个工具。
1.2.1 Visual Programming Language(VPL)Microsoft Visual Programming Language是一个基于图形化数据流的程序模型。
它适合于编写并行或是分布式处理程序。
VPL面对的对象是对变量和逻辑有一定概念初级程序员。
但是,VPL也不只是面对新手的,各组件可以让高级程序员进行进一步的开发。
同样的,VPL也不是只能用于机器人的开发,它在其它程序方面也有不错的表现。
VPL为程序爱好者、学生、网页程序员、高级程序员建立了一个广阔的开发环境。
第一章绪论 5 1.2.2 Microsoft DSS Manifest Editor(DDSME)Microsoft DSS Manifest Editor是为开发者建立和编辑DSS服务清单而设计的。
服务清单是一个XML文件,包含了服务列表及服务的设置。
你可以用这个程序开始一个DSS runtime服务(清单加载服务)。
DSSME的窗口包含了建立、加载和储存清单的选项。
编辑器是用来创建你所使用的连接设置文件(清单文件)的项目的。
DSSME同样包含工具栏,用来快速的连接到所需的普通命令。
1.2.3 虚拟环境Microsoft Robotics Studio的目标是加快机器人的开发、试验与应用。
在这个过程中虚拟系统扮演着重要的角色。
由于价格、广泛的应用性和强大的性能,基于PC和高端游戏机的虚拟系统出现了。
平台所提供的虚拟环境对真实世界的时间环境、物理环境进行了逼真的模拟,同时提供了一定的视觉效果。
AGEIA PhysX Technologies为这个虚拟环境提供了相当强大的图形环境[3]。
1.4 本文主要研究成果与内容安排由于这次选择的平台较新,所以当前可用的资料很少且都是英文资料,作者在译制学习的过程中同时进行了大量尝试性的试验,阅读了大量有关机器人运动规划相关文献,掌握了运动避障的程序设计及存在的问题,己经对Microsoft Robotics Studio环境下机器人程序开发有了较清楚的了解,对MSRS系统的编程与虚拟和机器人避障规划开展了系统的研究,取得了如下研究结果:1、对MSRS开发平台有了较全面的了解,并且对VPL提供的各组件进行了尝试性的试验。
2、对MSRS平台的虚拟环境进行了研究,建立了试验所用的虚拟环境,并加入了具有多种组件的机器人模型。
基于Microsoft Robotics Studio的机器人设计63、对机器人的两种避障方式进行了研究,分析了程序流程,并根据避障理论设计了试验用机器人程序。
4、对避障过程中出现的问题进行了学习,对峡谷效应和抖动现象进行了分析并研究了解决方案。
作者在前期主要尝试和学习MSRS平台的各种功能,在MSDN的资料库中进行了搜索和阅读,了解了当前MSRS平台的研究方向和研究成果。
同时还进行了机器人运动规划的学习,了解了机器人避障实现的流程和编程方法,学习了机器人的行为规则。
中期作者主要开始自行设计基于不同传感器的机器人的避障程序,并对所编写的程序进行修改和完善,解决避障运动中出现的问题,同时尝试分析这些问题,了解了峡谷效应和抖动问题。
后期作者将任务集中在论文的编写和虚拟环境的实现与调试,自行设计并完成了试验所使用的虚拟环境,并尝试在虚拟环境中测试了所完成的基于激光测距传感器的避障程序。