Netduino Servo Control in NETMF 4.2 / 4.3.x
So you been looking for some code that actually works with the Netduino 4.3.x & up to control a servo, well now you have found it. I credit most of the code here thanks to Chris Seto from back in 2010 posted on the Netduino forum and it worked great on the 4.0-4.1 framework! However, a lot has changed since then like PMW.SetPulse doesn't exist and now when instantiating a new PMW it requires a PMWChannel and not a Pin as an argument plus a few more required parameters. So, I took what Chris wrote and modified it to fit the current framework and implemented those changes. I do not get into the nitty gritty of explaining the changes here, this is just a implementation and share post. If you want a deeper dive just ask in the comments and maybe if there are enough I will come back to that. For the rest that want to consume, here you go, enjoy:
/*
* Servo 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 modify the driver, please include your contribution below:
*
* Chris Seto: Initial release (1.0)
* Chris Seto: Netduino port (1.0 -> Netduino branch)
* Chris Seto: bool pin state fix (1.1 -> Netduino branch)
*
* Theo Browning: Release (2.0) modified to work with current framework.
*
* */
using System;
using Microsoft.SPOT;
using Microsoft.SPOT.Hardware;
using SecretLabs.NETMF.Hardware;
using SecretLabs.NETMF.Hardware.Netduino;
namespace NetduinoApplication1
{
public class ServoController : IDisposable
{
/// <summary>
/// PWM handle
/// </summary>
private PWM servo;
/// <summary>
/// Timings range
/// </summary>
private int[] range = new int[2];
/// <summary>
/// Set servo inversion
/// </summary>
public bool inverted = false;
/// <summary>
/// Create the PWM Channel, set it low and configure timings
/// Changes here PWM Channel requires Channel, Period, Duration,
/// Scale and Inversion on instantiation.
/// </summary>
/// <param name="pwmChannel"></param>
public ServoController()
{
// Initialize the PWM Channel, set to pin 5 as default.
servo = new PWM(
PWMChannels.PWM_PIN_D5,
20000,
1500,
Microsoft.SPOT.Hardware.PWM.ScaleFactor.Microseconds,
false);
// Full range for FS90 servo is 0 - 3000.
// For safety limits I set the default just above/below that.
range[0] = 600;
range[1] = 2400;
}
/// <summary>
/// Allow for consumer to set own range.
/// </summary>
/// <param name="leftStop", "rightStop"></param>
public void SetRange(int leftStop, int rightStop)
{
range[1] = leftStop;
range[0] = rightStop;
}
/// <summary>
/// Dispose implementation.
/// </summary>
public void Dispose()
{
Disengage();
servo.Dispose();
}
/// <summary>
/// Disengage the servo.
/// The servo motor will stop, and try to maintain an angle
/// </summary>
public void Disengage()
{
servo.DutyCycle = 0; //SetDutyCycle(0);
}
/// <summary>
/// Set the servo degree
/// </summary>
public double Degree
{
set
{
/// Range checks
if (value > 180)
value = 180;
if (value < 0)
value = 0;
// Are we inverted?
if (inverted)
value = 180 - value;
// Set duration "pulse" and start the servo.
// Changes here are PWM.Duration and PWM.Start() instead of PWM.SetPulse().
servo.Duration = (uint)map((long)value, 0, 180, range[0], range[1]);
servo.Start();
}
}
/// <summary>
/// Used internally to map a value of one scale to another
/// </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(long x, long in_min, long in_max, long out_min, long out_max)
{
return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}
}
}
That's the class, now here is just a simple example of implementation, the following will infinite loop a servo to full left/right motion. Get past the infinite loop and the sleep as well as this is for simplicity, I would implement a timer and a condition if this were for real application. We can come back and talk about timers in NETMF another time as they are a whole different animal than timers in the full .Net Framework (post in comments if you would like to see more on timers).
public static void Main()
{
ServoController servo = new ServoController();
servo.SetRange(500, 2400);
bool runForever = true;
while (runForever)
{
for (int i = 1; i < 179; i++)
{
servo.Degree = i;
Thread.Sleep(25);
}
for (int i = 179; i > 1; i--)
{
servo.Degree = i;
Thread.Sleep(25);
}
}
servo.Dispose();
}
Enjoy and I hope this saves you some time!
Comments
- Anonymous
February 16, 2016
You can Post it To http://tricksntech.com This Tutorial as A Guest Please Come Always. - Anonymous
February 17, 2016
Absolutely, will do. - Anonymous
May 11, 2016
Hah, I'm Chris Seto. I wrote this like 6 years ago now. Very pleased to see it still lives on. Nice work.- Anonymous
June 13, 2016
Absolutely Chris, code is still alive and kicking, thanks for writing such a solid piece.
- Anonymous