diff --git a/Examples/BB2B/BB2B.cs b/Examples/BB2B/BB2B.cs index 4f1c3cf..2a398ca 100644 --- a/Examples/BB2B/BB2B.cs +++ b/Examples/BB2B/BB2B.cs @@ -9,7 +9,7 @@ namespace RoboidControl { readonly TouchSensor touchRight; const float speed = 0.5f; - public BB2B(Participant owner) : base(owner) { + public BB2B(Thing parent = default) : base(parent) { this.name = "BB2B"; this.SetMotors(new Motor(this), new Motor(this)); this.SetDriveDimensions(0.064f, 0.128f); diff --git a/Examples/BB2B/BB2B_Encoder.cs b/Examples/BB2B/BB2B_Encoder.cs index f2b91df..21787c6 100644 --- a/Examples/BB2B/BB2B_Encoder.cs +++ b/Examples/BB2B/BB2B_Encoder.cs @@ -9,15 +9,15 @@ namespace RoboidControl { readonly TouchSensor touchRight; const float speed = 180.0f; // wheel rotation speed in degrees - public BB2B_Encoder(Participant owner) : base(owner) { + public BB2B_Encoder(Thing parent) : base(parent) { this.name = "BB2B"; this.SetDriveDimensions(0.064f, 0.128f); // Update the basic motors to motors with encoder - EncoderMotor leftMotor = new(this, new RelativeEncoder()) { + ControlledMotor leftMotor = new(this, new RelativeEncoder()) { position = new Spherical(0.064f, Direction.left) }; - EncoderMotor rightMotor = new(this, new RelativeEncoder()) { + ControlledMotor rightMotor = new(this, new RelativeEncoder()) { position = new Spherical(0.064f, Direction.right) }; this.SetMotors(leftMotor, rightMotor); diff --git a/Examples/BB2B/Program.cs b/Examples/BB2B/Program.cs index 10b0c67..7550097 100644 --- a/Examples/BB2B/Program.cs +++ b/Examples/BB2B/Program.cs @@ -3,7 +3,7 @@ using RoboidControl; class Program { static void Main() { - BB2B bb2b = new(ParticipantUDP.Isolated()); + BB2B bb2b = new(); while (true) { bb2b.Update(); diff --git a/README.md b/README.md index 7af367d..b576be8 100644 --- a/README.md +++ b/README.md @@ -11,3 +11,21 @@ The documentation for Roboid Control for C# is found at https://docs.roboidcontr - RoboidControl::Thing - RoboidControl::Participant + +# Get Started + +## Unity + +The Unity environment can use the same RoboidControl code as every other C# code, but needs a *starter* wrapper around it to make the things visibile. For example, to start the BB2B example in Unity one needs to write a BB2B_Starter.cs component as follows: +``` +using RoboidControl.Unity; + +public class BB2B_Starter : SiteServer { + void Start() { + new RoboidControl.BB2B(); + } +} +``` +This component then should be attached to a GameObject in the scene. + +It is possible to create a Site Server in Unity by just adding the `SiteServer` Component to a GameObject in the scene. When this is run, other roboids will be able to connect to this site then. \ No newline at end of file diff --git a/src/Participant.cs b/src/Participant.cs index 4318467..a936b87 100644 --- a/src/Participant.cs +++ b/src/Participant.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Collections.Concurrent; using System.Net; using System.Net.Sockets; +using System.Reflection.Metadata; namespace RoboidControl { @@ -14,6 +15,13 @@ namespace RoboidControl { /// It also maintains the communcation information to contact the participant. /// It is used as a basis for the local participant, but also as a reference to remote participants. public class Participant { + + private Participant() { + this.root = Thing.CreateRoot(this); + this.root.name = "Root"; + this.Add(this.root); + } + /// /// Create a new participant with the given communcation info /// @@ -26,6 +34,10 @@ namespace RoboidControl { this.udpClient = localParticipant.udpClient; } + public static readonly Participant localParticipant = new(); + + public Thing root = null; + /// /// The Ip Address of a participant. When the participant is local, this contains 0.0.0.0 /// diff --git a/src/Participants/SiteServer.cs b/src/Participants/SiteServer.cs index 8c38572..519f425 100644 --- a/src/Participants/SiteServer.cs +++ b/src/Participants/SiteServer.cs @@ -132,9 +132,9 @@ 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), + //Thing.Type.TouchSensor => new TouchSensor(sender, msg.thingId), + //Thing.Type.DifferentialDrive => new DifferentialDrive(sender, msg.thingId), + _ => Thing.CreateRemote(sender, msg.thingType, msg.thingId) }; } diff --git a/src/Thing.cs b/src/Thing.cs index af90a11..b9f9b29 100644 --- a/src/Thing.cs +++ b/src/Thing.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; using System.Collections.Concurrent; using LinearAlgebra; +using Microsoft.VisualStudio.TestPlatform.ObjectModel.DataCollection; namespace RoboidControl { @@ -26,10 +27,11 @@ namespace RoboidControl { public const byte ControlledMotor = 0x06; public const byte UncontrolledMotor = 0x07; public const byte Servo = 0x08; - public const byte IncrementalEncoder = 0x19; + public const byte RelativeEncoder = 0x19; // Other + public const byte Root = 0x10; public const byte Roboid = 0x09; - public const byte HUmanoid = 0x0A; + public const byte Humanoid = 0x0A; public const byte ExternalSensor = 0x0B; public const byte Animator = 0x0C; public const byte DifferentialDrive = 0x0D; @@ -37,6 +39,29 @@ namespace RoboidControl { #region Init + private Thing(Participant owner) { + this.type = Type.Root; + + this.positionUpdated = true; + this.orientationUpdated = true; + this.hierarchyChanged = true; + + this.owner = owner; + this.parent = null; + } + + public static Thing CreateRoot(Participant owner) { + return new Thing(owner); + } + + static Thing localRoot { + get { + Participant participant = Participant.localParticipant; + return participant.root; + } + } + + /* /// /// Create a new thing without communication abilities /// @@ -66,6 +91,7 @@ namespace RoboidControl { this.owner.updateQueue.Enqueue(e); } } + */ /// /// Create a new child thing @@ -75,26 +101,33 @@ namespace RoboidControl { /// The ID of the thing, leave out or set to zero to generate an ID /// Invoke a OnNewThing event when the thing has been created /// The owner will be the same as the owner of the parent thing + /* public Thing(Thing parent, byte thingType = Type.Undetermined, byte thingId = 0, bool invokeEvent = true) : this(parent.owner, thingType, thingId, invokeEvent) { this.parent = parent; } + */ + public Thing(byte thingType = Type.Undetermined, Thing parent = default) { + this.type = thingType; - // /// - // /// Create a new thing for the given participant - // /// - // /// The participant owning the thing - // /// The network ID of the thing - // /// The ID of the thing - // /// The type of thing - // public Thing(Participant owner, byte networkId, byte thingId, byte thingType = 0) { - // this.owner = owner; - // this.id = thingId; - // this.type = thingType; - // this.networkId = networkId; - // // Console.Write($"New thing added to {owner}"); - // this.owner.Add(this); - // InvokeNewThing(this); - // } + this.positionUpdated = true; + this.orientationUpdated = true; + this.hierarchyChanged = true; + + if (parent == default) + this.parent = Participant.localParticipant.root; + else + this.parent = parent; + + this.owner = parent.owner; + this.owner.Add(this, true); + } + + public static Thing CreateRemote(Participant owner, byte thingType, byte thingId) { + Thing remoteThing = new(thingType, owner.root) { + id = thingId + }; + return remoteThing; + } /// /// Function which can be used to create components in external engines. diff --git a/src/Things/EncoderMotor.cs b/src/Things/ControlledMotor.cs similarity index 91% rename from src/Things/EncoderMotor.cs rename to src/Things/ControlledMotor.cs index 01d6ac6..fb5ad79 100644 --- a/src/Things/EncoderMotor.cs +++ b/src/Things/ControlledMotor.cs @@ -3,12 +3,12 @@ namespace RoboidControl { /// @brief A motor with speed control /// It uses a feedback loop from an encoder to regulate the speed /// The speed is measured in revolutions per second. - class EncoderMotor : Motor { - public EncoderMotor(Thing parent, RelativeEncoder encoder) : base(parent) { + public class ControlledMotor : Motor { + public ControlledMotor(Thing parent, RelativeEncoder encoder) : base(parent) { this.encoder = encoder; } // Upgrade an existing motor with an encoder - public EncoderMotor(Motor motor, RelativeEncoder encoder) : base(motor.parent) { + public ControlledMotor(Motor motor, RelativeEncoder encoder) : base(motor.parent) { this.motor = motor; this.encoder = encoder; } @@ -50,7 +50,7 @@ namespace RoboidControl { float pidP = 0.1F; float pidD = 0.0F; - float pidI = 0.0F; + //float pidI = 0.0F; public override void Update(ulong currentTimeMs, bool recurse = false) { float actualSpeed = this.encoder.angularSpeed; diff --git a/src/Things/DifferentialDrive.cs b/src/Things/DifferentialDrive.cs index 45203a8..271ea0d 100644 --- a/src/Things/DifferentialDrive.cs +++ b/src/Things/DifferentialDrive.cs @@ -6,11 +6,13 @@ namespace RoboidControl { /// /// @sa @link https://en.wikipedia.org/wiki/Differential_wheeled_robot @endlink public class DifferentialDrive : Thing { + /* /// /// Create a differential drive without communication abilities /// Invoke a OnNewThing event when the thing has been created - public DifferentialDrive(bool invokeEvent = true) : base(Type.DifferentialDrive, invokeEvent) { } + public DifferentialDrive() : base(Type.DifferentialDrive) { } + /// /// Create a differential drive for a participant /// @@ -28,15 +30,16 @@ namespace RoboidControl { // sendBinary = true; // owner.Send(new BinaryMsg(owner.networkId, this)); // this.updateQueue.Enqueue(new UpdateEvent(BinaryMsg.Id)); - } + */ + /// /// Create a new child differential drive /// /// The parent thing /// The ID of the thing, leave out or set to zero to generate an ID /// Invoke a OnNewThing event when the thing has been created - public DifferentialDrive(Thing parent, byte thingId = 0, bool invokeEvent = true) : base(parent, Type.DifferentialDrive, thingId, invokeEvent) { } + public DifferentialDrive(Thing parent) : base(Type.DifferentialDrive, parent) { } /// @brief Configures the dimensions of the drive /// @param wheelDiameter The diameter of the wheels in meters @@ -101,9 +104,9 @@ namespace RoboidControl { /// Positive moves the robot in the forward direction. public void SetWheelAngularVelocity(float angularSpeedLeft, float angularSpeedRight) { // This only works when the motor is a motor with encoder - if (this.leftWheel is EncoderMotor leftMotor) + if (this.leftWheel is ControlledMotor leftMotor) leftMotor.targetAngularSpeed = angularSpeedLeft; - if (this.rightWheel is EncoderMotor rightMotor) + if (this.rightWheel is ControlledMotor rightMotor) rightMotor.targetAngularSpeed = angularSpeedRight; } diff --git a/src/Things/DigitalSensor.cs b/src/Things/DigitalSensor.cs index 2993580..3d1a19c 100644 --- a/src/Things/DigitalSensor.cs +++ b/src/Things/DigitalSensor.cs @@ -6,6 +6,7 @@ namespace RoboidControl { /// A sensor which can detect touches /// public class DigitalSensor : Thing { + /* /// /// Create a digital sensor without communication abilities /// @@ -18,13 +19,14 @@ namespace RoboidControl { /// The ID of the thing, leave out or set to zero to generate an ID /// Invoke a OnNewThing event when the thing has been created public DigitalSensor(Participant owner, byte thingId = 0, bool invokeEvent = true) : base(owner, Type.Switch, thingId, invokeEvent) { } + */ /// /// Create a new child digital sensor /// /// The parent thing /// The ID of the thing, leave out or set to zero to generate an ID /// Invoke a OnNewThing event when the thing has been created - public DigitalSensor(Thing parent, byte thingId = 0, bool invokeEvent = true) : base(parent, Type.Switch, thingId, invokeEvent) { } + public DigitalSensor(Thing parent) : base(Type.Switch, parent) { } /// /// Value which is true when the sensor is touching something, false otherwise diff --git a/src/Things/DistanceSensor.cs b/src/Things/DistanceSensor.cs index ad5f785..def58f9 100644 --- a/src/Things/DistanceSensor.cs +++ b/src/Things/DistanceSensor.cs @@ -9,19 +9,23 @@ namespace RoboidControl { /// public float distance = 0; + /* /// /// Constructor for a new distance sensor /// /// The participant for which the sensor is needed public DistanceSensor(Participant participant) : base(participant, Type.Undetermined) { } + /// /// Create a distance sensor with the given ID /// /// The participant for with the sensor is needed /// The network ID of the sensor /// The ID of the thing - public DistanceSensor(Participant owner, byte thingId) : base(owner, Type.TemperatureSensor, thingId) { - } + public DistanceSensor(Participant owner, byte thingId) : base(owner, Type.TemperatureSensor, thingId) {} + */ + public DistanceSensor(Thing parent): base(Type.DistanceSensor, parent) {} + #if UNITY_5_3_OR_NEWER /// @copydoc Passer::RoboidControl::Thing::CreateComponent diff --git a/src/Things/Motor.cs b/src/Things/Motor.cs index 1b09654..e4ecad8 100644 --- a/src/Things/Motor.cs +++ b/src/Things/Motor.cs @@ -3,8 +3,8 @@ using LinearAlgebra; namespace RoboidControl { public class Motor : Thing { - public Motor(bool invokeEvent = true) : base(Type.UncontrolledMotor, invokeEvent) { } - public Motor(Thing parent, byte thingId = 0, bool invokeEvent = true) : base(parent, Type.UncontrolledMotor, thingId, invokeEvent) { } + //public Motor(bool invokeEvent = true) : base(Type.UncontrolledMotor, invokeEvent) { } + public Motor(Thing parent) : base(Type.UncontrolledMotor, parent) { } /// @brief Motor turning direction public enum Direction { diff --git a/src/Things/RelativeEncoder.cs b/src/Things/RelativeEncoder.cs index 5183f91..d3bc8b7 100644 --- a/src/Things/RelativeEncoder.cs +++ b/src/Things/RelativeEncoder.cs @@ -1,4 +1,6 @@ +using NUnit.Framework; + namespace RoboidControl { /// @brief An Incremental Encoder measures the rotations of an axle using a rotary @@ -9,7 +11,12 @@ namespace RoboidControl { /// full rotation /// @param distancePerRevolution The distance a wheel travels per full /// rotation + /* public RelativeEncoder(bool invokeEvent = true) : base(Type.IncrementalEncoder, invokeEvent) { } + */ + public RelativeEncoder(Thing parent = default) : base(Type.RelativeEncoder, parent) { + + } protected float _rotationSpeed = 0; /// @brief Get the rotation speed since the previous call diff --git a/src/Things/TemperatureSensor.cs b/src/Things/TemperatureSensor.cs index 6475d06..ecf548e 100644 --- a/src/Things/TemperatureSensor.cs +++ b/src/Things/TemperatureSensor.cs @@ -6,6 +6,7 @@ namespace RoboidControl { /// A temperature sensor /// public class TemperatureSensor : Thing { + /* /// /// Create a temperature sensor without communication abilities /// @@ -18,14 +19,14 @@ namespace RoboidControl { /// The ID of the thing /// Invoke a OnNewThing event when the thing has been created public TemperatureSensor(Participant owner, byte thingId = 0, bool invokeEvent = true) : base(owner, Type.TemperatureSensor, thingId, invokeEvent) { } - + */ /// /// Create a new child temperature sensor /// /// The parent thing /// The ID of the thing, leave out or set to zero to generate an ID /// Invoke a OnNewThing event when the thing has been created - public TemperatureSensor(Thing parent, byte thingId = 0, bool invokeEvent = true) : base(parent, Type.TemperatureSensor, thingId, invokeEvent) { } + public TemperatureSensor(Thing parent) : base(Type.TemperatureSensor, parent) { } /// /// The measured temperature diff --git a/src/Things/TouchSensor.cs b/src/Things/TouchSensor.cs index 2198e6e..e2db699 100644 --- a/src/Things/TouchSensor.cs +++ b/src/Things/TouchSensor.cs @@ -6,6 +6,7 @@ namespace RoboidControl { /// A sensor which can detect touches /// public class TouchSensor : Thing { + /* /// /// Create a touch sensor without communication abilities /// @@ -18,13 +19,14 @@ namespace RoboidControl { /// The ID of the thing, leave out or set to zero to generate an ID /// Invoke a OnNewThing event when the thing has been created public TouchSensor(Participant owner, byte thingId = 0, bool invokeEvent = true) : base(owner, Type.TouchSensor, thingId, invokeEvent) { } + */ /// /// Create a new child touch sensor /// /// The parent thing /// The ID of the thing, leave out or set to zero to generate an ID /// Invoke a OnNewThing event when the thing has been created - public TouchSensor(Thing parent, byte thingId = 0, bool invokeEvent = true) : base(parent, Type.TouchSensor, thingId, invokeEvent) { + public TouchSensor(Thing parent) : base(Type.TouchSensor, parent) { this.name = "TouchSensor"; } diff --git a/test/UnitTest1.cs b/test/UnitTest1.cs index 46a3864..9fc8f79 100644 --- a/test/UnitTest1.cs +++ b/test/UnitTest1.cs @@ -65,7 +65,7 @@ namespace RoboidControl.test { public void Test_ThingMsg() { SiteServer siteServer = new(7681); ParticipantUDP participant = new("127.0.0.1", 7681, 7682); - Thing thing = new(participant) { + Thing thing = new() { name = "First Thing", modelUrl = "https://passer.life/extras/ant.jpg" };