Driver:
/* * Electric Speed Controller NETMF Driver * Coded by Chris Seto August 2010 * <chris@chrisseto.com> * * Use this code for whatever you want. Modify it, redistribute it, I don't care. * I do ask that you please keep this header intact, however. * If you modfy the driver, please include your contribution below: * * Chris Seto: Inital release (1.0) * Chris Seto: Second release (1.1) * Chris Seto: Third release (1.2) * Chris Seto: Netduino port (1.2 -> Netduino) * * */ using System.Threading; using Microsoft.SPOT.Hardware; using SecretLabs.NETMF.Hardware; namespace ElectricSpeedController_API { // This is the parent clas that will hold speed controller settings public abstract class SpeedControllers { // Timing range public abstract int[] range { get; } // How long to wait after setup to exit constructor public abstract int armPeriod { get; } // Ramp iteration timings public abstract int[] rampIterationPause { get; } } // This is the actual driver public class SpeedController { /// <summary> /// PWM handle /// </summary> private PWM esc; /// <summary> /// Timing ranges /// </summary> public int[] range = new int[3]; /// <summary> /// Invert power setting /// </summary> public bool inverted = false; /// <summary> /// ESC model settings /// </summary> readonly SpeedControllers escModel; /// <summary> /// ESC drive modes /// </summary> public enum DriveModes { Reverse, Forward, FullScale, } /// <summary> /// Active drive mode /// </summary> public DriveModes DriveMode = DriveModes.Forward; /// <summary> /// Last known throttle setting /// </summary> private int currentThrottle = 0; /// <summary> /// 0-100% throttle setting /// </summary> public int Throttle { set { // Range checks if (value > 100) value = 100; if (value < 0) value = 0; // Are we inverted? if (inverted) value = 100 - value; // This will be filled below... int[] range = new int[2]; int rampIterationPause = 0; // Select the drive mode switch (DriveMode) { // Set the pulse ranges to the after neutral segment case DriveModes.Forward: range[0] = escModel.range[1]; range[1] = escModel.range[2]; rampIterationPause = escModel.rampIterationPause[1]; break; // Set the pulse ranges to the before neutral segment case DriveModes.Reverse: range[0] = escModel.range[1]; range[1] = escModel.range[0]; rampIterationPause = escModel.rampIterationPause[0]; break; // Use both segments case DriveModes.FullScale: range[0] = escModel.range[0]; range[1] = escModel.range[2]; rampIterationPause = escModel.rampIterationPause[2]; break; } // Step the wave up or down // I absolutely hate doing it this way, but really, there's no other better way. if (value < currentThrottle) { for (int set = currentThrottle; set >= value; set--) { // Set the pulse esc.SetPulse(20000, (uint)map(set, 0, 100, range[0], range[1])); Thread.Sleep(rampIterationPause); } } else { for (int set = currentThrottle; set <= value; set++) { esc.SetPulse(20000, (uint)map(set, 0, 100, range[0], range[1])); Thread.Sleep(rampIterationPause); } } // Set the current power setting currentThrottle = value; } get { return currentThrottle; } } /// <summary> /// Create the PWM pin, set it low and configure /// timing settings /// </summary> /// <param name="pin"></param> public SpeedController(Cpu.Pin pin, SpeedControllers escModel) { // Set up the PWM port esc = new PWM((Cpu.Pin)pin); // Bind the ESC settings this.escModel = escModel; // Pull the throttle all the way out Throttle = 0; // Arm the ESC Thread.Sleep(escModel.armPeriod); } public void Dispose() { this.disengage(); esc.Dispose(); } /// <summary> /// Disengage ESC. /// Behavior is dependant on ESC make and model. /// </summary> public void disengage() { esc.SetDutyCycle(0); } /// <summary> /// Used internally to map a percentage to a timing range /// </summary> /// <param name="x"></param> /// <param name="in_min"></param> /// <param name="in_max"></param> /// <param name="out_min"></param> /// <param name="out_max"></param> /// <returns></returns> private long map(int x, int in_min, int in_max, int out_min, int out_max) { return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min; } } }
Config class:
/* * Traxxas XL5 Speed Controller settings * Coded by Chris Seto August 2010 * <chris@chrisseto.com> * * Use this code for whatever you want. Modify it, redistribute it, I don't care. * I do ask that you please keep this header intact, however. * If you modfy the driver, please include your contribution below: * * Chris Seto: Inital release (1.0) * Chris Seto: Bugfix: ramp iteration timings (1.1) * * * */ namespace ElectricSpeedController_API { public class TRAXXAS_XL5 : SpeedControllers { /// <summary> /// Wave timings /// </summary> public override int[] range { get { return new int[3] { 1000, 1500, 2000, }; } } /// <summary> /// how long to let the ESC sit after init /// </summary> public override int armPeriod { get { return 500; } } /// <summary> /// How long to wait between ramp iterations /// </summary> public override int[] rampIterationPause { get { return new int[3] { 50, 1, 1, }; } } } }
Example code:
using System.Threading; using ElectricSpeedController_API; using SecretLabs.NETMF.Hardware.Netduino; namespace NetduinoESCDemo { public class Program { public static void Main() { SpeedController xl5 = new SpeedController(Pins.GPIO_PIN_D9, new TRAXXAS_XL5()); for (int i = 0; i <= 100; i++) { xl5.Throttle = i; Thread.Sleep(50); } xl5.Throttle = 0; } } }