前回はMicrosoft Robotics Studio DocumentationのBasic Robotics Tutorials-Robotics Tutorial 1 (C#)に従い,Visual C#でタッチセンサーが押されたらOuch(アウチ=いて!)と表示するプログラムを作成した。

 今回紹介するRobotics Tutorial2 (C#)の内容は,タッチセンサーが押されたらモーターをオン・オフすることだ。Tutorial1のプログラムにモーターを回すためのコードを追加していく。

 まず,モーターを使うために以下のusing句を追加する。

----------------------------------------------------------

 using motor = Microsoft.Robotics.Services.Motor.Proxy;

----------------------------------------------------------

 次に自分が作成しているMyTutorial1 serviceとmotor serviceの間にパートナーシップを作成する。

----------------------------------------------------------

 [Partner("motor", Contract = motor.Contract.Identifier,
  CreationPolicy = PartnerCreationPolicy.UseExisting)]
 private motor.MotorOperations _motorPort = 
  new motor.MotorOperations();

----------------------------------------------------------

 モーターサービスと通信するには,MotorOperationsポートを作成して,Partner属性で識別できるようにする必要がある。

 上記のコードを追加したクラスファイルは,MyTutorial1.csであるが,このプロジェクトにはもう一つクラスファイルがある。以下のMyTutorial1Types.csファイルである。

----------------------------------------------------------

 using Microsoft.Ccr.Core;
 using Microsoft.Dss.Core.Attributes;
 using Microsoft.Dss.ServiceModel.Dssp;
 using System;
 using System.Collections.Generic;
 using W3C.Soap;
 using mytutorial1 = Robotics.MyTutorial1;
 
 namespace Robotics.MyTutorial1
 {
  public sealed class Contract
  {
   public const String Identifier = 
    "http://schemas.tempuri.org/2007/01/mytutorial1.html";
  }
  [DataContract()]
  public class MyTutorial1State
  {
   [DataMember]
   public bool MotorOn;・・・ (1)
  }
  public class MyTutorial1Operations : 
     PortSet<DsspDefaultLookup, DsspDefaultDrop, Get>
  {
  }
  public class Get : 
   Get<GetRequestType, PortSet<MyTutorial1State, Fault>>
  {
  }
 }

----------------------------------------------------------

 MyTutorial1Types.csファイルに施す変更は,MyTutorial1StateにデータメンバーMotorOn(ブール型)を追加することだ(1)。このメンバー変数にモーターが現在回っているか,止まっているかを記憶し,タッチセンサーを押されたときにモーターを回すか止めるか判断するのだ。

 次に,MyTutorial1.csのBumperHandlerメソッドにモーターを回転させるコードを記述する。以下はMyTutorial1.csの全コードだ。

----------------------------------------------------------

using Microsoft.Ccr.Core;
using Microsoft.Dss.Core;
using Microsoft.Dss.Core.Attributes;
using Microsoft.Dss.ServiceModel.Dssp;
using Microsoft.Dss.ServiceModel.DsspServiceBase;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Xml;
using mytutorial1 = Robotics.MyTutorial1;
using bumper = Microsoft.Robotics.Services.ContactSensor.Proxy;
using motor = Microsoft.Robotics.Services.Motor.Proxy;
namespace Robotics.MyTutorial1
{
 [DisplayName("MyTutorial1")]
 [Description("The MyTutorial1 Service")]
 [Contract(Contract.Identifier)]
 public class MyTutorial1Service : DsspServiceBase
 {
  private MyTutorial1State _state = new MyTutorial1State();
  [ServicePort("/mytutorial1", AllowMultipleInstances=false)]
  private MyTutorial1Operations _mainPort = 
    new MyTutorial1Operations();

  [Partner("bumper", Contract = bumper.Contract.Identifier,
    CreationPolicy = PartnerCreationPolicy.UseExisting)]
  private bumper.ContactSensorArrayOperations _bumperPort = 
    new bumper.ContactSensorArrayOperations();

  [Partner("motor", Contract = motor.Contract.Identifier, 
    CreationPolicy = PartnerCreationPolicy.UseExisting)]
  private motor.MotorOperations _motorPort = 
    new motor.MotorOperations();
  public 
   MyTutorial1Service(DsspServiceCreationPort creationPort) : 
  base(creationPort)
  {
  }
  protected override void Start()
  {
   ActivateDsspOperationHandlers();
   SubscribeToBumpers();
   DirectoryInsert();
   LogInfo(LogGroups.Console, "Service uri: ");
  }
  void SubscribeToBumpers()
  {
   bumper.ContactSensorArrayOperations bumperNotificationPort = 
    new bumper.ContactSensorArrayOperations();

   _bumperPort.Subscribe(bumperNotificationPort);
   Activate(
    Arbiter.Receive<bumper.Update>
     (true, bumperNotificationPort, BumperHandler));
  }
  private void BumperHandler(bumper.Update notification) ・・(2)
  {
   string message;
   if (!notification.Body.Pressed)
    return;
   _state.MotorOn = !_state.MotorOn;
   motor.SetMotorPowerRequest motorRequest = 
    new motor.SetMotorPowerRequest();
   if (_state.MotorOn)
   {
    motorRequest.TargetPower = 1.0;
    message = "Motor On";
   }
   else
   {
    motorRequest.TargetPower = 0.0;
    message = "Motor Off";
   }
   _motorPort.SetMotorPower(motorRequest);
   LogInfo(LogGroups.Console, message);
   } 

   [ServiceHandler(ServiceHandlerBehavior.Concurrent)]
   public virtual IEnumerator<ITask> GetHandler(Get get)
   {
    get.ResponsePort.Post(_state);
    yield break;
   }
  }
}

----------------------------------------------------------

  (2)のBumperHandlerメソッドでモーターをオン・オフしている。具体的には,TargetPowerプロパティに数値を指定して,SetMotorPowerメソッドでモーターの回転スピードを指定する。

 この例では1.0で回転,0.0でストップだが,TargetPowerに0.3などと小さい値を指定すると,少しゆっくり回る。0.1では回らなかった。

 タッチセンサーは入力ポート1と3でセンスするが,モーターはポートAにつないだときだけ回る。なぜ出力ポートCにモーターをつないだときは回らないのか? 入力ポートと出力ポートを限定する設定はどこに記述されているのか? このあたりがまだわからない。