现在的位置: 首页 > 专题 > 机器人 > Robotics Studio > 设计中心 > 文档 > 专题 > 机器人 > 正文

Robotics Studio学习教程:第十一天——利用 DSS 建立虚拟环境(2)

2014年04月28日 Robotics Studio, 文档, 机器人 ⁄ 转载:原文链接 ⁄ 共 6323字 ⁄ 字号 暂无评论 ⁄ 阅读 960 次

 

Microsoft Robotics Studio

Microsoft Robotics Studio

继之前分享的一篇《Robotics Studio学习教程:第十天——利用 DSS 建立虚拟环境(1)》, 我们将继续分享下一篇《Robotics Studio学习教程:第十一天——利用 DSS 建立虚拟环境(2)》,让我继续开始我们学习Visual Programming Language,以及使用Robotics Studio学习开发机器人应用的道路吧。

 

[Robotics Studio] DSS with VSE [II] -- Day11

昨天我们写了一个基本的 DSS Service , 可以操控 Visual Simulation Environment.

现在我们再来为它多加一点, 就来帮它加一个功能, 让 VPL 可以透过这个组件加入一个立方块到 VSE 当中.

我们开放这个立方块的初始位置 (X, Y, Z) , 以及这个物体 (Entity) 的名称给外部输入 , 所以在 VSE_ExampleType.cs 当中加入下面的 code:

  1. [DataContract]
  2. public class AddBoxInfo
  3. {
  4.     [DataMember]
  5.     public float X { getset; }

  6.     [DataMember]
  7.     public float Y { getset; }

  8.     [DataMember]
  9.     public float Z { getset; }

  10.     [DataMember]
  11.     public string BoxName { getset; }
  12.  
  13. }

然后, 我也想让这个组件把这些立方块 (Box) 看成是自己的状态之一, 所以我们修改 VSE_ExampleState class 的定义如下:

  1. /// <summary>
  2. /// VSE_Example state
  3. /// </summary>
  4. [DataContract]
  5. public class VSE_ExampleState
  6. {
  7.     [DataMember]
  8.     public List<string> Boxes { getset; }
  9.     public VSE_ExampleState()
  10.     {
  11.         Boxes = new List<string>();
  12.     }
  13. }

 

现在我们要帮 VSE_Example 新增一个 DSS Operation (为了不混淆, 以后就跟官方文件讲一样的话, 叫做 DSSP , 表示 DSS 对外操作的 Protocol : Decentralize Software Service Protocol)  , 不同于上次我们使用的 Submit, 这次我们改用 Insert , 连同 VSE_ExampleOperations 也加上必要的修改, 如下:

  1. /// <summary>
  2. /// VSE_Example main operations port
  3. /// </summary>
  4. [ServicePort]
  5. public class VSE_ExampleOperations : PortSet<DsspDefaultLookup, DsspDefaultDrop, Get, Subscribe, AddABox>
  6. {
  7. }

  8. [DisplayName("Add a box")]
  9. [Description("Add a box into VSE")]
  10. public class AddABox : Insert<AddBoxInfo, PortSet<DefaultInsertResponseType, Fault>>
  11. {
  12. }

 

现在我们已经用过 Submit, Insert, 为了日后不再解说, 所以我在这里先把所有内建的 DSSP 做个说明 (接下来如果你忘了 DSS 的架构图, 可以去 Day8 回忆一下).

在 Microsoft DSS Framework 当中, 为了我们写 code 方便, 已经帮我们内建了一些 DSSP, 这样日后我们要对 DSS Service 加上一些可让外部操控的功能时, 直接宣告一个 class , 采用继承 , 在继承时设定好输出入的资料形态, 然后就可以把该功能 (该 class) 加到该 DSS Service 的 MainPort 当中. 以刚刚的例子而言, 我们宣告了 AddABox 这样的 class, 继承了 DSS 内建的 Insert , 也设定好输入是 AddBoxInfo , 输出是 DefaultInsertResponseType 或是 Fault 型态. 然后把 AddABox 加入到 VSE_ExampleOperations 的 PortSet 后面的众多功能之一 , 这个 VSE_ExampleOperations 如果你去看 VSE_Example.cs (在 VSE_ExampleService 当中), 会看到

  1. /// <summary>
  2. /// Main service port
  3. /// </summary>
  4. [ServicePort("/VSE_Example", AllowMultipleInstances = true)]
  5. VSE_ExampleOperations _mainPort = new VSE_ExampleOperations();

 

所以你就知道 VSE_ExampleService 的 MainPort 就是 VSE_ExampleOperations 这个 class 的实体 (instance).

内建的 DSSP 放在 Microsoft.Dss.ServiceModel.Dssp 这个 Namespace 下面, 所以你想看说明, 可以到 RDS 安装目录的 documentation 当中找到 CcrAndDssRuntimeClassRef.chm , 当中有很多 class 的定义. 以下我要针对这些内建的 DSSP 作一些说明.

第一大类, 关乎一个 DSS Service 的生死

Create : 一般而言是 DSS 内建的 Constructor Service (属于 DSS System Service 之一) 会呼叫的, 也就是用来生成该 DSS 的实体, 所以当你写 Factory 之类的 DSS 也许可以用它. DSS 当中也内建有 Manifest loader service , 这个也会呼叫使用 Create .

Drop : 相对于 Create , 这是用来停止 (Shut down) DSS Service 的, 你可以发现我们的范例都有 DsspDefaultDrop , 就是继承自 Drop , 如果你要自己写 Handler, 记得在 ServiceHandler 的属性加上 ServiceHandlerBehavior.Teardown

第二类, 系统查询协议使用

Lookup : 用来对外揭露这个 Service 有哪些 Contracts, 一般而言 DsspDefaultLookup 就够用了.

第三大类, 用来让外界 (其他 DSS Service) 查询该 DSS Service 的状态 (state)使用

一般而言, Get, Query 都不会有 State 改变的问题, 你可以看成是读取用, 为了与写入的 DSSP Service 同步协调, 有必要在 Handler 函式的 ServiceHandler 的属性上面加上 ServiceHandlerBehavior.Concurrent . 这样所有该 DSS Service 读取用的 DSSP Handler 都可以同时执行而不会有问题.

Get : 用来让外界知道该 DSS Service 目前的状态 (state) , 一般而言就是直接把该 DSS Service 的 state 回传回去.

Query : 类似 Get, 但是是让外界取得状态的子集合, 所以一个 DSS 可以有很多个 Query, 因为状态可能数据量很多, 如果用 Get 会很耗资源, 所以可以让外界用 Query 来取得部份的状态信息.

Subscribe : 用来让其他 DSS Service 注册, 这样我们这个 DSS Service 就可以在状态改变时透过 SubscriptionManager (属于 DSS System Service 之一) 来通知注册的 DSS, 一般流程如下 (来自官方的图):

clip_image002

第四大类, 用来让外界更改或写入 DSS Service 的状态

你可以看成写入动作, 所以有必要在这类的 Handler 函式的 ServiceHandler 属性上面加上 ServiceHandlerBehavior.Exclusive , 这不但会使得所有写入动作不会一起执行 , 而且读取也不会跟写入动作同时执行(这样会造成数据不一致) . 一般而言,建议你在撰写这类 DSSP Handler 的时候, 在 DSS 更改或写入状态之前要做一些前置检查动作, 发现有问题就要及早报告失败, 更改完毕再对 SubcriptionManager 发个通知. (如上图) 最后才回报更改或写入结果.

Insert : 就是对 DSS 的 state 执行加入数据的动作.

Update : 就是对 DSS 的 state 执行更改部分数据的动作 (相较于 Replace, 这个只是更改部分数据).

Upsert : Update or Insert 的意思, 就是如果找到要变更的数据, 就变更, 找不到就新增数据. 如果没这个, 你呼叫 Update , 发现没有再来 Insert, 在这个过程当中, 很有可能别的 DSS 也来插一脚, 关于同步运算的问题就头大了. 所以有必要提供 atomic operation (一次运算完毕, 运算过程不会被其他同时运算干扰).

Delete : 相对于 Insert, 就是删除 DSS state 当中的数据.

Replace : 相较于 Update, 这个是更改 state 的全部数据 (一般做法就是把整个 state 替换掉).

最后一类 : 就是跟 DSS state 无关的 DSSP

一般而言这类 Handler 函式的 ServiceHandler 属性也是采用 ServiceHandlerBehavior.Concurrent .

Submit : 输出入的结果与 DSS state 内容没有关系, 属于独立运算之类的 DSSP.

好了, 喷完一堆口水以后, 下次我们新增 DSSP 的时候就由上面这几种当中挑选最适合的来继承.
(挑错了怎么办, 我也不知道如果你挂羊头卖狗肉会有甚么后果啊!)

回到我们刚刚写的程序, 只差最后一步了, 就是把 AddABox 的 ServiceHandler 写好.

我们在 VSE_ExampleService class 当中加上如下的 code:

  1. /// <summary>
  2. /// 在虛擬環境 (VSE) 當中加上一個立方體
  3. /// </summary>
  4. /// <param name="position"></param>
  5. /// <param name="bxname"></param>
  6. void AddBox(Vector3 position, string bxname)
  7. {
  8.     Vector3 dimensions =
  9.         new Vector3(0.2f, 0.2f, 0.2f); // meters

  10.     // create simple movable entity, with a single shape
  11.     SingleShapeEntity box = new SingleShapeEntity(
  12.         new BoxShape(
  13.             new BoxShapeProperties(
  14.             100, // mass in kilograms.
  15.             new Pose(), // relative pose
  16.             dimensions)), // dimensions
  17.         position);

  18.     // mass or density can be specified.  No need to specify both
  19.     box.State.MassDensity.Mass = 0;

  20.     // Name the entity. All entities must have unique names
  21.     box.State.Name = bxname;

  22.     // Insert entity in simulation.
  23.     SimulationEngine.GlobalInstancePort.Insert(box);
  24. }

  25. /// <summary>
  26. /// AddABox 的 ServiceHandler
  27. /// </summary>
  28. /// <param name="abx"></param>
  29. /// <returns></returns>
  30. [ServiceHandler(ServiceHandlerBehavior.Exclusive)]
  31. public IEnumerator<ITask> AddABoxHanlder(AddABox abx)
  32. {
  33.    // 先檢查是否傳了正確的資料
  34.    if (string.IsNullOrEmpty(abx.Body.BoxName))
  35.    {
  36.        abx.ResponsePort.Post(
  37.            Fault.FromCodeSubcodeReason(
  38.                FaultCodes.Sender,
  39.                DsspFaultCodes.OperationFailed, "No Name!"));
  40.        yield break;
  41.    }
  42.  
  43.     // 再檢查是否允許加入這樣的資料
  44.     if (_state.Boxes.Exists(n => String.Compare(n, abx.Body.BoxName, true) == 0))
  45.     {
  46.         abx.ResponsePort.Post(
  47.             Fault.FromCodeSubcodeReason(
  48.                 FaultCodes.Sender,
  49.                 DsspFaultCodes.DuplicateEntry, "box with that name is already exists."));
  50.         yield break;
  51.     }

  52.    // 執行 state 的變更
  53.    _state.Boxes.Add(abx.Body.BoxName);

  54.    // 在 VSE 當中加上立方塊
  55.     AddBox(new Vector3(abx.Body.X, abx.Body.Y, abx.Body.Z), abx.Body.BoxName);

  56.    // 發一個狀態變更通知
  57.     base.SendNotification(_submgrPort, abx);

  58.    // 回報結果
  59.    abx.ResponsePort.Post(DefaultInsertResponseType.Instance);

  60.    yield break;
  61. }

 

大功告成, 最后, 用  VPL 写个程序来玩玩, 如下:

clip_image004

我用了两个 SimpleDialog (不同名称 (name), 所以不是分身) , 第一个是 Prompt , 就是让用户填一串文字, 然后把该文字塞给 VSE_Example 的 Add abox, 设定在 X,Y,Z 都是 3, BoxName 则是 SimpleDialog 吐出的 TextData , 然后成功的话再重复做, 失败就跳一个 Error 的 Alert, 再回去重复.

结果就可以一直产生立方块...如下图:

clip_image006

玩到后来居然给我这个画面:

clip_image008

微软你......难怪被人叫 M$

 

让我们继续一下章教程:

《Robotics Studio学习教程:第十天——利用 DSS 建立虚拟环境(3)》

fgx

分享到:

Wopus问答

×