首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> 關於.NET

Microsoft Robotics Studio 遠程控制機器人開發全攻略

     編輯:關於.NET

Microsoft Robotics Studio (MRDS) 基於 .NET/.NET CF,若機器人無法運行 .NET,需在 PC 端構建遠程控制服務。本文詳細講解四大核心環節。

架構概覽

PC與機器人遠程連接架構 LegoNxt服務架構

  • PC 端服務實現 MRDS 通用協議(Motor、Bumper、Sonar 等),隱藏硬件細節,供 VPL 統一調用。
  • 機器人端運行通信接口程序(單片機/ARM 等),循環讀取傳感器、發送數據、處理電機指令。
  • Brick Service:PC 端抽象機器人實體,負責串口/藍牙通信、狀態維護、指令分發。

步驟一:機器人端通信接口

若硬件已提供(如 NXT、iRobot Create),可跳過。否則需自行開發:循環輪詢傳感器 → 發送數據至 PC;接收電機指令 → 驅動硬件。

步驟二:PC 端 Brick Service 核心實現

串口配置與數據收發

SerialPort serialPort = new SerialPort();
void Open(int comPort, int baudRate)
{
    serialPort = new SerialPort("COM" + comPort, baudRate);
    serialPort.Encoding = Encoding.Default;
    serialPort.Parity = Parity.None;
    serialPort.DataBits = 8;
    serialPort.StopBits = StopBits.One;
    serialPort.DataReceived += SerialPort_DataReceived;
    serialPort.Open();
}
void SendData(byte[] buffer) { serialPort.Write(buffer, 0, buffer.Length); }

內部端口與獨占處理

收到數據先發往內部端口 _myRobotInboundPort,再由獨占接收器更新狀態:

void SerialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
    _myRobotInboundPort.Post(sensorMsg); // 不直接改狀態
}

protected override void Start()
{
    var main = ActivateDsspOperationHandlers();
    main.CombineWith(new Interleave(
        new TeardownReceiverGroup(),
        new ExclusiveReceiverGroup(
            Arbiter.ReceiveWithIterator(true, _myRobotInboundPort, MyRobotSensorMessageHandler)
        ),
        new ConcurrentReceiverGroup()
    ));
}

private IEnumerator MyRobotSensorMessageHandler(SensorNotification msg)
{
    _state.sensor = msg.sensor; // 獨占更新狀態
    yield break;
}

步驟三:自定義訂閱——傳感器數據按需分發

標準訂閱推送所有傳感器數據,浪費頻寬。SelectiveSubscribe 允許訂閱者指定關注的傳感器名單(邏輯 OR:任一變化即通知)。

類型定義

public class MyBrickServiceOperations : PortSet<
    DsspDefaultLookup, DsspDefaultDrop, Get,
    SelectiveSubscribe, Subscribe> {}

public class SelectiveSubscribe : Subscribe<
    MySubscribeRequestType, PortSet<SubscribeResponseType, Fault>> {}

[DataContract]
public class MySubscribeRequestType : SubscribeRequestType
{
    [DataMember] public List<string> Sensors; // 要訂閱的傳感器名稱
}

處理器實現

[ServiceHandler(ServiceHandlerBehavior.Exclusive)]
public IEnumerator SelectiveSubscribeHandler(SelectiveSubscribe req)
{
    var sub = new submgr.InsertSubscription(
        new submgr.InsertSubscriptionMessage(req.Body.Subscriber, req.Body.Expiration, 0));
    sub.Body.NotificationCount = req.Body.NotificationCount;
    var filter = new List<submgr.QueryType>();
    foreach (string s in req.Body.Sensors)
        filter.Add(new submgr.QueryType(s.ToUpper())); // OR 邏輯
    sub.Body.QueryList = filter.ToArray();
    subMgrPort.Post(sub);
    yield return Arbiter.Choice(sub.ResponsePort,
        delegate(SubscribeResponseType rsp) { req.ResponsePort.Post(rsp); },
        delegate(Fault f) { req.ResponsePort.Post(f); });
}

通知分發


private IEnumerator MyRobotSensorMessageHandler(SensorNotification msg)
{
    _state.sensor = msg.sensor;
    var notify = new List<string> { msg.Name.ToUpper() };
    // 通知普通訂閱者
    subMgrPort.Post(new submgr.Submit(_state, DsspActions.ReplaceRequest));
    // 通知選擇性訂閱者
    subMgrPort.Post(new submgr.Submit(_state, DsspActions.ReplaceRequest, notify.ToArray()));
    yield break;
}

步驟四:通用服務——實現 MRDS 標準協議

使用 Alternate Contracts 借用現有協議(如 Motor、ContactSensorArray),無需複製定義文件。

雙端口模式

[ServicePort("/RobotOne", AllowMultipleInstances = false)]
RobotOneOperations _mainPort = new RobotOneOperations();

[AlternateServicePort(AlternateContract = motor.Contract.Identifier)]
motor.MotorOperations _motorPort = new motor.MotorOperations();
  • 主端口處理自定義操作。
  • 備用端口處理標準協議操作(SetMotorPower、Get、Subscribe 等)。

生成備用協議項目

DssInfo \o:"D:\RoboticsCommon" \s:Html bin\RoboticsCommon.dll
// 找到 Contract: https://schemas.microsoft.com/robotics/2006/05/motor.html

DssNewService.exe /service:MyRobotMotor /dir:samples\MyRobotMotor /alt:"https://schemas.microsoft.com/robotics/2006/05/motor.html"

電機服務核心邏輯

[Partner("MyBrickService", Contract = brick.Contract.Identifier, ...)]
brick.MyBrickServiceOperations _brickPort = new brick.MyBrickServiceOperations();

[ServiceHandler(ServiceHandlerBehavior.Exclusive)]
public IEnumerator SetMotorPowerHandler(motor.SetMotorPower msg)
{
    double power = msg.Body.TargetPower;
    if (_state.ReversePolarity) power *= -1;
    _state.CurrentPower = power;
    int native = (int)Math.Round(power * _state.PowerScalingFactor);

    var cmd = new brick.SetMotor { PowerSetpoint = native };
    yield return Arbiter.Choice(_brickPort.SendMotorCommand(cmd),
        delegate(DefaultUpdateResponseType ok) { msg.ResponsePort.Post(ok); },
        delegate(Fault f) { msg.ResponsePort.Post(f); });
}

碰撞傳感器服務訂閱 Brick


private void SubscribeToNXT()
{
    var notifyPort = new brick.MyBrickServiceOperations();
    var req = new brick.MySubscribeRequestType { Sensors = new List<string>() };
    foreach (var s in _state.Sensors) req.Sensors.Add("TOUCH" + s.Identifier);

    Activate(Arbiter.Choice(_brickPort.SelectiveSubscribe(req, notifyPort),
        delegate(SubscribeResponseType rsp) {
            subscribed = true;
            Activate(Arbiter.Receive(true, notifyPort, SensorNotificationHandler));
        },
        delegate(Fault f) { LogError("Subscription failed"); }));
}

private void SensorNotificationHandler(brick.Replace notify)
{
    foreach (var s in _state.Sensors)
    {
        bool pressed = notify.Body.SensorPort[s.Identifier - 1] == 1;
        if (s.Pressed != pressed)
        {
            s.Pressed = pressed; s.TimeStamp = DateTime.Now;
            _subMgrPort.Post(new submgr.Submit(s, DsspActions.UpdateRequest));
        }
    }
}

狀態擴展:SonarAsBumper 示例

繼承 ContactSensorArrayState,添加距離/閾值字段。主/備用端口分別掛載不同 Interleave,Get 等消息需分別實現處理器,備用端口返回基類狀態(顯式 Clone() 轉型避免序列化衝突)。

作者註:文章翻譯自 MSDN《Robotics Tutorial 6》,英文原文閱讀疲勞,翻譯以助理解。硬件經驗有限,歡迎指正。推薦 laneser 博客深度研究 MRDS。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved