First step to adding differential dirve
This commit is contained in:
parent
574a8c742b
commit
25edc506a0
@ -1,39 +1,40 @@
|
|||||||
|
|
||||||
namespace RoboidControl {
|
namespace RoboidControl {
|
||||||
|
|
||||||
public class BB2B : Thing {
|
// The robot is based on a differential drive
|
||||||
readonly DifferentialDrive drive;
|
public class BB2B : DifferentialDrive {
|
||||||
readonly TouchSensor touchLeft;
|
readonly DifferentialDrive drive;
|
||||||
readonly TouchSensor touchRight;
|
readonly TouchSensor touchLeft;
|
||||||
|
readonly TouchSensor touchRight;
|
||||||
|
|
||||||
public BB2B() : base(128) { // thingType = 128
|
public BB2B(Participant owner) : base(owner) {
|
||||||
|
this.name = "BB2B";
|
||||||
|
this.wheelRadius = 0.032f;
|
||||||
|
this.wheelSeparation = 0.128f;
|
||||||
|
|
||||||
// The robot's propulsion is a differential drive
|
// Is has a touch sensor at the front left of the roboid
|
||||||
drive = new();
|
touchLeft = new(this);
|
||||||
|
// and other one on the right
|
||||||
|
touchRight = new(this);
|
||||||
|
}
|
||||||
|
|
||||||
// Is has a touch sensor at the front left of the roboid
|
public override void Update(ulong currentTimeMs, bool recurse = true) {
|
||||||
touchLeft = new(drive);
|
|
||||||
// and other one on the right
|
// The left wheel turns forward when nothing is touched on the right side
|
||||||
touchRight = new(drive);
|
// and turn backward when the roboid hits something on the right
|
||||||
|
float leftWheelSpeed = touchRight.touchedSomething ? -600.0f : 600.0f;
|
||||||
|
|
||||||
|
// The right wheel does the same, but instead is controlled by
|
||||||
|
// touches on the left side
|
||||||
|
float rightWheelSpeed = touchLeft.touchedSomething ? -600.0f : 600.0f;
|
||||||
|
|
||||||
|
// When both sides are touching something, both wheels will turn backward
|
||||||
|
// and the roboid will move backwards
|
||||||
|
|
||||||
|
this.SetWheelVelocity(leftWheelSpeed, rightWheelSpeed);
|
||||||
|
|
||||||
|
base.Update(currentTimeMs, recurse);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Update(ulong currentTimeMs, bool recurse = true) {
|
|
||||||
|
|
||||||
// The left wheel turns forward when nothing is touched on the right side
|
|
||||||
// and turn backward when the roboid hits something on the right
|
|
||||||
float leftWheelSpeed = touchRight.touchedSomething ? -600.0f : 600.0f;
|
|
||||||
|
|
||||||
// The right wheel does the same, but instead is controlled by
|
|
||||||
// touches on the left side
|
|
||||||
float rightWheelSpeed = touchLeft.touchedSomething ? -600.0f : 600.0f;
|
|
||||||
|
|
||||||
// When both sides are touching something, both wheels will turn backward
|
|
||||||
// and the roboid will move backwards
|
|
||||||
|
|
||||||
drive.SetWheelVelocity(leftWheelSpeed, rightWheelSpeed);
|
|
||||||
|
|
||||||
base.Update(currentTimeMs, recurse);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
|
@ -3,7 +3,7 @@ using RoboidControl;
|
|||||||
|
|
||||||
class Program {
|
class Program {
|
||||||
static void Main() {
|
static void Main() {
|
||||||
BB2B bb2b = new();
|
BB2B bb2b = new(ParticipantUDP.Isolated());
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
bb2b.Update();
|
bb2b.Update();
|
||||||
|
108
Unity/DifferentialDrive.cs
Normal file
108
Unity/DifferentialDrive.cs
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
#if UNITY_5_3_OR_NEWER
|
||||||
|
using System.Linq;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace RoboidControl.Unity {
|
||||||
|
public class DifferentialDrive : Thing {
|
||||||
|
|
||||||
|
public WheelCollider leftWheel;
|
||||||
|
public WheelCollider rightWheel;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Create the Unity representation
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="core">The core touch sensor</param>
|
||||||
|
/// <returns>The Unity representation of the touch sensor</returns>
|
||||||
|
public static DifferentialDrive Create(RoboidControl.DifferentialDrive core) {
|
||||||
|
GameObject gameObj = new(core.name);
|
||||||
|
DifferentialDrive component = gameObj.AddComponent<DifferentialDrive>();
|
||||||
|
component.Init(core);
|
||||||
|
|
||||||
|
Rigidbody rb = gameObj.AddComponent<Rigidbody>();
|
||||||
|
rb.isKinematic = false;
|
||||||
|
rb.mass = 0.5f;
|
||||||
|
|
||||||
|
return component;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void HandleBinary() {
|
||||||
|
RoboidControl.DifferentialDrive drive = core as RoboidControl.DifferentialDrive;
|
||||||
|
if (leftWheel == null) {
|
||||||
|
GameObject leftWheelObj = new GameObject("Left wheel");
|
||||||
|
leftWheelObj.transform.SetParent(this.transform);
|
||||||
|
leftWheel = leftWheelObj.AddComponent<WheelCollider>();
|
||||||
|
leftWheel.mass = 0.1f;
|
||||||
|
leftWheel.suspensionDistance = 0.01f;
|
||||||
|
leftWheel.suspensionSpring = new JointSpring {
|
||||||
|
spring = 1000f, // Very high spring value to make it rigid
|
||||||
|
damper = 100f, // Low damping (could be adjusted for slight 'bounciness')
|
||||||
|
targetPosition = 0.5f // Neutral position (middle of the suspension travel)
|
||||||
|
};
|
||||||
|
leftWheel.radius = drive.wheelRadius;
|
||||||
|
leftWheel.center = new Vector3(-drive.wheelSeparation / 2, 0, 0);
|
||||||
|
}
|
||||||
|
if (rightWheel == null) {
|
||||||
|
GameObject rightWheelObj = new GameObject("Left wheel");
|
||||||
|
rightWheelObj.transform.SetParent(this.transform);
|
||||||
|
rightWheel = rightWheelObj.AddComponent<WheelCollider>();
|
||||||
|
rightWheel.mass = 0.1f;
|
||||||
|
rightWheel.suspensionDistance = 0.01f;
|
||||||
|
rightWheel.suspensionSpring = new JointSpring {
|
||||||
|
spring = 1000f, // Very high spring value to make it rigid
|
||||||
|
damper = 100f, // Low damping (could be adjusted for slight 'bounciness')
|
||||||
|
targetPosition = 0.5f // Neutral position (middle of the suspension travel)
|
||||||
|
};
|
||||||
|
rightWheel.radius = drive.wheelRadius;
|
||||||
|
rightWheel.center = new Vector3(drive.wheelSeparation / 2, 0, 0);
|
||||||
|
|
||||||
|
}
|
||||||
|
// Thing[] children = this.GetComponentsInChildren<Thing>();
|
||||||
|
// if (leftWheel == null) {
|
||||||
|
// leftWheel = children.FirstOrDefault(child => child.core.id == drive.leftWheel.id);
|
||||||
|
// if (leftWheel == null) {
|
||||||
|
// RoboidControl.Thing coreThing = new(drive.owner, 0, drive.leftWheel.id, false) {
|
||||||
|
// name = "Left Wheel"
|
||||||
|
// };
|
||||||
|
// leftWheel = Thing.Create(coreThing);
|
||||||
|
// leftWheel.transform.SetParent(this.transform);
|
||||||
|
// }
|
||||||
|
// WheelCollider wheel = this.GetComponent<WheelCollider>();
|
||||||
|
// if (wheel == null)
|
||||||
|
// wheel = this.gameObject.AddComponent<WheelCollider>();
|
||||||
|
// wheel.mass = 0.1f;
|
||||||
|
// wheel.suspensionDistance = 0.01f;
|
||||||
|
// wheel.suspensionSpring = new JointSpring {
|
||||||
|
// spring = 1000f, // Very high spring value to make it rigid
|
||||||
|
// damper = 100f, // Low damping (could be adjusted for slight 'bounciness')
|
||||||
|
// targetPosition = 0.5f // Neutral position (middle of the suspension travel)
|
||||||
|
// };
|
||||||
|
// wheel.radius = drive.wheelRadius;
|
||||||
|
// wheel.center = new Vector3(-drive.wheelSeparation / 2, 0, 0);
|
||||||
|
// }
|
||||||
|
// if (rightWheel == null) {
|
||||||
|
// this.rightWheel = children.FirstOrDefault(child => child.core.id == drive.rightWheel.id);
|
||||||
|
// if (this.rightWheel == null) {
|
||||||
|
// RoboidControl.Thing coreThing = new(drive.owner, 0, drive.rightWheel.id, false) {
|
||||||
|
// name = "Right Wheel"
|
||||||
|
// };
|
||||||
|
// this.rightWheel = Thing.Create(coreThing);
|
||||||
|
// this.rightWheel.transform.SetParent(this.transform);
|
||||||
|
// }
|
||||||
|
// WheelCollider wheel = this.GetComponent<WheelCollider>();
|
||||||
|
// if (wheel == null)
|
||||||
|
// wheel = this.gameObject.AddComponent<WheelCollider>();
|
||||||
|
// wheel.mass = 0.1f;
|
||||||
|
// wheel.suspensionDistance = 0.01f;
|
||||||
|
// wheel.suspensionSpring = new JointSpring {
|
||||||
|
// spring = 1000f, // Very high spring value to make it rigid
|
||||||
|
// damper = 100f, // Low damping (could be adjusted for slight 'bounciness')
|
||||||
|
// targetPosition = 0.5f // Neutral position (middle of the suspension travel)
|
||||||
|
// };
|
||||||
|
// wheel.radius = drive.wheelRadius;
|
||||||
|
// wheel.center = new Vector3(drive.wheelSeparation / 2, 0, 0);
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif
|
@ -24,15 +24,21 @@ namespace RoboidControl.Unity {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void HandleThingEvent(RoboidControl.Participant.UpdateEvent e) {
|
protected virtual void HandleThingEvent(RoboidControl.Participant.UpdateEvent e) {
|
||||||
switch (e.thing) {
|
switch (e.thing) {
|
||||||
case RoboidControl.TouchSensor coreTouchSensor:
|
case RoboidControl.TouchSensor coreTouchSensor:
|
||||||
TouchSensor touchSensor = TouchSensor.Create(coreTouchSensor);
|
TouchSensor touchSensor = TouchSensor.Create(coreTouchSensor);
|
||||||
coreTouchSensor.component = touchSensor;
|
coreTouchSensor.component = touchSensor;
|
||||||
break;
|
break;
|
||||||
|
case RoboidControl.DifferentialDrive coreDrive:
|
||||||
|
DifferentialDrive differentialDrive = DifferentialDrive.Create(coreDrive);
|
||||||
|
coreDrive.component = differentialDrive;
|
||||||
|
break;
|
||||||
case RoboidControl.Thing coreThing:
|
case RoboidControl.Thing coreThing:
|
||||||
Thing thing = Thing.Create(coreThing);
|
if (coreThing.component != null) {
|
||||||
coreThing.component = thing;
|
Thing thing = Thing.Create(coreThing);
|
||||||
|
coreThing.component = thing;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -42,7 +42,8 @@ namespace RoboidControl.Unity {
|
|||||||
participant.coreParticipant = e.participant;
|
participant.coreParticipant = e.participant;
|
||||||
break;
|
break;
|
||||||
case ThingMsg.id:
|
case ThingMsg.id:
|
||||||
e.thing.CreateComponent();
|
HandleThingEvent(e);
|
||||||
|
//e.thing.CreateComponent();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -48,6 +48,7 @@ namespace RoboidControl.Unity {
|
|||||||
protected void Init(RoboidControl.Thing core) {
|
protected void Init(RoboidControl.Thing core) {
|
||||||
this.core = core;
|
this.core = core;
|
||||||
this.participant = FindAnyObjectByType<SiteServer>();
|
this.participant = FindAnyObjectByType<SiteServer>();
|
||||||
|
core.owner = this.participant.coreParticipant;
|
||||||
if (core.parent != null && core.parent.component != null)
|
if (core.parent != null && core.parent.component != null)
|
||||||
this.transform.SetParent(core.parent.component.transform, false);
|
this.transform.SetParent(core.parent.component.transform, false);
|
||||||
|
|
||||||
@ -105,6 +106,9 @@ namespace RoboidControl.Unity {
|
|||||||
if (core.angularVelocity.distance == 0)
|
if (core.angularVelocity.distance == 0)
|
||||||
this.transform.localRotation = core.orientation.ToQuaternion();
|
this.transform.localRotation = core.orientation.ToQuaternion();
|
||||||
break;
|
break;
|
||||||
|
case BinaryMsg.Id:
|
||||||
|
this.HandleBinary();
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -143,6 +147,7 @@ namespace RoboidControl.Unity {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected virtual void HandleBinary() {}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -36,9 +36,7 @@ namespace RoboidControl.Unity {
|
|||||||
/// <param name="core">The core touch sensor</param>
|
/// <param name="core">The core touch sensor</param>
|
||||||
/// <returns>The Unity representation of the touch sensor</returns>
|
/// <returns>The Unity representation of the touch sensor</returns>
|
||||||
public static TouchSensor Create(RoboidControl.TouchSensor core) {
|
public static TouchSensor Create(RoboidControl.TouchSensor core) {
|
||||||
GameObject gameObj = core.name != null ?
|
GameObject gameObj = new(core.name);
|
||||||
new(core.name) :
|
|
||||||
new("Touch Sensor");
|
|
||||||
TouchSensor component = gameObj.AddComponent<TouchSensor>();
|
TouchSensor component = gameObj.AddComponent<TouchSensor>();
|
||||||
component.Init(core);
|
component.Init(core);
|
||||||
|
|
||||||
|
@ -117,16 +117,7 @@ namespace RoboidControl {
|
|||||||
Console.WriteLine($"{this.name}: Process thing [{msg.networkId}/{msg.thingId}] {msg.thingType} {msg.parentId} ");
|
Console.WriteLine($"{this.name}: Process thing [{msg.networkId}/{msg.thingId}] {msg.thingType} {msg.parentId} ");
|
||||||
|
|
||||||
Thing thing = sender.Get(msg.thingId);
|
Thing thing = sender.Get(msg.thingId);
|
||||||
if (thing == null) {
|
thing ??= ProcessNewThing(sender, msg);
|
||||||
switch (msg.thingType) {
|
|
||||||
case (byte)Thing.Type.TouchSensor:
|
|
||||||
new TouchSensor(sender, msg.thingId);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (thing == null)
|
|
||||||
thing = new Thing(sender, msg.thingType, msg.thingId);
|
|
||||||
|
|
||||||
if (msg.parentId != 0) {
|
if (msg.parentId != 0) {
|
||||||
thing.parent = sender.Get(msg.parentId);
|
thing.parent = sender.Get(msg.parentId);
|
||||||
@ -139,6 +130,14 @@ namespace RoboidControl {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected virtual Thing ProcessNewThing(Participant sender, ThingMsg msg) {
|
||||||
|
return msg.thingType switch {
|
||||||
|
Thing.Type.TouchSensor => new TouchSensor(sender, msg.thingId),
|
||||||
|
Thing.Type.DifferentialDrive => new DifferentialDrive(sender, msg.thingId),
|
||||||
|
_ => new Thing(sender, msg.thingType, msg.thingId),
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
#endregion Receive
|
#endregion Receive
|
||||||
|
|
||||||
|
@ -17,7 +17,19 @@ namespace RoboidControl {
|
|||||||
/// <param name="owner">The owning participant</param>
|
/// <param name="owner">The owning participant</param>
|
||||||
/// <param name="thingId">The ID of the thing, leave out or set to zero to generate an ID</param>
|
/// <param name="thingId">The ID of the thing, leave out or set to zero to generate an ID</param>
|
||||||
/// <param name="invokeEvent">Invoke a OnNewThing event when the thing has been created</param>
|
/// <param name="invokeEvent">Invoke a OnNewThing event when the thing has been created</param>
|
||||||
public DifferentialDrive(Participant participant, byte thingId = 0, bool invokeEvent = true) : base(participant, Type.DifferentialDrive, thingId, invokeEvent) { }
|
public DifferentialDrive(Participant owner, byte thingId = 0, bool invokeEvent = true) : base(owner, Type.DifferentialDrive, thingId, invokeEvent) {
|
||||||
|
Thing leftWheel = new(this) {
|
||||||
|
name = "Left Wheel"
|
||||||
|
};
|
||||||
|
Thing rightWheel = new(this) {
|
||||||
|
name = "Right Wheel"
|
||||||
|
};
|
||||||
|
SetMotors(leftWheel, rightWheel);
|
||||||
|
sendBinary = true;
|
||||||
|
owner.Send(new BinaryMsg(owner.networkId, this));
|
||||||
|
this.updateQueue.Enqueue(new UpdateEvent(BinaryMsg.Id));
|
||||||
|
|
||||||
|
}
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Create a new child differential drive
|
/// Create a new child differential drive
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -92,17 +104,43 @@ namespace RoboidControl {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// @brief The radius of a wheel in meters
|
/// @brief The radius of a wheel in meters
|
||||||
protected float wheelRadius = 1.0f;
|
public float wheelRadius = 1.0f;
|
||||||
/// @brief The distance between the wheels in meters
|
/// @brief The distance between the wheels in meters
|
||||||
protected float wheelSeparation = 1.0f;
|
public float wheelSeparation = 1.0f;
|
||||||
|
|
||||||
/// @brief Convert revolutions per second to meters per second
|
/// @brief Convert revolutions per second to meters per second
|
||||||
protected float rpsToMs = 1.0f;
|
protected float rpsToMs = 1.0f;
|
||||||
|
|
||||||
/// @brief The left wheel
|
/// @brief The left wheel
|
||||||
protected Thing leftWheel = null;
|
public Thing leftWheel = null;
|
||||||
/// @brief The right wheel
|
/// @brief The right wheel
|
||||||
protected Thing rightWheel = null;
|
public Thing rightWheel = null;
|
||||||
|
|
||||||
|
bool sendBinary = false;
|
||||||
|
public override byte[] GenerateBinary() {
|
||||||
|
if (!sendBinary)
|
||||||
|
return System.Array.Empty<byte>();
|
||||||
|
|
||||||
|
byte[] data = new byte[6];
|
||||||
|
byte ix = 0;
|
||||||
|
data[ix++] = leftWheel.id;
|
||||||
|
data[ix++] = rightWheel.id;
|
||||||
|
LowLevelMessages.SendFloat16(data, ref ix, wheelRadius);
|
||||||
|
LowLevelMessages.SendFloat16(data, ref ix, wheelSeparation);
|
||||||
|
sendBinary = false;
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void ProcessBinary(byte[] data) {
|
||||||
|
byte ix = 0;
|
||||||
|
byte leftWheelId = data[ix++];
|
||||||
|
this.leftWheel = this.owner.Get(leftWheelId);
|
||||||
|
byte rightWheelId = data[ix++];
|
||||||
|
this.rightWheel = this.owner.Get(rightWheelId);
|
||||||
|
this.wheelRadius = LowLevelMessages.ReceiveFloat16(data, ref ix);
|
||||||
|
this.wheelSeparation = LowLevelMessages.ReceiveFloat16(data, ref ix);
|
||||||
|
this.updateQueue.Enqueue(new UpdateEvent(BinaryMsg.Id));
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace RoboidControl
|
} // namespace RoboidControl
|
@ -24,7 +24,9 @@ namespace RoboidControl {
|
|||||||
/// <param name="parent">The parent thing</param>
|
/// <param name="parent">The parent thing</param>
|
||||||
/// <param name="thingId">The ID of the thing, leave out or set to zero to generate an ID</param>
|
/// <param name="thingId">The ID of the thing, leave out or set to zero to generate an ID</param>
|
||||||
/// <param name="invokeEvent">Invoke a OnNewThing event when the thing has been created</param>
|
/// <param name="invokeEvent">Invoke a OnNewThing event when the thing has been created</param>
|
||||||
public TouchSensor(Thing parent, byte thingId = 0, bool invokeEvent = true) : base(parent, Type.TouchSensor, thingId, invokeEvent) { }
|
public TouchSensor(Thing parent, byte thingId = 0, bool invokeEvent = true) : base(parent, Type.TouchSensor, thingId, invokeEvent) {
|
||||||
|
this.name = "TouchSensor";
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Value which is true when the sensor is touching something, false otherwise
|
/// Value which is true when the sensor is touching something, false otherwise
|
||||||
|
Loading…
x
Reference in New Issue
Block a user