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.

indimini

Member Since 02 Oct 2012
Offline Last Active Feb 09 2013 12:25 AM
-----

#41414 Netduino Go Ethernet

Posted by indimini on 12 December 2012 - 02:21 AM

Chris,

On July 12, you wrote "Once we receive the Ethernet module samples, we'll run a few days of tests. Assuming those pass (which they almost always do), it'll take about a month to manufacture, test, and ship the modules to resellers. So not too long..."


Sept 27th you wrote "We have a few last items to check off before we put these on the production line, but at this point it looks like we're good to go. I can't wait to get these out to everyone"


Dec 4th you wrote "We're working on the Ethernet modules and firmware update..." which doesn't sound close to what was promised nearly five months ago.


As somebody who bought into the Netduino Go's vision based on what was posted by your company on this forum, I honestly feel like I've been mislead and bought into a technology that isn't ready for my needs. (I'm also waiting for a one-wire library and a shield base that doesn't require four sockets to use.) I don't mean to be an *ss, but honestly, lots of promises have been made to your customers that aren't being fulfilled. When can we expect real dates for these products/features?


#36981 Continuous Rotation Servo on the Shield Base controlled with Potentiometer

Posted by indimini on 10 October 2012 - 07:24 PM

Great write up! This inspired me to pull out some old servos and start playing with the shield and PWM. (I'm so new to all this microcontroller stuff, but having far too much fun.) I ended up creating some classes to make it easier to play with the servos. I thought I'd post it to get feedback. (Who knows, others may even find it useful.)

First, I defined a class "Servo" that extends the Microsoft.SPOT.Hardware.PWM class. The class adds methods to center the servo, to rotate it given a specified angle, and to position it given a bounded value (e.g. POT value).

The servo class is designed to work with the ServoFactory static class. ServoFactory lets you configure settings for different servos and offers a single static method to construct a servo instance. I use this rather than instantiating the servo's directly. The servo type, defined in an enum, determines how the servo behaves in terms of allowed range of movement, pulse widths, etc.


  /// <summary>
  /// This class encapsulates the operation of a servo, allowing for easy operations to set angle and return-to-center.
  /// </summary>
  public class Servo : PWM
  {
    /// <summary>
    /// Constructs an instance of the servo.  Using the ServoFactory to create an instance of a specific servo type
    /// is the recommended method of servo instantiation
    /// </summary>
    /// <param name="channel">The PWM channel to which the servo is connected</param>
    /// <param name="info">Struct containing servo-specific functional parameters</param>
    /// <param name="reverse">Indicates whether or not the default servo rotation should be reversed</param>
    /// <param name="maxAngle">Sets the maximum angle the servo can travel.</param>
    public Servo(Cpu.PWMChannel channel, ServoFactory.ServoConfig info, bool reverse, double maxAngle)
      : base(channel, 20000, info.Neutral, ScaleFactor.Microseconds, info.Invert)
    {
      ReverseMult = reverse ? -1 : 1;
      MaxAngle = maxAngle;
      Settings = info;
    }

    /// <summary>
    /// A multiplier used to negate values if reverse mode is desired.
    /// </summary>
    private float ReverseMult;
    /// <summary>
    /// Holds the maximum rotation angle allowed
    /// </summary>
    private double MaxAngle;
    /// <summary>
    /// Holds a reference to the servo's parameter values
    /// </summary>
    private ServoFactory.ServoConfig Settings;

    /// <summary>
    /// Returns the servo to it's neutral position
    /// </summary>
    public void Center()
    {
      base.Duration = Settings.Neutral;
    }

    /// <summary>
    /// Moves the servo to the specified angle, or the max angle if outside those bounds
    /// </summary>
    /// <param name="angle">The position angle in degrees</param>
    public void TurnTo(double angle)
    {
      double a = System.Math.Min(System.Math.Abs(angle), Settings.MaxRotationAngle);
      if (angle < 0)
        a *= -1;
      base.Duration = (uint)(Settings.Neutral + (a / Settings.AngleFromNeutral * Settings.DegPulse * ReverseMult));
    }

    public void ReverseRotation()
    {
      ReverseMult *= -1;
    }

    /// <summary>
    /// Moves a servo to a position based on the input relative to the min and max bounds. inMin corresponds to the minimum
    /// servo angle and inMax the maximum angle.
    /// </summary>
    /// <param name="input">desired value</param>
    /// <param name="inMin">lower bound</param>
    /// <param name="inMax">upper bound</param>
    public void MoveTo(double input, double inMin, double inMax)
    {
      double outMin = Settings.Neutral - ReverseMult * (MaxAngle / Settings.AngleFromNeutral * Settings.DegPulse);
      double outMax = Settings.Neutral + ReverseMult * (MaxAngle / Settings.AngleFromNeutral * Settings.DegPulse);
      base.Duration = (uint)((input - inMin) * (outMax - outMin) / (inMax - inMin) + outMin);
    }
  }


  /// <summary>
  /// This is a static helper class that provides a factory method to construct a known set of servo types
  /// based on their configuration data.
  /// </summary>
  public static class ServoFactory
  {
    /// <summary>
    /// Defines parameters identifying operational performance of a servo
    /// </summary>
    public struct ServoConfig
    {
      /// <summary>
      /// Enumeration identifying the servo type
      /// </summary>
      public ServoType Type;
      /// <summary>
      /// Holds the pulse width in # of microseconds to set server neutral position
      /// </summary>
      public uint Neutral;
      /// <summary>
      /// Holds the pulse adjustment to rotate the servo the specified pulse angle
      /// </summary>
      public uint DegPulse;
      /// <summary>
      /// Holds the pulse angle set when the DegPulse value is applied to the neutral pulse width
      /// For example, 400 microseconds with a DegPulse of 45 Deg indicates that the servo will rotate
      /// 45 deg when the pulse is added to neutral
      /// </summary>
      public double AngleFromNeutral;
      /// <summary>
      /// Sets the maximum rotation angle for the servo - ensures that users don't try to over-rotate the servo
      /// </summary>
      public double MaxRotationAngle;
      /// <summary>
      /// Sets a boolean indicating whether or not to invert the PWM signal
      /// </summary>
      public bool Invert;
    }

    /// <summary>
    /// Array holding information for each registered servo type
    /// </summary>
    private static ServoConfig[] registeredServos;

    // To Add additional servo definitions, add an enum value above ServoCount and add a record
    // to the ServoInfo array in the initialize method

    /// <summary>
    /// Identifies the servos available.
    /// </summary>
    public enum ServoType
    {
      Airtronics_94102,
      Futuba_S3004,
      ServoCount
    }

    /// <summary>
    /// Initializes the parameters for the known registered servo types
    /// </summary>
    private static void Initialize()
    {
      registeredServos = new ServoConfig[(int)ServoType.ServoCount];
      registeredServos[(int)ServoType.Futuba_S3004] = new ServoConfig { Type = ServoType.Futuba_S3004, Neutral = 1520, DegPulse = 400, AngleFromNeutral = 45, MaxRotationAngle = 90, Invert = false };
      registeredServos[(int)ServoType.Airtronics_94102] = new ServoConfig { Type = ServoType.Airtronics_94102, Neutral = 1500, DegPulse = 390, AngleFromNeutral = 45, MaxRotationAngle = 90, Invert = false };
    }

    /// <summary>
    /// Factory method that creates an instance of the Servo class, initialized from the available servo information
    /// </summary>
    /// <param name="channel">The PWM channel the servo is connected to</param>
    /// <param name="type">The enumeration value for a known servo type</param>
    /// <param name="reverse">If true, the requests to move the servo are reversed from their default behavior</param>
    /// <param name="maxAngle">Sets the maximum allowed rotation angle - defaults to the maximum specified for the servo, but can be made to be less</param>
    /// <returns>An instance of the servo</returns>
    /// <exception cref="UnknownTypeException">Throws this if the servo type is not defined.</exception>
    public static Servo CreateServo(Cpu.PWMChannel channel, ServoType type, bool reverse = false, double maxAngle = double.NaN)
    {
      if (registeredServos == null)
        Initialize();

      foreach (var servoInfo in registeredServos)
      {
        if (servoInfo.Type == type)
          return new Servo(channel, 
            servoInfo, 
            reverse, 
            (maxAngle == double.NaN) ? servoInfo.MaxRotationAngle : System.Math.Min(servoInfo.MaxRotationAngle, maxAngle));
      }
      // If you got here, the servo type was not initialized.
      throw new UnknownTypeException();
    }
  }


An example of how I used this code is shown below.


namespace ServoFun
{
  public class Program
  {

    private static ShieldBase shieldBase;
    private static NetduinoGo.Button btn;
    private static Servo servo;

    static bool started;

    public static void Main()
    {
      btn = new NetduinoGo.Button(GoSockets.Socket1);
      btn.ButtonReleased += new NetduinoGo.Button.ButtonEventHandler(btn_ButtonReleased);
      shieldBase = new ShieldBase(GoSockets.Socket5);

      // Create our type-specific servo
      servo = ServoFactory.CreateServo(shieldBase.PWMChannels.PWM_PIN_D5, ServoFactory.ServoType.Futuba_S3004);

      servo.Start();
      servo.Center();
      started = true;

      while (true)
      {
        Thread.Sleep(100);
      }
    }

    static void btn_ButtonReleased(object sender, bool isPressed)
    {
      if (started)
      {
        if (ndx >= testAngles.Length)
        {
          // Once we get to last test data angle, stop the servo
          servo.Stop();
          started = false; 
        }
        else
        {
          // Test servo rotation.
          servo.TurnTo(testAngles[ndx++]);
        }
      }
      else
      {
        // Pressing after stop restarts the servo and re-centers it.
        servo.Start();
        servo.Center();
        ndx = 0;
        started = true;
      }
    }

    static float[] testAngles = new float[] { 18, 45,-45,-90}; // Specify a set of rotational angles
    static int ndx = 0; // Index into my test data.
  }
}



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.