前回は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にモーターをつないだときは回らないのか? 入力ポートと出力ポートを限定する設定はどこに記述されているのか? このあたりがまだわからない。