Compare commits

...

2 Commits

12 changed files with 708 additions and 77 deletions

View File

@ -1,39 +1,46 @@

using LinearAlgebra;
namespace RoboidControl {
public class BB2B : Thing {
readonly DifferentialDrive drive;
readonly TouchSensor touchLeft;
readonly TouchSensor touchRight;
// The robot is based on a differential drive
public class BB2B : DifferentialDrive {
readonly DifferentialDrive drive;
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
drive = new();
// Is has a touch sensor at the front left of the roboid
touchLeft = new(this) {
position = Spherical.Degrees(0.12f, -30, 0),
orientation = new SwingTwist(-30, 0, 0)
};
touchRight = new(this) {
position = Spherical.Degrees(0.12f, 30, 0),
orientation = new SwingTwist(30, 0, 0)
};
}
// Is has a touch sensor at the front left of the roboid
touchLeft = new(drive);
// and other one on the right
touchRight = new(drive);
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
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);
}
}
}

View File

@ -3,7 +3,7 @@ using RoboidControl;
class Program {
static void Main() {
BB2B bb2b = new();
BB2B bb2b = new(ParticipantUDP.Isolated());
while (true) {
bb2b.Update();

View File

@ -0,0 +1,73 @@
#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 prefab = (GameObject)Resources.Load("DifferentialDrive");
if (prefab != null) {
// Use resource prefab when available
GameObject gameObj = Instantiate(prefab);
DifferentialDrive component = gameObj.GetComponent<DifferentialDrive>();
if (component != null)
component.core = core;
return component;
}
else {
// Fallback implementation
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 coreDrive = 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 = 100f, // Very high spring value to make it rigid
damper = 10f, // Low damping (could be adjusted for slight 'bounciness')
targetPosition = 0.5f // Neutral position (middle of the suspension travel)
};
}
leftWheel.radius = coreDrive.wheelRadius;
leftWheel.center = new Vector3(-coreDrive.wheelSeparation / 2, 0, 0);
if (rightWheel == null) {
GameObject rightWheelObj = new GameObject("Right wheel");
rightWheelObj.transform.SetParent(this.transform);
rightWheel = rightWheelObj.AddComponent<WheelCollider>();
rightWheel.mass = 0.1f;
rightWheel.suspensionDistance = 0.01f;
rightWheel.suspensionSpring = new JointSpring {
spring = 100f, // Very high spring value to make it rigid
damper = 10f, // Low damping (could be adjusted for slight 'bounciness')
targetPosition = 0.5f // Neutral position (middle of the suspension travel)
};
}
rightWheel.radius = coreDrive.wheelRadius;
rightWheel.center = new Vector3(coreDrive.wheelSeparation / 2, 0, 0);
}
}
}
#endif

View File

@ -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) {
case RoboidControl.TouchSensor coreTouchSensor:
TouchSensor touchSensor = TouchSensor.Create(coreTouchSensor);
coreTouchSensor.component = touchSensor;
break;
case RoboidControl.DifferentialDrive coreDrive:
DifferentialDrive differentialDrive = DifferentialDrive.Create(coreDrive);
coreDrive.component = differentialDrive;
break;
case RoboidControl.Thing coreThing:
Thing thing = Thing.Create(coreThing);
coreThing.component = thing;
if (coreThing.component != null) {
Thing thing = Thing.Create(coreThing);
coreThing.component = thing;
}
break;
}
}

View File

@ -0,0 +1,315 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!1 &135949056663158942
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 693610334404048217}
- component: {fileID: 874278397287993211}
- component: {fileID: 8149674613691108646}
m_Layer: 0
m_Name: Body
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &693610334404048217
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 135949056663158942}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 0.15, y: 0.05, z: 0.2}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 6798369561388671537}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!33 &874278397287993211
MeshFilter:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 135949056663158942}
m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0}
--- !u!23 &8149674613691108646
MeshRenderer:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 135949056663158942}
m_Enabled: 1
m_CastShadows: 1
m_ReceiveShadows: 1
m_DynamicOccludee: 1
m_StaticShadowCaster: 0
m_MotionVectors: 1
m_LightProbeUsage: 1
m_ReflectionProbeUsage: 1
m_RayTracingMode: 2
m_RayTraceProcedural: 0
m_RenderingLayerMask: 1
m_RendererPriority: 0
m_Materials:
- {fileID: 10303, guid: 0000000000000000f000000000000000, type: 0}
m_StaticBatchInfo:
firstSubMesh: 0
subMeshCount: 0
m_StaticBatchRoot: {fileID: 0}
m_ProbeAnchor: {fileID: 0}
m_LightProbeVolumeOverride: {fileID: 0}
m_ScaleInLightmap: 1
m_ReceiveGI: 1
m_PreserveUVs: 0
m_IgnoreNormalsForChartDetection: 0
m_ImportantGI: 0
m_StitchLightmapSeams: 1
m_SelectedEditorRenderState: 3
m_MinimumChartSize: 4
m_AutoUVMaxDistance: 0.5
m_AutoUVMaxAngle: 89
m_LightmapParameters: {fileID: 0}
m_SortingLayerID: 0
m_SortingLayer: 0
m_SortingOrder: 0
m_AdditionalVertexStreams: {fileID: 0}
--- !u!1 &3377575892836316963
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 7997617267105515189}
- component: {fileID: 3291281099104606017}
m_Layer: 0
m_Name: Left wheel
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &7997617267105515189
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 3377575892836316963}
serializedVersion: 2
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
m_LocalPosition: {x: 0, y: 0.003924, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 6798369561388671537}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!146 &3291281099104606017
WheelCollider:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 3377575892836316963}
serializedVersion: 2
m_Center: {x: -0.1, y: 0, z: 0}
m_Radius: 0.1
m_SuspensionSpring:
spring: 100
damper: 10
targetPosition: 0.5
m_SuspensionDistance: 0.01
m_ForceAppPointDistance: 0
m_Mass: 0.1
m_WheelDampingRate: 0.25
m_ForwardFriction:
m_ExtremumSlip: 0.4
m_ExtremumValue: 1
m_AsymptoteSlip: 0.8
m_AsymptoteValue: 0.5
m_Stiffness: 1
m_SidewaysFriction:
m_ExtremumSlip: 0.2
m_ExtremumValue: 1
m_AsymptoteSlip: 0.5
m_AsymptoteValue: 0.75
m_Stiffness: 1
m_IncludeLayers:
serializedVersion: 2
m_Bits: 0
m_ExcludeLayers:
serializedVersion: 2
m_Bits: 0
m_LayerOverridePriority: 0
m_Enabled: 1
m_ProvidesContacts: 0
--- !u!1 &4326386140118987503
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 6798369561388671537}
- component: {fileID: 2975045340952151157}
- component: {fileID: 4118868690347991998}
m_Layer: 0
m_Name: DifferentialDrive
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &6798369561388671537
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 4326386140118987503}
serializedVersion: 2
m_LocalRotation: {x: 1.276433e-21, y: -1.082074e-19, z: -2.3980766e-36, w: 1}
m_LocalPosition: {x: 2.1932227e-37, y: -0.06941543, z: -1.3084181e-19}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children:
- {fileID: 7997617267105515189}
- {fileID: 2660791421672615984}
- {fileID: 693610334404048217}
m_Father: {fileID: 0}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!114 &2975045340952151157
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 4326386140118987503}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 5c80bc2fd1d8aa14facb1ad4b6ccf7b3, type: 3}
m_Name:
m_EditorClassIdentifier:
<core>k__BackingField:
terminate: 0
id: 1
type: 13
nameChanged: 1
hierarchyChanged: 1
positionUpdated: 0
orientationUpdated: 0
linearVelocityUpdated: 0
angularVelocityUpdated: 0
participant: {fileID: 0}
leftWheel: {fileID: 3291281099104606017}
rightWheel: {fileID: 5992237647142430322}
--- !u!54 &4118868690347991998
Rigidbody:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 4326386140118987503}
serializedVersion: 4
m_Mass: 0.5
m_Drag: 0
m_AngularDrag: 0.05
m_CenterOfMass: {x: 0, y: 0, z: 0}
m_InertiaTensor: {x: 1, y: 1, z: 1}
m_InertiaRotation: {x: 0, y: 0, z: 0, w: 1}
m_IncludeLayers:
serializedVersion: 2
m_Bits: 0
m_ExcludeLayers:
serializedVersion: 2
m_Bits: 0
m_ImplicitCom: 1
m_ImplicitTensor: 1
m_UseGravity: 1
m_IsKinematic: 0
m_Interpolate: 0
m_Constraints: 0
m_CollisionDetection: 0
--- !u!1 &5122915782100933114
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 2660791421672615984}
- component: {fileID: 5992237647142430322}
m_Layer: 0
m_Name: Right wheel
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &2660791421672615984
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 5122915782100933114}
serializedVersion: 2
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
m_LocalPosition: {x: 0, y: 0.003924, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 6798369561388671537}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!146 &5992237647142430322
WheelCollider:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 5122915782100933114}
serializedVersion: 2
m_Center: {x: 0.1, y: 0, z: 0}
m_Radius: 0.1
m_SuspensionSpring:
spring: 100
damper: 10
targetPosition: 0.5
m_SuspensionDistance: 0.01
m_ForceAppPointDistance: 0
m_Mass: 0.1
m_WheelDampingRate: 0.25
m_ForwardFriction:
m_ExtremumSlip: 0.4
m_ExtremumValue: 1
m_AsymptoteSlip: 0.8
m_AsymptoteValue: 0.5
m_Stiffness: 1
m_SidewaysFriction:
m_ExtremumSlip: 0.2
m_ExtremumValue: 1
m_AsymptoteSlip: 0.5
m_AsymptoteValue: 0.75
m_Stiffness: 1
m_IncludeLayers:
serializedVersion: 2
m_Bits: 0
m_ExcludeLayers:
serializedVersion: 2
m_Bits: 0
m_LayerOverridePriority: 0
m_Enabled: 1
m_ProvidesContacts: 0

View File

@ -0,0 +1,191 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!1 &1535520457298351474
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 1122722937167266542}
- component: {fileID: 8409364771467476437}
- component: {fileID: 6632295589629461102}
m_Layer: 0
m_Name: Sphere
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &1122722937167266542
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1535520457298351474}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 0.01, y: 0.01, z: 0.01}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 839661735326876684}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!33 &8409364771467476437
MeshFilter:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1535520457298351474}
m_Mesh: {fileID: 10207, guid: 0000000000000000e000000000000000, type: 0}
--- !u!23 &6632295589629461102
MeshRenderer:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1535520457298351474}
m_Enabled: 1
m_CastShadows: 1
m_ReceiveShadows: 1
m_DynamicOccludee: 1
m_StaticShadowCaster: 0
m_MotionVectors: 1
m_LightProbeUsage: 1
m_ReflectionProbeUsage: 1
m_RayTracingMode: 2
m_RayTraceProcedural: 0
m_RenderingLayerMask: 1
m_RendererPriority: 0
m_Materials:
- {fileID: 10303, guid: 0000000000000000f000000000000000, type: 0}
m_StaticBatchInfo:
firstSubMesh: 0
subMeshCount: 0
m_StaticBatchRoot: {fileID: 0}
m_ProbeAnchor: {fileID: 0}
m_LightProbeVolumeOverride: {fileID: 0}
m_ScaleInLightmap: 1
m_ReceiveGI: 1
m_PreserveUVs: 0
m_IgnoreNormalsForChartDetection: 0
m_ImportantGI: 0
m_StitchLightmapSeams: 1
m_SelectedEditorRenderState: 3
m_MinimumChartSize: 4
m_AutoUVMaxDistance: 0.5
m_AutoUVMaxAngle: 89
m_LightmapParameters: {fileID: 0}
m_SortingLayerID: 0
m_SortingLayer: 0
m_SortingOrder: 0
m_AdditionalVertexStreams: {fileID: 0}
--- !u!1 &6521541507066528382
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 839661735326876684}
- component: {fileID: 1922171662874522792}
- component: {fileID: 5295705618145761524}
- component: {fileID: 5884202444353424411}
m_Layer: 0
m_Name: TouchSensor
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &839661735326876684
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 6521541507066528382}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: -0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children:
- {fileID: 1122722937167266542}
m_Father: {fileID: 0}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!114 &1922171662874522792
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 6521541507066528382}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: ab969221c3007d441b18dd7387cf22d4, type: 3}
m_Name:
m_EditorClassIdentifier:
<core>k__BackingField:
terminate: 0
id: 4
type: 5
nameChanged: 1
hierarchyChanged: 1
positionUpdated: 0
orientationUpdated: 0
linearVelocityUpdated: 0
angularVelocityUpdated: 0
participant: {fileID: 0}
--- !u!54 &5295705618145761524
Rigidbody:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 6521541507066528382}
serializedVersion: 4
m_Mass: 1
m_Drag: 0
m_AngularDrag: 0.05
m_CenterOfMass: {x: 0, y: 0, z: 0}
m_InertiaTensor: {x: 1, y: 1, z: 1}
m_InertiaRotation: {x: 0, y: 0, z: 0, w: 1}
m_IncludeLayers:
serializedVersion: 2
m_Bits: 0
m_ExcludeLayers:
serializedVersion: 2
m_Bits: 0
m_ImplicitCom: 1
m_ImplicitTensor: 1
m_UseGravity: 1
m_IsKinematic: 1
m_Interpolate: 0
m_Constraints: 0
m_CollisionDetection: 0
--- !u!135 &5884202444353424411
SphereCollider:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 6521541507066528382}
m_Material: {fileID: 0}
m_IncludeLayers:
serializedVersion: 2
m_Bits: 0
m_ExcludeLayers:
serializedVersion: 2
m_Bits: 0
m_LayerOverridePriority: 0
m_IsTrigger: 1
m_ProvidesContacts: 0
m_Enabled: 1
serializedVersion: 3
m_Radius: 0.01
m_Center: {x: 0, y: 0, z: 0}

View File

@ -42,7 +42,8 @@ namespace RoboidControl.Unity {
participant.coreParticipant = e.participant;
break;
case ThingMsg.id:
e.thing.CreateComponent();
HandleThingEvent(e);
//e.thing.CreateComponent();
break;
}
}

View File

@ -48,6 +48,7 @@ namespace RoboidControl.Unity {
protected void Init(RoboidControl.Thing core) {
this.core = core;
this.participant = FindAnyObjectByType<SiteServer>();
core.owner = this.participant.coreParticipant;
if (core.parent != null && core.parent.component != null)
this.transform.SetParent(core.parent.component.transform, false);
@ -105,6 +106,9 @@ namespace RoboidControl.Unity {
if (core.angularVelocity.distance == 0)
this.transform.localRotation = core.orientation.ToQuaternion();
break;
case BinaryMsg.Id:
this.HandleBinary();
break;
}
}
@ -143,6 +147,7 @@ namespace RoboidControl.Unity {
}
}
protected virtual void HandleBinary() {}
}

View File

@ -36,34 +36,28 @@ namespace RoboidControl.Unity {
/// <param name="core">The core touch sensor</param>
/// <returns>The Unity representation of the touch sensor</returns>
public static TouchSensor Create(RoboidControl.TouchSensor core) {
GameObject gameObj = core.name != null ?
new(core.name) :
new("Touch Sensor");
TouchSensor component = gameObj.AddComponent<TouchSensor>();
component.Init(core);
Rigidbody rb = gameObj.AddComponent<Rigidbody>();
rb.isKinematic = true;
SphereCollider collider = gameObj.AddComponent<SphereCollider>();
collider.radius = 0.01f;
collider.isTrigger = true;
if (gameObj.transform.parent != null && gameObj.transform.localPosition.magnitude > 0) {
collider.radius = Vector3.Distance(gameObj.transform.position, gameObj.transform.parent.position) / 2;
gameObj.transform.position = (gameObj.transform.position + gameObj.transform.parent.position) / 2;
GameObject prefab = (GameObject)Resources.Load("TouchSensor");
if (prefab != null) {
// Use resource prefab when available
GameObject gameObj = Instantiate(prefab);
TouchSensor component = gameObj.GetComponent<TouchSensor>();
if (component != null)
component.core = core;
return component;
}
else {
// Fallback implementation
GameObject gameObj = new(core.name);
TouchSensor component = gameObj.AddComponent<TouchSensor>();
component.Init(core);
return component;
}
Rigidbody rb = gameObj.AddComponent<Rigidbody>();
rb.isKinematic = true;
protected override void Update() {
base.Update();
if (touchCollider.radius == 0.01f &&
this.transform.parent != null && this.transform.localPosition.magnitude > 0
) {
touchCollider.radius = Vector3.Distance(this.transform.position, this.transform.parent.position) / 2;
this.transform.position = (this.transform.position + this.transform.parent.position) / 2;
SphereCollider collider = gameObj.AddComponent<SphereCollider>();
collider.radius = 0.01f;
collider.isTrigger = true;
return component;
}
}

View File

@ -117,16 +117,7 @@ namespace RoboidControl {
Console.WriteLine($"{this.name}: Process thing [{msg.networkId}/{msg.thingId}] {msg.thingType} {msg.parentId} ");
Thing thing = sender.Get(msg.thingId);
if (thing == null) {
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);
thing ??= ProcessNewThing(sender, msg);
if (msg.parentId != 0) {
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

View File

@ -17,7 +17,19 @@ namespace RoboidControl {
/// <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(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>
/// Create a new child differential drive
/// </summary>
@ -92,17 +104,43 @@ namespace RoboidControl {
}
/// @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
protected float wheelSeparation = 1.0f;
public float wheelSeparation = 1.0f;
/// @brief Convert revolutions per second to meters per second
protected float rpsToMs = 1.0f;
/// @brief The left wheel
protected Thing leftWheel = null;
public Thing leftWheel = null;
/// @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

View File

@ -24,7 +24,9 @@ namespace RoboidControl {
/// <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 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>
/// Value which is true when the sensor is touching something, false otherwise