Netduino home hardware projects downloads community

Jump to content


The Netduino forums have been replaced by new forums at community.wildernesslabs.co. This site has been preserved for archival purposes only and the ability to make new accounts or posts has been turned off.
Photo

Netduino ESC driver


  • Please log in to reply
8 replies to this topic

#1 Chris Seto

Chris Seto

    Advanced Member

  • Members
  • PipPipPip
  • 405 posts

Posted 21 August 2010 - 04:11 PM

This is a VERY thoroughly tested electric speed controller driver for the Netduino. Right now, it supports Traxxas ESCs only, but you can add support for other ones by making your own config class. Please note, this is meant for hobby grade RC ESCs, not for anything industrial, which may have a completely different signaling system :)

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;

		}

	}
}


#2 Chris Walker

Chris Walker

    Secret Labs Staff

  • Moderators
  • 7767 posts
  • LocationNew York, NY

Posted 21 August 2010 - 05:56 PM

Now that is pretty awesome. Makes we want to buy the Traxxas just to play with the code. Thank you for this contribution to the community!

#3 Brandon G

Brandon G

    Advanced Member

  • Members
  • PipPipPip
  • 92 posts
  • LocationVancouver BC, Canada

Posted 16 January 2011 - 07:25 AM

Chris, as i look through how to do this best you are turning out to be a great resource, thanks it really appreciated. the above code, just trying to get my head around the concepts and expose my newbie skill sets here. the SetPulse method of the pwm, what is the 20,000, trying to find docs on it but dont quite get it I will attach my changes/ assumptions afterwards

#4 Chris Seto

Chris Seto

    Advanced Member

  • Members
  • PipPipPip
  • 405 posts

Posted 16 January 2011 - 12:59 PM

Read up on PPM spec, 20,000uS frame width with a 1000uS - 2000uS high duration. This is also old code, btw :)

#5 Brandon G

Brandon G

    Advanced Member

  • Members
  • PipPipPip
  • 92 posts
  • LocationVancouver BC, Canada

Posted 16 January 2011 - 07:24 PM

thanks chris, do have a link to more upto date code, i assume frame width would be a config point

#6 Chris Seto

Chris Seto

    Advanced Member

  • Members
  • PipPipPip
  • 405 posts

Posted 16 January 2011 - 08:32 PM

Frame width is a constant although some ESCs do allow do allow for a smaller frame and thus a faster update rate.

#7 ByteMaster

ByteMaster

    Advanced Member

  • Members
  • PipPipPip
  • 76 posts

Posted 16 April 2012 - 11:18 AM

Chris - thanks for this code. I did have a question though. As you stated spinning while your ramp up/down the the throttle w/ a sleep command is really ugly. 20ms to make a 20% change in throttle is forever on a small device, especially since most of that time is just sleeping. My last production experience with embedded stuff was the 'HC11 in about '95 and I'm still trying to grok how a managed frameworks works for doing this kind of stuff. But since the primary thing/activity are doing that's eating up CPU while ramping up/down the wave is to sleep, couldn't you spin up a new thread? Of course the challenge here is thread synchronization if another update comes in while the first update hasn't completed. But I think this would be very do-able. Also do you have to ramp up/down in steps of one? Thoughts?
Kevin D. Wolf
Windows Phone Development MVP
President Software Logistics, LLC
Tampa, FL

#8 Giosax.net

Giosax.net

    New Member

  • Members
  • Pip
  • 3 posts

Posted 16 September 2013 - 02:07 PM

Hi All, :rolleyes:

 

I try to use this drive code for my ESC (Mistery FM30A) and netuduino 2 plus, but I have some question because this code work on MF 4.1... :(
I need the confirm for this changes in MF 4.2:
 

 

MF 4.1 Code: (Costructor)

/// <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 static void Main()
  {
  SpeedController xl5 = new SpeedController(Pins.GPIO_PIN_D9, new TRAXXAS_XL5());

... ...

MF 4.2 Code:

public SpeedController(Cpu.PWMChannel pin, SpeedControllers escModel){   // Set up the PWM port   esc = new PWM(pin, 20000, 1500, PWM.ScaleFactor.Microseconds, false);   // Bind the ESC settings   this.escModel = escModel;   // Pull the throttle all the way out   Throttle = 0;   // Arm the ESC   Thread.Sleep(escModel.armPeriod);}... ... ... public static void Main(){   SpeedController xl5 = new SpeedController(PWMChannels.PWM_PIN_D9, new TRAXXAS_XL5());.....

?

?

?

?

?

?

 

MF 4.1 Code:

public void disengage(){    esc.SetDutyCycle(0);}......// 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);   }}

MF 4.2 code

public void disengage(){    esc.Duration = 0;}......// 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.Duration = (uint)map(set, 0, 100, range[0], range[1]);       Thread.Sleep(rampIterationPause);   }}else{   for (int set = currentThrottle; set <= value; set++)   {       esesc.Duration = (uint)map(set, 0, 100, range[0], range[1]);        Thread.Sleep(rampIterationPause);   }}

Could you confirm me this change?!  :) ;)

 

Thxxxxxxx

Gianni



#9 gtwillia

gtwillia

    New Member

  • Members
  • Pip
  • 2 posts

Posted 23 November 2013 - 11:08 PM

Does anyone have a code example that works with the netduino plus? The code above is old.

 

Regards,

 

 

Gregory






0 user(s) are reading this topic

0 members, 0 guests, 0 anonymous users

home    hardware    projects    downloads    community    where to buy    contact Copyright © 2016 Wilderness Labs Inc.  |  Legal   |   CC BY-SA
This webpage is licensed under a Creative Commons Attribution-ShareAlike License.