From f611a0755c29ceed7367d12c79b0c773f674957d Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Mon, 12 May 2025 14:56:45 +0200 Subject: [PATCH] Update docs/cleanup --- Unity/DifferentialDrive.cs | 72 ++++++++++++++++++++----------- Unity/DistanceSensor.cs | 43 ++++++++++--------- Unity/Motor.cs | 67 +++++++++++++++++++---------- Unity/Thing.cs | 70 ++++++++++++++++++------------ Unity/TouchSensor.cs | 75 ++++++++++++++------------------- Unity/Wheel.cs | 4 ++ src/Thing.cs | 18 ++++---- src/Things/DifferentialDrive.cs | 4 +- src/Things/EncoderMotor.cs | 2 +- src/Things/Motor.cs | 2 +- 10 files changed, 208 insertions(+), 149 deletions(-) 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)); } }