Netduino home hardware projects downloads community

Jump to content


Photo

Netduino servo class


  • Please log in to reply
52 replies to this topic

#1 Chris Seto

Chris Seto

    Advanced Member

  • Members
  • PipPipPip
  • 405 posts

Posted 21 August 2010 - 05:46 AM

This is a class I use on my other NETMF hardware to run my RC car based robot. It took very little effort to port to the Netduino, hopefully someone find it useful :)

/*
 * Servo NETMF Driver
 *	Coded by Chris Seto August 2010
 *	<chris@chrisseto.com> 
 *	
 * Use this code for whatveer 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: Netduino port (1.0 -> Netduino branch)
 * Chris Seto: bool pin state fix (1.1 -> Netduino branch)
 * 
 * 
 * */

using System;
using Microsoft.SPOT.Hardware;
using SecretLabs.NETMF.Hardware;

namespace Servo_API
{
	public class Servo : 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 pin, set it low and configure timings
		/// </summary>
		/// <param name="pin"></param>
		public Servo(Cpu.Pin pin)
		{
			// Init the PWM pin
			servo = new PWM((Cpu.Pin)pin);

			servo.SetDutyCycle(0);

			// Typical settings
			range[0] = 1000;
			range[1] = 2000;
		}

		public void Dispose()
		{
			disengage();
			servo.Dispose();
		}

		/// <summary>
		/// Allow the user to set cutom timings
		/// </summary>
		/// <param name="fullLeft"></param>
		/// <param name="fullRight"></param>
		public void setRange(int fullLeft, int fullRight)
		{
			range[1] = fullLeft;
			range[0] = fullRight;
		}

		/// <summary>
		/// Disengage the servo. 
		/// The servo motor will stop trying to maintain an angle
		/// </summary>
		public void disengage()
		{
			// See what the Netduino team say about this... 
			servo.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 the pulse
				servo.SetPulse(20000, (uint)map((long)value, 0, 180, range[0], range[1]));
			}
		}

		/// <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;
		}
	}
}

Example code:
using System.Threading;
using SecretLabs.NETMF.Hardware.Netduino;
using Servo_API;

namespace NetduinoServoDemo
{
	public class Program
	{
		public static void Main()
		{
			Servo servo = new Servo(Pins.GPIO_PIN_D9);

			while (true)
			{
				for (int i = 0; i <= 180; i++)
				{
					servo.Degree = i;
					Thread.Sleep(10);
				}

				for (int i = 180; i >= 0; i--)
				{
					servo.Degree = i;
					Thread.Sleep(10);
				}
			}
		}

	}
}


#2 greg

greg

    Advanced Member

  • Members
  • PipPipPip
  • 169 posts
  • LocationChicago, IL

Posted 21 August 2010 - 12:59 PM

This is a class I use on my other NETMF hardware to run my RC car based robot. It took very little effort to port to the Netduino, hopefully someone find it useful :)

/*
 * Servo NETMF Driver
 *	Coded by Chris Seto August 2010
 *	<chris@chrisseto.com> 
 *	
 * Use this code for whatveer 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: Netduino port (1.0 -> Netduino branch)
 * 
 * 
 * */

using System;
using Microsoft.SPOT.Hardware;
using SecretLabs.NETMF.Hardware;

namespace Servo_API
{
	public class Servo : 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 pin, set it low and configure timings
		/// </summary>
		/// <param name="pin"></param>
		public Servo(Cpu.Pin pin)
		{
			// Init the PWM pin
			servo = new PWM((Cpu.Pin)pin);

			// See what the Netduino team say about this... 
			//servo.Set(false);

			// Typical settings
			range[0] = 1000;
			range[1] = 2000;
		}

		public void Dispose()
		{
			servo.Dispose();
		}

		/// <summary>
		/// Allow the user to set cutom timings
		/// </summary>
		/// <param name="fullLeft"></param>
		/// <param name="fullRight"></param>
		public void setRange(int fullLeft, int fullRight)
		{
			range[1] = fullLeft;
			range[0] = fullRight;
		}

		/// <summary>
		/// Disengage the servo. 
		/// The servo motor will stop trying to maintain an angle
		/// </summary>
		public void disengage()
		{
			// See what the Netduino team say about this... 
			//servo.Set(false);
		}

		/// <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 the pulse
				servo.SetPulse(20000, (uint)map((long)value, 0, 180, range[0], range[1]));
			}
		}

		/// <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;
		}
	}
}

Example code:
using System.Threading;
using SecretLabs.NETMF.Hardware.Netduino;
using Servo_API;

namespace NetduinoServoDemo
{
	public class Program
	{
		public static void Main()
		{
			Servo servo = new Servo(Pins.GPIO_PIN_D9);

			while (true)
			{
				for (int i = 0; i <= 180; i++)
				{
					servo.Degree = i;
					Thread.Sleep(10);
				}

				for (int i = 180; i >= 0; i--)
				{
					servo.Degree = i;
					Thread.Sleep(10);
				}
			}
		}

	}
}



Good stuff - I was in the middle of writing my own by why reinvent the wheel? :)

Thanks!

#3 Chris Seto

Chris Seto

    Advanced Member

  • Members
  • PipPipPip
  • 405 posts

Posted 21 August 2010 - 03:26 PM

Good stuff - I was in the middle of writing my own by why reinvent the wheel? :)

Thanks!

Nice, at least someone got some use out of it! Yeah, this class has been used and tested extensively, so it's all worked out. I will be updating the class in just a sec, too.

#4 klotz

klotz

    Advanced Member

  • Members
  • PipPipPip
  • 60 posts

Posted 22 August 2010 - 03:26 PM

Nice, at least someone got some use out of it! Yeah, this class has been used and tested extensively, so it's all worked out. I will be updating the class in just a sec, too.

I just tried to use the class from the post, and I get an error while compiling "Error 1 The type or namespace name 'Cpu' could not be found (are you missing a using directive or an assembly reference?)"

While I am new to using C# this is not the first class library I have made so I am a little confused about why I am getting the error. I did copy and pasted the file from the post.
Any suggestion?

#5 Chris Seto

Chris Seto

    Advanced Member

  • Members
  • PipPipPip
  • 405 posts

Posted 22 August 2010 - 04:40 PM

Did you include the Microsoft.SPOT.Hardware reference? You probably also need SecretLabs.NETMF.Hardware and SecretLabs.NETMF.Hardware.Netduino

#6 klotz

klotz

    Advanced Member

  • Members
  • PipPipPip
  • 60 posts

Posted 22 August 2010 - 06:52 PM

Did you include the Microsoft.SPOT.Hardware reference? You probably also need SecretLabs.NETMF.Hardware and SecretLabs.NETMF.Hardware.Netduino

So it was a problem with the way I created the project, not the source at all. Once I went to References under the solution explorer and added the Microsoft.SPOT.Hardware, it build just fine.
Like I said I am still a nubie when it comes to C#.

BTW: That and SecretLabs.NETMF.Hardware. Oops. :lol:
Thanks.

#7 Chris Seto

Chris Seto

    Advanced Member

  • Members
  • PipPipPip
  • 405 posts

Posted 22 August 2010 - 07:58 PM

No problem! You can also use the object browser to see what references a are required for what functions.

#8 Hai Nguyen

Hai Nguyen

    Advanced Member

  • Members
  • PipPipPip
  • 54 posts

Posted 23 August 2010 - 02:39 AM

Hi Chris,
This is Hai, I am trying to make distance sensor driver works on netduino, but for some reasons it doesn't work, could you take a look and see if you can notice I did something wrong.
code has been removed due to it may spark legal issue -Hai
Thanks!

Here is exception:

The thread '<No Name>' (0x2) has exited with code 0 (0x0).
    #### Exception System.ArgumentOutOfRangeException - CLR_E_OUT_OF_RANGE (1) ####
    #### Message: 
    #### SecretLabs.NETMF.Hardware.AnalogInput::ADC_Enable [IP: 0000] ####
    #### SecretLabs.NETMF.Hardware.AnalogInput::.ctor [IP: 0026] ####
    #### SecretLabs.NETMF.Hardware.Netduino.Drivers.DistanceDetector::.ctor [IP: 0045] ####
    #### Program::Main [IP: 0007] ####
A first chance exception of type 'System.ArgumentOutOfRangeException' occurred in SecretLabs.NETMF.Hardware.dll
An unhandled exception of type 'System.ArgumentOutOfRangeException' occurred in SecretLabs.NETMF.Hardware.dll


#9 Chris Seto

Chris Seto

    Advanced Member

  • Members
  • PipPipPip
  • 405 posts

Posted 23 August 2010 - 03:02 AM

Hi Chris,
This is Hai, I am trying to modify FEZ's distance sensor driver to get it work on netduino, but it doesnt work, could you take a look and see if you can notice I did something wrong.

Thanks!

using System;
using Microsoft.SPOT.Hardware;
using SecretLabs.NETMF.Hardware;

namespace SecretLabs.NETMF.Hardware.Netduino.Drivers
{
    class DistanceDetector: IDisposable
    {
        AnalogInput port;
        float Y0 = 0;
        float X0 = 0;
        float Y1 = 0;
        float X1 = 0;
        float C  = 0;

        public enum SharpSensorType : byte
        {
            GP2Y0A21YK = 0,
            GP2D120    = 1,
        }
        public void Dispose()
        {            
            port.Dispose();
        }

        public DistanceDetector(Cpu.Pin pin, SharpSensorType type) 
        {
            port = new AnalogInput((Cpu.Pin)pin );
            port.SetRange(0, 330);

            switch (type){
                case SharpSensorType.GP2Y0A21YK: 
                        Y0 = 10;
                        X0 = 315;
                        Y1 = 80;
                        X1 = 30;
                        break;
                case SharpSensorType.GP2D120: 
                        Y0 = 3;
                        X0 = 315;
                        Y1 = 30;
                        X1 = 30;
                        break;  
                }

                C = (Y1 - Y0) / (1 / X1 - 1 / X0);

            }
        
            public float GetDistance() 
            {
                return C / ((float)port.Read() + (float).001) - (C / X0) + Y0;
            }
    }
}
Usage:
 DistanceDetector frontL = new DistanceDetector(Pins.GPIO_PIN_D0,DistanceDetector.SharpSensorType.GP2Y0A21YK);      
      while (true)
        {            
Debug.Print("L: " + frontL.GetDistance().ToString() ); 
            Thread.Sleep(100);
        }
Here is exception:

The thread '<No Name>' (0x2) has exited with code 0 (0x0).
    #### Exception System.ArgumentOutOfRangeException - CLR_E_OUT_OF_RANGE (1) ####
    #### Message: 
    #### SecretLabs.NETMF.Hardware.AnalogInput::ADC_Enable [IP: 0000] ####
    #### SecretLabs.NETMF.Hardware.AnalogInput::.ctor [IP: 0026] ####
    #### SecretLabs.NETMF.Hardware.Netduino.Drivers.DistanceDetector::.ctor [IP: 0045] ####
    #### Program::Main [IP: 0007] ####
A first chance exception of type 'System.ArgumentOutOfRangeException' occurred in SecretLabs.NETMF.Hardware.dll
An unhandled exception of type 'System.ArgumentOutOfRangeException' occurred in SecretLabs.NETMF.Hardware.dll


Hi Hai, fancy seeing you here :rolleyes:

It looks like you are using the wrong pin. The argument is out of range because you are using a digital pin. Try GPIO_PIN_A0

#10 Chris Walker

Chris Walker

    Secret Labs Staff

  • Moderators
  • 7165 posts
  • LocationNew York, NY

Posted 23 August 2010 - 03:08 AM

Hi there Hai, welcome to the community; thanks for your post!

 DistanceDetector frontL = new DistanceDetector(Pins.GPIO_PIN_D0,DistanceDetector.SharpSensorType.GP2Y0A21YK);      
Here is exception:

The thread '<No Name>' (0x2) has exited with code 0 (0x0).
    #### Exception System.ArgumentOutOfRangeException - CLR_E_OUT_OF_RANGE (1) ####
    #### Message: 
    #### SecretLabs.NETMF.Hardware.AnalogInput::ADC_Enable [IP: 0000] ####
    #### SecretLabs.NETMF.Hardware.AnalogInput::.ctor [IP: 0026] ####
    #### SecretLabs.NETMF.Hardware.Netduino.Drivers.DistanceDetector::.ctor [IP: 0045] ####
    #### Program::Main [IP: 0007] ####
A first chance exception of type 'System.ArgumentOutOfRangeException' occurred in SecretLabs.NETMF.Hardware.dll
An unhandled exception of type 'System.ArgumentOutOfRangeException' occurred in SecretLabs.NETMF.Hardware.dll


Pins.GPIO_PIN_D0 is a digital pin. AnalogInput can only take readings from analog-capable pins. Did you mean to use Pins.GPIO_PIN_A0 (analog 0) instead?

One quick tip...

port = new AnalogInput((Cpu.Pin)pin );


You don't need to cast your pins with (Cpu.Pin). We use the Cpu.Pin type natively, even in the "Pins." enumeration--so you can just just say:

port = new AnalogInput(pin);

Nice to have you here!

Chris

EDIT: dang, Chris, you beat me in responding to Hai's post. :) Great stuff.

#11 Chris Seto

Chris Seto

    Advanced Member

  • Members
  • PipPipPip
  • 405 posts

Posted 23 August 2010 - 03:28 AM

"EDIT: dang, Chris, you beat me in responding to Hai's post. :) Great stuff. " Hahaha. 4 minutes later. At any rate, Hai and I know each other from the TinyCLR site. Hai, I'll be coding up the PPM decoder later tonight, although it won't be released until tomorrow, since I am waiting for the RC truck's battery to charge 8.5 hours) to test it. When that's done, I'll package it all up and make a new thread for the Netduino branch of the hobby grade RC car control suite.

#12 Hai Nguyen

Hai Nguyen

    Advanced Member

  • Members
  • PipPipPip
  • 54 posts

Posted 23 August 2010 - 05:45 AM

Hi CHRISes! :-) Sorry I join the fun a litle late. I did mix things up didn't I?...You guys are rock!!!! I did mean A0. It works now. Life is good again. I am waiting for your RX driver, also if neccessary post this driver in appropriate section so that people can find it easier? I recommend moderator to lock up that room to keep the library clean? Thank you very much!!

#13 Chris Seto

Chris Seto

    Advanced Member

  • Members
  • PipPipPip
  • 405 posts

Posted 23 August 2010 - 06:21 AM

Hi Hai, RX / PPM decoder driver is done, I'm just waiting to test it. Looks like it will be another 7.5 hours.

#14 Hai Nguyen

Hai Nguyen

    Advanced Member

  • Members
  • PipPipPip
  • 54 posts

Posted 23 August 2010 - 10:36 PM

Hi Hai,

RX / PPM decoder driver is done, I'm just waiting to test it. Looks like it will be another 7.5 hours.


Chris take your time, I am not in hurry.

I am planning to use my existing 3 Sharp sensors, 2 front + 1 back. I will see how it work with these sensor first and may end up getting a longer range one. Are you planning to get something more powerful/longer range?

#15 Chris Seto

Chris Seto

    Advanced Member

  • Members
  • PipPipPip
  • 405 posts

Posted 23 August 2010 - 11:53 PM

Hi Hai, Yeah, I'll be using a combination of Sharp IR and Parallax PING))) sensors. Each pair will be on it's own pan/tilt mount. I might have something like 4 pairs, one per corner.

#16 Hai Nguyen

Hai Nguyen

    Advanced Member

  • Members
  • PipPipPip
  • 54 posts

Posted 25 August 2010 - 05:39 AM

Hi Hai,

Yeah, I'll be using a combination of Sharp IR and Parallax PING))) sensors. Each pair will be on it's own pan/tilt mount. I might have something like 4 pairs, one per corner.


Chris,

Did you get a chance to play with sensors on netduino the drive i posted early for some reasosn it returns same reading everytime, I am having some sort of issues with Netduino deployment so I am not sure if the issue is with sensor driver

#17 Chris Seto

Chris Seto

    Advanced Member

  • Members
  • PipPipPip
  • 405 posts

Posted 25 August 2010 - 03:35 PM

Hi Hai, I have been playing with my Netduino plenty, but I didn't know you had something you wanted me to test. I'll do that tonight and let you know :)

#18 Hai Nguyen

Hai Nguyen

    Advanced Member

  • Members
  • PipPipPip
  • 54 posts

Posted 27 August 2010 - 06:03 AM

Hi Hai,

I have been playing with my Netduino plenty, but I didn't know you had something you wanted me to test. I'll do that tonight and let you know :)



Chris,
Never mind, My wiring got messed upp, otherwise the driver works just fine.

Thanks!

#19 Arceon

Arceon

    New Member

  • Members
  • Pip
  • 9 posts
  • LocationManchester, UK

Posted 02 September 2010 - 09:21 PM

Hey Chris you couldn't help a guy out could ya? :)

I'm using a servo off an old helicopter (link) and no matter what I do, I can't get it to move using code. If I apply power to it, after about 2-3 secs it spins all the way to the right, is that what it's supposed to do?

I'm very new to all this in case you couldn't tell :D

#20 Chris Walker

Chris Walker

    Secret Labs Staff

  • Moderators
  • 7165 posts
  • LocationNew York, NY

Posted 03 September 2010 - 04:11 AM

I'm using a servo off an old helicopter (link) and no matter what I do, I can't get it to move using code. If I apply power to it, after about 2-3 secs it spins all the way to the right, is that what it's supposed to do?


I'm sure Chris will pitch in, but in the meantime one quick bit of info:

1. Motors work by applying power to them. The more power (or the higher dutycycle on the PWM) the faster they move, generally speaking.
2. Servos work by sending them short pulses every ## milliseconds. The length of the pulse dictates what angle the servo should move to. To move a servo all the way around, you'd send a 90 degree command followed by a 180 degree command, etc. (generally--pick your angles for what makes sense).

The beautiful thing about servos is that you get very precise movements when moving things like robot arms and you get very precise speeds when turning the servo like a motor. Oh, plus you can simply apply the proper voltage to the servo and just use the lines from the Netduino to act as data control lines.

Chris

P.S. I'm totally assuming that you are setting the dutycycle here like a motor and not using servo code--but I'm also probably totally off-base :) Hopefully this is helpful either way.




0 user(s) are reading this topic

0 members, 0 guests, 0 anonymous users

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