// Copyright (C)2026, Philip Munts dba Munts Technologies. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // // * Redistributions of source code must retain the above copyright notice, // this list of conditions and the following disclaimer. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE // POSSIBILITY OF SUCH DAMAGE. namespace IO.Objects.SkidSteer { /// /// Skid Steering 2WD vehicle class. /// public class Vehicle2WD { private readonly IO.Interfaces.Motor.Output LeftMotor; private readonly IO.Interfaces.Motor.Output RightMotor; private double Sensitivity = 0.2; private double GoVelocity = IO.Interfaces.Motor.Velocities.Stop; /// /// Skid Steering 2WD vehicle object constructor. /// /// Left motor driver output object instance. /// instance. /// Right motor driver output object instance. /// instance. /// Steering sensitivity scale factor. /// Allowed values range from 0.0 (exclusive) to 1.0 (inclusive). public Vehicle2WD(IO.Interfaces.Motor.Output left, IO.Interfaces.Motor.Output right, double sensitivity = 0.2) { if ((sensitivity <= 0.0) || (sensitivity > 1.0)) throw new System.Exception("Vehicle2WD() sensitivity is out of range."); LeftMotor = left; RightMotor = right; Sensitivity = sensitivity; GoVelocity = IO.Interfaces.Motor.Velocities.Stop; } /// /// Initiate forward or reverse motion. /// /// New motor velocity. Value values range /// from -1.0 for full speed astern to +1.0 for full speed ahead. /// Duration in milliseconds public void Go(double newvelocity, uint milliseconds = 0) { if (System.Math.Abs(newvelocity) > IO.Interfaces.Motor.Velocities.Maximum) throw new System.Exception("Go() velocity is out of range"); LeftMotor.velocity = newvelocity; RightMotor.velocity = newvelocity; GoVelocity = newvelocity; System.Threading.Thread.Sleep((int)milliseconds); } /// /// Stop motion. /// public void Stop() { Go(IO.Interfaces.Motor.Velocities.Stop); } /// /// Initiate a turn. /// /// Normalized conceptual steering wheel position. /// Allowed values from -1.0 (steering wheel fully counterclockwise) to /// +1.0 (steering wheel fully clockwise). /// Duration in milliseconds. public void Turn(double steering, uint milliseconds) { if ((steering < -1.0) || (steering > +1.0)) throw new System.Exception("Turn() steering is out of range"); if (steering == 0.0) // No turn, so just keep moving return; else if (GoVelocity > IO.Interfaces.Motor.Velocities.Stop) { // Moving forward LeftMotor.velocity = GoVelocity*(1.0 - Sensitivity) + steering*Sensitivity; RightMotor.velocity = GoVelocity*(1.0 - Sensitivity) - steering*Sensitivity; } else if (GoVelocity < IO.Interfaces.Motor.Velocities.Stop) { // Moving reverse LeftMotor.velocity = GoVelocity*(1.0 - Sensitivity) - steering*Sensitivity; RightMotor.velocity = GoVelocity*(1.0 - Sensitivity) + steering*Sensitivity; } else { // Stopped, so just spin in place LeftMotor.velocity = steering; RightMotor.velocity = -steering; } System.Threading.Thread.Sleep((int)milliseconds); // Resume forward or reverse motion Go(GoVelocity); } } }