diff --git a/Unity/DifferentialDrive.cs b/Unity/DifferentialDrive.cs
index a0e4b99..4f573aa 100644
--- a/Unity/DifferentialDrive.cs
+++ b/Unity/DifferentialDrive.cs
@@ -2,54 +2,77 @@
using UnityEngine;
namespace RoboidControl.Unity {
+
+ ///
+ /// The Unity representation of a Roboid Control differential drive
+ ///
public class DifferentialDrive : Thing {
- public Wheel leftWheel;
- public Wheel rightWheel;
- public SphereCollider casterWheel;
-
- protected RoboidControl.DifferentialDrive coreDrive => core as RoboidControl.DifferentialDrive;
+ ///
+ /// The core differential drive
+ ///
+ public RoboidControl.DifferentialDrive coreDrive => core as RoboidControl.DifferentialDrive;
///
/// Create the Unity representation
///
- /// The core touch sensor
+ /// The core touch sensor
/// The Unity representation of the touch sensor
- public static DifferentialDrive Create(RoboidControl.DifferentialDrive core) {
- DifferentialDrive component = null;
- Rigidbody rb = null;
+ /// This uses a 'DifferentialDrive' resource when available for the Unity representation.
+ /// If this is not available, a default representation is created.
+ public static DifferentialDrive Create(RoboidControl.DifferentialDrive coreDrive) {
+ DifferentialDrive differentialDrive;
GameObject prefab = (GameObject)Resources.Load("DifferentialDrive");
if (prefab != null) {
// Use resource prefab when available
GameObject gameObj = Instantiate(prefab);
- component = gameObj.GetComponent();
- if (component != null)
- component.core = core;
-
- rb = component.GetComponent();
+ differentialDrive = gameObj.GetComponent();
+ differentialDrive.Init(coreDrive);
}
else {
- // Fallback implementation
- GameObject gameObj = new(core.name);
- component = gameObj.AddComponent();
- component.Init(core);
+ // Default implementation
+ GameObject gameObj = new(coreDrive.name);
+ differentialDrive = gameObj.AddComponent();
+ differentialDrive.Init(coreDrive);
- rb = gameObj.AddComponent();
+ Rigidbody rb = gameObj.AddComponent();
rb.isKinematic = false;
rb.mass = 0.1f;
}
- return component;
+ return differentialDrive;
}
+ ///
+ /// The left wheel of the differential drive
+ ///
+ public Wheel leftWheel;
+ ///
+ /// The right wheel of the differential drive
+ ///
+ public Wheel rightWheel;
+ ///
+ /// The caster wheel to keep the differential drive horizontal
+ ///
+ public SphereCollider casterWheel;
+
+ ///
+ /// The rigidbody of the differential drive
+ ///
private Rigidbody rb = null;
+ ///
+ /// Start the Unity representation
+ ///
protected virtual void Start() {
rb = GetComponent();
}
+ ///
+ /// Handle the binary event indicating a configuration change
+ ///
protected override void HandleBinary() {
- Debug.Log("Diff drive handle Binary");
- if (coreDrive.wheelRadius <= 0) // || coreDrive.wheelSeparation <= 0)
+ // Ignore it when the wheel radius is not set
+ if (coreDrive.wheelRadius <= 0)
return;
// Destroy any (generic) thing with the same id
@@ -66,7 +89,6 @@ namespace RoboidControl.Unity {
leftWheel.core ??= coreDrive.leftWheel;
SphereCollider leftWheelCollider = leftWheel.GetComponent();
leftWheelCollider.radius = coreDrive.wheelRadius;
- // leftWheelCollider.center = new Vector3(-coreDrive.wheelSeparation / 2, 0, 0);
}
// Destroy any (generic) thing with the same id
@@ -83,7 +105,6 @@ namespace RoboidControl.Unity {
rightWheel.core ??= coreDrive.rightWheel;
SphereCollider rightWheelCollider = rightWheel.GetComponent();
rightWheelCollider.radius = coreDrive.wheelRadius;
- // rightWheelCollider.center = new Vector3(coreDrive.wheelSeparation / 2, 0, 0);
}
if (casterWheel == null) {
@@ -99,6 +120,9 @@ namespace RoboidControl.Unity {
casterWheel.center = new Vector3(0, 0, -wheelSeparation);
}
+ ///
+ /// Update the Unity representation state
+ ///
protected override void FixedUpdate() {
base.FixedUpdate();
diff --git a/Unity/DistanceSensor.cs b/Unity/DistanceSensor.cs
index e27e2f7..4b81f9b 100644
--- a/Unity/DistanceSensor.cs
+++ b/Unity/DistanceSensor.cs
@@ -5,42 +5,45 @@ using UnityEngine;
namespace RoboidControl.Unity {
///
- /// The Unity representation of a distance sensor
+ /// The Unity representation of a Roboid Control distance sensor
///
public class DistanceSensor : Thing {
///
/// The core distance sensor
///
- public new RoboidControl.DistanceSensor core {
- get => (RoboidControl.DistanceSensor)base.core;
- set => base.core = value;
- }
+ public RoboidControl.DistanceSensor coreSensor => base.core as RoboidControl.DistanceSensor;
///
/// Start the Unity representation
///
protected virtual void Start() {
- if (core == null) {
- SiteServer siteServer = FindAnyObjectByType();
- SetCoreThing(new RoboidControl.DistanceSensor(siteServer.site));
- }
-
StartCoroutine(MeasureDistance());
}
///
/// Create the Unity representation of the distance sensor
///
- /// The parent of the core distance sensor
+ /// The core distance sensor
/// The Unity representation of the distance sensor
- public static DistanceSensor Create(RoboidControl.DistanceSensor core) {
- GameObject distanceObj = new("Distance sensor");
- DistanceSensor component = distanceObj.AddComponent();
- if (core.parent != null && core.parent.component != null)
- distanceObj.transform.SetParent(core.parent.component.transform, false);
-
- return component;
+ /// This uses a 'DistanceSensor' resource when available for the Unity representation.
+ /// If this is not available, a default representation is created.
+ public static DistanceSensor Create(RoboidControl.DistanceSensor coreSensor) {
+ DistanceSensor distanceSensor;
+ GameObject prefab = (GameObject)Resources.Load("DistanceSensor");
+ if (prefab != null) {
+ // Use resource prefab when available
+ GameObject gameObj = Instantiate(prefab);
+ distanceSensor = gameObj.GetComponent();
+ distanceSensor.Init(coreSensor);
+ }
+ else {
+ // Default implementation
+ GameObject distanceObj = new(coreSensor.name);
+ distanceSensor = distanceObj.AddComponent();
+ distanceSensor.Init(coreSensor);
+ }
+ return distanceSensor;
}
///
@@ -53,10 +56,10 @@ namespace RoboidControl.Unity {
Thing thing = hitInfo.transform.GetComponentInParent();
if (thing == null) {
// Debug.Log($"collision {hitInfo.transform.name} {hitInfo.distance}");
- core.distance = hitInfo.distance;
+ coreSensor.distance = hitInfo.distance;
}
else
- core.distance = 0;
+ coreSensor.distance = 0;
}
yield return new WaitForSeconds(0.1f);
}
diff --git a/Unity/Motor.cs b/Unity/Motor.cs
index 9995cee..3c15cdd 100644
--- a/Unity/Motor.cs
+++ b/Unity/Motor.cs
@@ -2,50 +2,73 @@
using UnityEngine;
namespace RoboidControl.Unity {
+ ///
+ /// The Unity representation of a Roboid Control motor
+ ///
public class Motor : Thing {
-
- public float maxSpeed = 5;
+
///
- /// Create the Unity representation
+ /// The core motor
///
- /// The core motor
+ public RoboidControl.Motor coreMotor => base.core as RoboidControl.Motor;
+
+ ///
+ /// Create the Unity representation of the motor
+ ///
+ /// The core motor
/// The Unity representation of a motor
- public static Motor Create(RoboidControl.Motor core) {
+ /// This uses a 'Motor' resource when available for the Unity representation.
+ /// If this is not available, a default representation is created.
+ public static Motor Create(RoboidControl.Motor coreMotor) {
+ Motor motor;
GameObject prefab = (GameObject)Resources.Load("Motor");
if (prefab != null) {
// Use resource prefab when available
GameObject gameObj = Instantiate(prefab);
- Motor component = gameObj.GetComponent();
- if (component != null)
- component.core = core;
- return component;
+ motor = gameObj.GetComponent();
+ motor.Init(coreMotor);
}
else {
- // Fallback implementation
- GameObject gameObj = new(core.name);
- Motor component = gameObj.AddComponent();
- component.Init(core);
+ // Default implementation
+ GameObject gameObj = new(coreMotor.name);
+ motor = gameObj.AddComponent();
+ motor.Init(coreMotor);
Rigidbody rb = gameObj.AddComponent();
rb.isKinematic = true;
- return component;
}
+ return motor;
}
- public float rotationSpeed = 0.0f;
+ ///
+ /// The maximum rotation speed of the motor in rotations per second
+ ///
+ public float maxSpeed = 5;
+ ///
+ /// The actual rotation speed in rotations per second
+ ///
+ public float rotationSpeed { get; protected set; }
+
+ ///
+ /// Update the Unity state
+ ///
+ protected override void FixedUpdate() {
+ base.FixedUpdate();
+ // We rotate the first child of the motor, which should be the axle.
+ float rotation = 360 * this.rotationSpeed * Time.fixedDeltaTime;
+ if (this.transform.childCount > 0)
+ this.transform.GetChild(0).Rotate(rotation, 0, 0);
+ }
+
+ ///
+ /// Handle the binary event containing the rotation speed
+ ///
protected override void HandleBinary() {
RoboidControl.Motor coreMotor = core as RoboidControl.Motor;
this.rotationSpeed = coreMotor.targetSpeed * maxSpeed;
}
- protected override void Update() {
- base.Update();
- // We rotate the first child of the motor, which should be the axle.
- float rotation = 360 * this.rotationSpeed * Time.deltaTime;
- if (this.transform.childCount > 0)
- this.transform.GetChild(0).Rotate(rotation, 0, 0);
- }
}
}
#endif
\ No newline at end of file
diff --git a/Unity/Thing.cs b/Unity/Thing.cs
index 51ae580..ab2fea1 100644
--- a/Unity/Thing.cs
+++ b/Unity/Thing.cs
@@ -6,35 +6,25 @@ using UnityEngine.Networking;
namespace RoboidControl.Unity {
///
- /// The representation of a Thing in Unity
+ /// The Unity representation fo a Roboid Control Thing
///
public class Thing : MonoBehaviour {
///
/// The core C# thing
///
- //[field: SerializeField]
public RoboidControl.Thing core { get; set; }
- public SiteServer participant;
-
- private string modelUrl = null;
+ ///
+ /// The owner of this thing
+ ///
+ public Participant owner;
///
- /// Set the core C# thing
+ /// Create a Unity representation of a Thing
///
- protected void SetCoreThing(RoboidControl.Thing thing) {
- core = thing;
- core.component = this;
-
- SiteServer siteServer = FindAnyObjectByType();
- if (siteServer == null || siteServer.site == null) {
- Debug.LogWarning("No site server found");
- return;
- }
- siteServer.site.Add(thing);
- }
-
+ /// The core of the thing
+ /// The created thing
public static Thing Create(RoboidControl.Thing core) {
// Debug.Log("Creating new Unity thing");
GameObject gameObj = string.IsNullOrEmpty(core.name) ?
@@ -45,11 +35,17 @@ namespace RoboidControl.Unity {
return component;
}
+ ///
+ /// Initialize the Thing
+ ///
+ /// The core of the thing
+ /// This affects the parent and pose of the thing
protected void Init(RoboidControl.Thing core) {
this.core = core;
this.core.component = this;
- this.participant = FindAnyObjectByType();
- core.owner = this.participant.coreParticipant;
+ this.owner = FindAnyObjectByType();
+ core.owner = this.owner.coreParticipant;
+
if (core.parent != null && core.parent.component != null) {
this.transform.SetParent(core.parent.component.transform, false);
this.transform.localPosition = Vector3.zero;
@@ -62,7 +58,7 @@ namespace RoboidControl.Unity {
}
///
- /// Update the Unity representation
+ /// Update the Unity rendering
///
protected virtual void Update() {
if (core == null)
@@ -79,10 +75,16 @@ namespace RoboidControl.Unity {
}
}
+ ///
+ /// Update the Unity state (just calls UpdateThing)
+ ///
protected virtual void FixedUpdate() {
UpdateThing();
}
+ ///
+ /// Update the Unity state
+ ///
public void UpdateThing() {
if (core == null) {
Debug.Log($"{this} core thing is gone, self destruct in 0 seconds...");
@@ -90,12 +92,16 @@ namespace RoboidControl.Unity {
return;
}
- if (core.updateQueue.TryDequeue(out RoboidControl.Thing.UpdateEvent e))
- HandleUpdateEvent(e);
+ while (core.updateQueue.TryDequeue(out RoboidControl.Thing.CoreEvent e))
+ HandleCoreEvent(e);
}
- private void HandleUpdateEvent(RoboidControl.Thing.UpdateEvent e) {
- switch (e.messageId) {
+ ///
+ /// Handle events from the core thing
+ ///
+ /// The core event to handle
+ private void HandleCoreEvent(RoboidControl.Thing.CoreEvent coreEvent) {
+ switch (coreEvent.messageId) {
case ThingMsg.id:
Debug.Log($"{this.core.id} Handle Thing");
if (core.parent == null)
@@ -113,7 +119,6 @@ namespace RoboidControl.Unity {
if (extension == ".jpg" || extension == ".png")
StartCoroutine(LoadJPG());
- this.modelUrl = core.modelUrl;
break;
case PoseMsg.Id:
Debug.Log($"{this.core.id} Handle Pose");
@@ -126,6 +131,10 @@ namespace RoboidControl.Unity {
}
}
+ ///
+ /// Load and attach a JPG sprite visualization of the thing
+ ///
+ ///
private IEnumerator LoadJPG() {
UnityWebRequest request = UnityWebRequestTexture.GetTexture(core.modelUrl);
yield return request.SendWebRequest();
@@ -153,6 +162,11 @@ namespace RoboidControl.Unity {
}
}
+ ///
+ /// Handle a Pose event
+ ///
+ /// This can update the position and/or orientation when the velocity of the thing is zero.
+ /// If a velocity is not zero, the position and/or orientation update will be ignored
protected virtual void HandlePose() {
if (core.linearVelocity.distance == 0)
this.transform.localPosition = core.position.ToVector3();
@@ -160,6 +174,10 @@ namespace RoboidControl.Unity {
this.transform.localRotation = core.orientation.ToQuaternion();
}
+
+ ///
+ /// Handle a Binary event
+ ///
protected virtual void HandleBinary() { }
}
diff --git a/Unity/TouchSensor.cs b/Unity/TouchSensor.cs
index a42cfe7..9702ffb 100644
--- a/Unity/TouchSensor.cs
+++ b/Unity/TouchSensor.cs
@@ -4,52 +4,36 @@ using UnityEngine;
namespace RoboidControl.Unity {
///
- /// The Unity representation of the TouchSensor
+ /// The Unity representation of a Roboid Control touch sensor
///
public class TouchSensor : Thing {
- // public SiteServer participant;
///
/// The core touch sensor
///
- public RoboidControl.TouchSensor coreSensor {
- get => base.core as RoboidControl.TouchSensor;
- set => base.core = value;
- }
-
- SphereCollider touchCollider = null;
+ public RoboidControl.TouchSensor coreSensor => base.core as RoboidControl.TouchSensor;
///
- /// Start the Unity represention
+ /// Create the Unity representation of the touch sensor
///
- protected virtual void Start() {
- if (core == null) {
- participant = FindAnyObjectByType();
- SetCoreThing(new RoboidControl.TouchSensor(participant.site));
- }
- touchCollider = GetComponent();
- }
-
- ///
- /// Create the Unity representation
- ///
- /// The core touch sensor
+ /// The core touch sensor
/// The Unity representation of the touch sensor
- public static TouchSensor Create(RoboidControl.TouchSensor core) {
+ /// This uses a 'TouchSensor' resource when available for the Unity representation.
+ /// If this is not available, a default representation is created.
+ public static TouchSensor Create(RoboidControl.TouchSensor coreSensor) {
+ TouchSensor touchSensor;
GameObject prefab = (GameObject)Resources.Load("TouchSensor");
if (prefab != null) {
// Use resource prefab when available
GameObject gameObj = Instantiate(prefab);
- TouchSensor component = gameObj.GetComponent();
- if (component != null)
- component.core = core;
- return component;
+ touchSensor = gameObj.GetComponent();
+ touchSensor.Init(coreSensor);
}
else {
- // Fallback implementation
- GameObject gameObj = new(core.name);
- TouchSensor component = gameObj.AddComponent();
- component.Init(core);
+ // Default implementation
+ GameObject gameObj = new(coreSensor.name);
+ touchSensor = gameObj.AddComponent();
+ touchSensor.Init(coreSensor);
Rigidbody rb = gameObj.AddComponent();
rb.isKinematic = true;
@@ -57,30 +41,33 @@ namespace RoboidControl.Unity {
SphereCollider collider = gameObj.AddComponent();
collider.radius = 0.01f;
collider.isTrigger = true;
- return component;
}
+ return touchSensor;
}
+ ///
+ /// Handle touch trigger collider enter event
+ ///
+ /// The collider which entered our trigger collider
private void OnTriggerEnter(Collider other) {
- // Debug.Log("Touch?");
- if (other.isTrigger) {
- // Debug.Log($" was trigger {other.name}");
- return;
- }
- if (this.transform.root == other.transform.root) {
- Debug.Log($" was myself {other.name}");
- return;
- }
+ // Don't detect trigger colliders
+ if (other.isTrigger)
+ return;
+ // Don't touch yourself
+ if (this.transform.root == other.transform.root)
+ return;
- Debug.Log($"*** {this} Touch");
- this.coreSensor.touchedSomething = true;
- this.core.updateQueue.Enqueue(new RoboidControl.Thing.UpdateEvent(BinaryMsg.Id));
+ this.coreSensor.touchedSomething = true;
+ this.core.updateQueue.Enqueue(new RoboidControl.Thing.CoreEvent(BinaryMsg.Id));
}
+ ///
+ /// Handl touch trigger collider exit event
+ ///
+ /// The collider which exited our trigger collider
private void OnTriggerExit(Collider other) {
if (other.isTrigger)
return;
- Debug.Log($"*** {this} Touch end");
this.coreSensor.touchedSomething = false;
}
}
diff --git a/Unity/Wheel.cs b/Unity/Wheel.cs
index e40891d..53b7820 100644
--- a/Unity/Wheel.cs
+++ b/Unity/Wheel.cs
@@ -2,6 +2,10 @@
using UnityEngine;
namespace RoboidControl.Unity {
+
+ ///
+ /// The Unity representation of a Roboid Control wheel
+ ///
public class Wheel : Motor {
///
/// Create the Unity representation
diff --git a/src/Thing.cs b/src/Thing.cs
index da6ce39..af90a11 100644
--- a/src/Thing.cs
+++ b/src/Thing.cs
@@ -138,7 +138,7 @@ namespace RoboidControl {
if (_name != value) {
_name = value;
nameChanged = true;
- this.updateQueue.Enqueue(new UpdateEvent(NameMsg.Id));
+ this.updateQueue.Enqueue(new CoreEvent(NameMsg.Id));
}
}
}
@@ -153,7 +153,7 @@ namespace RoboidControl {
set {
if (_modelUrl != value) {
_modelUrl = value;
- this.updateQueue.Enqueue(new UpdateEvent(ModelUrlMsg.Id));
+ this.updateQueue.Enqueue(new CoreEvent(ModelUrlMsg.Id));
}
}
}
@@ -188,7 +188,7 @@ namespace RoboidControl {
value.AddChild(this);
}
this.hierarchyChanged = true;
- this.updateQueue.Enqueue(new UpdateEvent(ThingMsg.id));
+ this.updateQueue.Enqueue(new CoreEvent(ThingMsg.id));
}
}
@@ -283,7 +283,7 @@ namespace RoboidControl {
if (_position != value) {
_position = value;
positionUpdated = true;
- updateQueue.Enqueue(new UpdateEvent(PoseMsg.Id));
+ updateQueue.Enqueue(new CoreEvent(PoseMsg.Id));
}
}
}
@@ -321,7 +321,7 @@ namespace RoboidControl {
if (_linearVelocity != value) {
_linearVelocity = value;
linearVelocityUpdated = true;
- updateQueue.Enqueue(new UpdateEvent(PoseMsg.Id));
+ updateQueue.Enqueue(new CoreEvent(PoseMsg.Id));
}
}
}
@@ -340,7 +340,7 @@ namespace RoboidControl {
if (_angularVelocity != value) {
_angularVelocity = value;
angularVelocityUpdated = true;
- updateQueue.Enqueue(new UpdateEvent(PoseMsg.Id));
+ updateQueue.Enqueue(new CoreEvent(PoseMsg.Id));
}
}
}
@@ -396,13 +396,13 @@ namespace RoboidControl {
}
}
- public class UpdateEvent {
- public UpdateEvent(int messageId) {
+ public class CoreEvent {
+ public CoreEvent(int messageId) {
this.messageId = messageId;
}
public int messageId; // see the communication messages
};
- public ConcurrentQueue updateQueue = new();
+ public ConcurrentQueue updateQueue = new();
#endregion Update
diff --git a/src/Things/DifferentialDrive.cs b/src/Things/DifferentialDrive.cs
index 97a35c4..45203a8 100644
--- a/src/Things/DifferentialDrive.cs
+++ b/src/Things/DifferentialDrive.cs
@@ -76,7 +76,7 @@ namespace RoboidControl {
// this.rightWheel.position = new Spherical(distance, Direction.right);
owner.Send(new BinaryMsg(owner.networkId, this));
- this.updateQueue.Enqueue(new UpdateEvent(BinaryMsg.Id));
+ this.updateQueue.Enqueue(new CoreEvent(BinaryMsg.Id));
}
/// @brief Directly specify the speeds of the motors
@@ -165,7 +165,7 @@ namespace RoboidControl {
this.rightWheel = this.owner.Get(rightWheelId) as Motor;
this._wheelRadius = LowLevelMessages.ReceiveFloat16(data, ref ix);
//this._wheelSeparation = LowLevelMessages.ReceiveFloat16(data, ref ix);
- this.updateQueue.Enqueue(new UpdateEvent(BinaryMsg.Id));
+ this.updateQueue.Enqueue(new CoreEvent(BinaryMsg.Id));
}
};
diff --git a/src/Things/EncoderMotor.cs b/src/Things/EncoderMotor.cs
index a31a31a..01d6ac6 100644
--- a/src/Things/EncoderMotor.cs
+++ b/src/Things/EncoderMotor.cs
@@ -37,7 +37,7 @@ namespace RoboidControl {
set {
if (value != this._targetAngularSpeed) {
this._targetAngularSpeed = value;
- updateQueue.Enqueue(new UpdateEvent(BinaryMsg.Id));
+ updateQueue.Enqueue(new CoreEvent(BinaryMsg.Id));
owner.Send(new BinaryMsg(this));
}
}
diff --git a/src/Things/Motor.cs b/src/Things/Motor.cs
index eaf6081..1b09654 100644
--- a/src/Things/Motor.cs
+++ b/src/Things/Motor.cs
@@ -25,7 +25,7 @@ namespace RoboidControl {
set {
if (value != _targetSpeed) {
_targetSpeed = Float.Clamp(value, -1, 1);
- updateQueue.Enqueue(new UpdateEvent(BinaryMsg.Id));
+ updateQueue.Enqueue(new CoreEvent(BinaryMsg.Id));
owner.Send(new BinaryMsg(this));
}
}