Completed things docs

This commit is contained in:
Pascal Serrarens 2025-04-30 11:41:10 +02:00
parent 346263d311
commit 09783d2103
6 changed files with 214 additions and 48 deletions

View File

@ -109,7 +109,7 @@ namespace RoboidControl {
if (thing == null) { if (thing == null) {
switch (msg.thingType) { switch (msg.thingType) {
case (byte)Thing.Type.TouchSensor: case (byte)Thing.Type.TouchSensor:
new TouchSensor(sender, msg.networkId, msg.thingId); new TouchSensor(sender, msg.thingId);
break; break;
} }
} }

View File

@ -27,9 +27,10 @@ namespace RoboidControl {
public const byte Servo = 0x08; public const byte Servo = 0x08;
// Other // Other
public const byte Roboid = 0x09; public const byte Roboid = 0x09;
public const byte HUmanoid = 0x010; public const byte HUmanoid = 0x0A;
public const byte ExternalSensor = 0x11; public const byte ExternalSensor = 0x0B;
public const byte Animator = 0x40; public const byte Animator = 0x0C;
public const byte DifferentialDrive = 0x0D;
} }
#region Init #region Init
@ -67,7 +68,7 @@ namespace RoboidControl {
/// <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>
/// <note>The owner will be the same as the owner of the parent thing</note> /// <note>The owner will be the same as the owner of the parent thing</note>
public Thing(Thing parent, byte thingType = Type.Undetermined, bool invokeEvent = true) : this(parent.owner, thingType, 0, invokeEvent) { public Thing(Thing parent, byte thingType = Type.Undetermined, byte thingId = 0, bool invokeEvent = true) : this(parent.owner, thingType, thingId, invokeEvent) {
this.parent = parent; this.parent = parent;
} }
@ -424,7 +425,7 @@ namespace RoboidControl {
/// <summary> /// <summary>
/// Function used to process binary data received for this thing /// Function used to process binary data received for this thing
/// </summary> /// </summary>
/// <param name="bytes">The binary data</param> /// <param name="bytes">The binary data to process</param>
public virtual void ProcessBinary(byte[] bytes) { public virtual void ProcessBinary(byte[] bytes) {
} }

View File

@ -1,14 +1,30 @@
using LinearAlgebra;
namespace RoboidControl { namespace RoboidControl {
/// @brief A thing which can move itself using a differential drive system /// @brief A thing which can move itself using a differential drive system
/// ///
/// @sa @link https://en.wikipedia.org/wiki/Differential_wheeled_robot @endlink /// @sa @link https://en.wikipedia.org/wiki/Differential_wheeled_robot @endlink
public class DifferentialDrive : Thing { public class DifferentialDrive : Thing {
/// @brief Create a differential drive without networking support /// <summary>
public DifferentialDrive() { } /// Create a differential drive without communication abilities
/// @brief Create a differential drive with networking support /// </summary
/// @param participant The local participant /// <param name="invokeEvent">Invoke a OnNewThing event when the thing has been created</param>
public DifferentialDrive(ParticipantUDP participant) : base(participant, Type.Undetermined) { } public DifferentialDrive(bool invokeEvent = true) : base(Type.DifferentialDrive, invokeEvent) { }
/// <summary>
/// Create a differential drive for a participant
/// </summary>
/// <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="invokeEvent">Invoke a OnNewThing event when the thing has been created</param>
public DifferentialDrive(ParticipantUDP participant, byte thingId = 0, bool invokeEvent = true) : base(participant, Type.DifferentialDrive, thingId, invokeEvent) { }
/// <summary>
/// Create a new child differential drive
/// </summary>
/// <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="invokeEvent">Invoke a OnNewThing event when the thing has been created</param>
public DifferentialDrive(Thing parent, byte thingId = 0, bool invokeEvent = true) : base(parent, Type.DifferentialDrive, thingId, invokeEvent) { }
/// @brief Configures the dimensions of the drive /// @brief Configures the dimensions of the drive
/// @param wheelDiameter The diameter of the wheels in meters /// @param wheelDiameter The diameter of the wheels in meters
@ -17,21 +33,63 @@ namespace RoboidControl {
/// These values are used to compute the desired wheel speed from the set /// These values are used to compute the desired wheel speed from the set
/// linear and angular velocity. /// linear and angular velocity.
/// @sa SetLinearVelocity SetAngularVelocity /// @sa SetLinearVelocity SetAngularVelocity
public void SetDriveDimensions(float wheelDiameter, float wheelSeparation) { } public void SetDriveDimensions(float wheelDiameter, float wheelSeparation) {
this.wheelRadius = wheelDiameter > 0 ? wheelDiameter / 2 : -wheelDiameter / 2;
this.wheelSeparation = wheelSeparation > 0 ? wheelSeparation : -wheelSeparation;
this.rpsToMs = wheelDiameter * Angle.pi;
float distance = this.wheelSeparation / 2;
if (this.leftWheel != null)
this.leftWheel.position = new Spherical(distance, Direction.left);
if (this.rightWheel != null)
this.rightWheel.position = new Spherical(distance, Direction.right);
}
/// @brief Congures the motors for the wheels /// @brief Congures the motors for the wheels
/// @param leftWheel The motor for the left wheel /// @param leftWheel The motor for the left wheel
/// @param rightWheel The motor for the right wheel /// @param rightWheel The motor for the right wheel
public void SetMotors(Thing leftWheel, Thing rightWheel) { } public void SetMotors(Thing leftWheel, Thing rightWheel) {
float distance = this.wheelSeparation / 2;
this.leftWheel = leftWheel;
if (this.leftWheel != null)
this.leftWheel.position = new Spherical(distance, Direction.left);
this.rightWheel = rightWheel;
if (this.rightWheel != null)
this.rightWheel.position = new Spherical(distance, Direction.right);
}
/// @brief Directly specify the speeds of the motors /// @brief Directly specify the speeds of the motors
/// @param speedLeft The speed of the left wheel in degrees per second. /// @param speedLeft The speed of the left wheel in degrees per second.
/// Positive moves the robot in the forward direction. /// Positive moves the robot in the forward direction.
/// @param speedRight The speed of the right wheel in degrees per second. /// @param speedRight The speed of the right wheel in degrees per second.
/// Positive moves the robot in the forward direction. /// Positive moves the robot in the forward direction.
public void SetWheelVelocity(float speedLeft, float speedRight) { } public void SetWheelVelocity(float speedLeft, float speedRight) {
if (this.leftWheel != null)
this.leftWheel.angularVelocity = new Spherical(speedLeft, Direction.left);
if (this.rightWheel != null)
this.rightWheel.angularVelocity = new Spherical(speedRight, Direction.right);
}
/// @copydoc RoboidControl::Thing::Update(unsigned long) /// @copydoc RoboidControl::Thing::Update(unsigned long)
public override void Update(ulong currentMs, bool recursive = true) { } public override void Update(ulong currentMs, bool recursive = true) {
if (this.linearVelocityUpdated) {
// this assumes forward velocity only....
float linearVelocity = this.linearVelocity.distance;
Spherical angularVelocity = this.angularVelocity;
float angularSpeed = angularVelocity.distance * Angle.Deg2Rad;
// Determine the rotation direction
if (angularVelocity.direction.horizontal < 0)
angularSpeed = -angularSpeed;
// wheel separation can be replaced by this.leftwheel.position.distance
float speedLeft = (linearVelocity + angularSpeed * this.wheelSeparation / 2) / this.wheelRadius * Angle.Rad2Deg;
float speedRight = (linearVelocity - angularSpeed * this.wheelSeparation / 2) / this.wheelRadius * Angle.Rad2Deg;
this.SetWheelVelocity(speedLeft, speedRight);
}
}
/// @brief The radius of a wheel in meters /// @brief The radius of a wheel in meters
protected float wheelRadius = 1.0f; protected float wheelRadius = 1.0f;

View File

@ -0,0 +1,74 @@
using System;
namespace RoboidControl {
/// <summary>
/// A sensor which can detect touches
/// </summary>
public class DigitalSensor : Thing {
/// <summary>
/// Create a digital sensor without communication abilities
/// </summary>
/// <param name="invokeEvent">Invoke a OnNewThing event when the thing has been created</param>
public DigitalSensor(bool invokeEvent = true) : base(Type.Switch, invokeEvent) { }
/// <summary>
/// Create a digital sensor for a participant
/// </summary>
/// <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="invokeEvent">Invoke a OnNewThing event when the thing has been created</param>
public DigitalSensor(Participant owner, byte thingId = 0, bool invokeEvent = true) : base(owner, Type.Switch, thingId, invokeEvent) { }
/// <summary>
/// Create a new child digital sensor
/// </summary>
/// <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="invokeEvent">Invoke a OnNewThing event when the thing has been created</param>
public DigitalSensor(Thing parent, byte thingId = 0, bool invokeEvent = true) : base(parent, Type.Switch, thingId, invokeEvent) { }
/// <summary>
/// Value which is true when the sensor is touching something, false otherwise
/// </summary>
private bool _state = false;
public bool state {
get { return _state; }
set {
if (_state != value) {
_state = value;
}
stateUpdated = true;
}
}
private bool stateUpdated = false;
#if UNITY_5_3_OR_NEWER
/// @copydoc Passer::RoboidControl::Thing::CreateComponent
public override void CreateComponent() {
this.component = Unity.DigitalSensor.Create(this);
this.component.core = this;
}
#endif
/// <summary>
/// Function used to generate binary data for this digital sensor
/// </summary>
/// <returns>A byte array with the binary data</returns>
/// <remark>The byte array will be empty when the digital status has not changed</remark>
public override byte[] GenerateBinary() {
if (!stateUpdated)
return Array.Empty<byte>();
byte[] bytes = new byte[1];
bytes[0] = (byte)(state ? 1 : 0);
stateUpdated = false;
return bytes;
}
/// <summary>
/// Function used to process binary data received for this digital sensor
/// </summary>
/// <param name="bytes">The binary data to process</param>
public override void ProcessBinary(byte[] bytes) {
this.state |= (bytes[0] == 1);
}
}
}

View File

@ -1,4 +1,4 @@
//using System; using System;
namespace RoboidControl { namespace RoboidControl {
@ -6,27 +6,50 @@ namespace RoboidControl {
/// A temperature sensor /// A temperature sensor
/// </summary> /// </summary>
public class TemperatureSensor : Thing { public class TemperatureSensor : Thing {
/// <summary>
/// Create a temperature sensor without communication abilities
/// </summary>
/// <param name="invokeEvent">Invoke a OnNewThing event when the thing has been created</param>
public TemperatureSensor(bool invokeEvent = true) : base(Type.TemperatureSensor, invokeEvent) { }
/// <summary>
/// Create a temperature sensor for a participant
/// </summary>
/// <param name="owner">The participant for with the sensor is needed</param>
/// <param name="thingId">The ID of the thing</param>
/// <param name="invokeEvent">Invoke a OnNewThing event when the thing has been created</param>
public TemperatureSensor(Participant owner, byte thingId = 0, bool invokeEvent = true) : base(owner, Type.TemperatureSensor, thingId, invokeEvent) { }
/// <summary>
/// Create a new child temperature sensor
/// </summary>
/// <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="invokeEvent">Invoke a OnNewThing event when the thing has been created</param>
public TemperatureSensor(Thing parent, byte thingId = 0, bool invokeEvent = true) : base(parent, Type.TemperatureSensor, thingId, invokeEvent) { }
/// <summary> /// <summary>
/// The measured temperature /// The measured temperature
/// </summary> /// </summary>
public float temperature = 0; public float temperature = 0;
/// <summary> /// <summary>
/// Create a temperature sensor with the given ID /// Function used to generate binary data for this temperature sensor
/// </summary> /// </summary>
/// <param name="participant">The participant for with the sensor is needed</param> /// <returns>A byte array with the binary data</returns>
/// <param name="networkId">The network ID of the sensor</param> public override byte[] GenerateBinary() {
/// <param name="thingId">The ID of the thing</param> byte[] bytes = new byte[2];
public TemperatureSensor(Participant participant, byte thingId) : base(participant, Type.TemperatureSensor, thingId) { } byte ix = 0;
LowLevelMessages.SendFloat16(bytes, ref ix, this.temperature);
return bytes;
}
/// <summary> /// <summary>
/// Function to extract the temperature received in the binary message /// Function to process the temperature from the binary data
/// </summary> /// </summary>
/// <param name="bytes">The byte array</param> /// <param name="bytes">The binary data to process</param>
public override void ProcessBinary(byte[] bytes) { public override void ProcessBinary(byte[] bytes) {
byte ix = 0; byte ix = 0;
this.temperature = LowLevelMessages.ReceiveFloat16(bytes, ref ix); this.temperature = LowLevelMessages.ReceiveFloat16(bytes, ref ix);
//Console.WriteLine($"temperature {this.name} = {this.temperature} C");
} }
} }

View File

@ -6,32 +6,29 @@ namespace RoboidControl {
/// A sensor which can detect touches /// A sensor which can detect touches
/// </summary> /// </summary>
public class TouchSensor : Thing { public class TouchSensor : Thing {
/// <summary> /// <summary>
/// Create a touch sensor /// Create a touch sensor without communication abilities
/// </summary> /// </summary>
/// <param name="owner">The participant for with the sensor is needed</param> /// <param name="invokeEvent">Invoke a OnNewThing event when the thing has been created</param>
/// <param name="invokeEvent">True when the creation should trigger an event</param> public TouchSensor(bool invokeEvent = true) : base(Type.TouchSensor, invokeEvent) { }
public TouchSensor(Participant owner) : base(owner, Type.TouchSensor) { /// <summary>
Console.Write("TouchSensor constructor"); /// Create a touch sensor for a participant
//touchedSomething = false; /// </summary>
//thisParticipant = owner; /// <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="invokeEvent">Invoke a OnNewThing event when the thing has been created</param>
public TouchSensor(Participant owner, byte networkId, byte thingId) : base(owner, networkId, thingId) { public TouchSensor(Participant owner, byte thingId = 0, bool invokeEvent = true) : base(owner, Type.TouchSensor, thingId, invokeEvent) { }
// Console.Write("TouchSensor constructor"); /// <summary>
//touchedSomething = false; /// Create a new child touch sensor
//thisParticipant = participant; /// </summary>
} /// <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>
public TouchSensor(Thing parent, bool invokeEvent = true) : base(parent, (byte)Type.TouchSensor, invokeEvent) { } /// <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 ParticipantUDP thisParticipant;
/// <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
/// </summary> /// </summary>
//public bool touchedSomething = false;
private bool _touchedSomething = false; private bool _touchedSomething = false;
public bool touchedSomething { public bool touchedSomething {
get { return _touchedSomething; } get { return _touchedSomething; }
@ -52,14 +49,27 @@ namespace RoboidControl {
this.component.core = this; this.component.core = this;
} }
#endif #endif
/// <summary>
/// Function used to generate binary data for this touch sensor
/// </summary>
/// <returns>A byte array with the binary data</returns>
/// <remark>The byte array will be empty when the touch status has not changed</remark>
public override byte[] GenerateBinary() { public override byte[] GenerateBinary() {
if (!touchUpdated) if (!touchUpdated)
return new byte[0]; return Array.Empty<byte>();
byte[] buffer = new byte[1]; byte[] bytes = new byte[1];
buffer[0] = (byte)(touchedSomething ? 1 : 0); bytes[0] = (byte)(touchedSomething ? 1 : 0);
touchUpdated = false; touchUpdated = false;
return buffer; return bytes;
}
/// <summary>
/// Function used to process binary data received for this touch sensor
/// </summary>
/// <param name="bytes">The binary data to process</param>
public override void ProcessBinary(byte[] bytes) {
this.touchedSomething |= (bytes[0] == 1);
} }
} }
} }