#if UNITY_5_3_OR_NEWER using UnityEngine; namespace RoboidControl.Unity { /// /// The Unity representation of a Roboid Control differential drive /// public class DifferentialDrive : Thing { /// /// The core differential drive /// public RoboidControl.DifferentialDrive coreDrive => core as RoboidControl.DifferentialDrive; /// /// Create the Unity representation /// /// The core touch sensor /// The Unity representation of the touch sensor /// 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); differentialDrive = gameObj.GetComponent(); differentialDrive.Init(coreDrive); } else { // Default implementation GameObject gameObj = new(coreDrive.name); differentialDrive = gameObj.AddComponent(); differentialDrive.Init(coreDrive); Rigidbody rb = gameObj.AddComponent(); rb.isKinematic = false; rb.mass = 0.1f; } 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() { // Ignore it when the wheel radius is not set if (coreDrive.wheelRadius <= 0) return; // Destroy any (generic) thing with the same id if (leftWheel == null) { Thing[] things = FindObjectsOfType(); foreach (Thing thing in things) { if (thing.core.id == coreDrive.leftWheel.id) Destroy(thing.gameObject); } } if (leftWheel == null && coreDrive.leftWheel != null) leftWheel = Wheel.Create(this.transform, coreDrive.leftWheel.id); if (leftWheel != null) { leftWheel.core ??= coreDrive.leftWheel; SphereCollider leftWheelCollider = leftWheel.GetComponent(); leftWheelCollider.radius = coreDrive.wheelRadius; } // Destroy any (generic) thing with the same id if (rightWheel == null) { Thing[] things = FindObjectsOfType(); foreach (Thing thing in things) { if (thing.core.id == coreDrive.rightWheel.id) Destroy(thing.gameObject); } } if (rightWheel == null && coreDrive.rightWheel != null) rightWheel = Wheel.Create(this.transform, coreDrive.rightWheel.id); if (rightWheel != null) { rightWheel.core ??= coreDrive.rightWheel; SphereCollider rightWheelCollider = rightWheel.GetComponent(); rightWheelCollider.radius = coreDrive.wheelRadius; } if (casterWheel == null) { GameObject gameObj = new("Caster wheel"); gameObj.transform.parent = this.transform; casterWheel = gameObj.AddComponent(); casterWheel.material = Wheel.slidingWheel; } casterWheel.radius = coreDrive.wheelRadius; // Put it in the middle of the back // This code assumes that the left wheel position has Direction.left and the right wheel Direction.right... float wheelSeparation = coreDrive.leftWheel.position.distance + coreDrive.rightWheel.position.distance; casterWheel.center = new Vector3(0, 0, -wheelSeparation); } /// /// Update the Unity representation state /// protected override void FixedUpdate() { base.FixedUpdate(); if (rb != null && leftWheel != null && rightWheel != null) { float leftWheelVelocity = leftWheel.rotationSpeed * (2 * Mathf.PI) * coreDrive.wheelRadius; float rightWheelVelocity = rightWheel.rotationSpeed * (2 * Mathf.PI) * coreDrive.wheelRadius; // This code assumes that the left wheel position has Direction.left and the right wheel Direction.right... float wheelSeparation = coreDrive.leftWheel.position.distance + coreDrive.rightWheel.position.distance; float forwardSpeed = (leftWheelVelocity + rightWheelVelocity) / 2f; float turningSpeed = (leftWheelVelocity - rightWheelVelocity) / wheelSeparation; // Use smoothing to emulate motor inertia rb.velocity = 0.9f * rb.velocity + 0.1f * forwardSpeed * transform.forward; rb.angularVelocity = 0.9f * rb.angularVelocity + 0.1f * turningSpeed * Vector3.up; } } } } #endif