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.

BrandonW6's Content

There have been 8 items by BrandonW6 (Search limited from 25-April 23)


By content type

See this member's

Sort by                Order  

#46761 I2C and Analog Pins on Netduino 2

Posted by BrandonW6 on 06 March 2013 - 03:09 PM in Netduino 2 (and Netduino 1)

Hello.

 

I'm curious about the pin changes between the netduino and the netduino 2.

 

I notice that there are a separate pair of pins now for i2c clock and data on the netduino 2.

Previously it was on analog pins 4/5 i believe.

 

So question: does this mean I am now able to use all 6 analog inputs while using i2c?

 

The final goal is to drive 6 servos, have 6 analog inputs to help control the servos, and an RGB LCD Display to control settings and options.

 

Should be all possible right?

 

Only corncern i have is that the LCD shield has connections for both the new I2C pin locations, as well as the old ones.  So I am thinking I will have to disconnect it from the analog pins.

 

Thanks in advance!

 

 




#37430 3d Matrix Transformations

Posted by BrandonW6 on 19 October 2012 - 02:36 PM in General Discussion

Hello, I have the need to do some 3D transformations to Rotate and Translate 3d Points. Can anyone point me to a Library that will run on the Micro Framework?



#37047 Many many PWMs

Posted by BrandonW6 on 11 October 2012 - 06:15 PM in General Discussion

Thanks for the info Carb, I may try out one of those boards later, I like the idea of driving it direct from USB.

But in any case, I had already ordered the Adafruit 16 channel 12 bit Pwm driver. I translated the arduino driver files into c# and found it works great using i2c to communicate to the board. Here is the driver code for anyone who needs it:

/*
 *      Adafruit 16 channel 12 bit PWM Servo Driver NETMF
 *      Code Translated by Brandon Watt Oct 2012
 *      
 * This board use I2C to communicate, 2 pins are required to 
 * interface. For Netduino/Arduino Uno, thats SCL -> Analog 5, SDA -> Analog 4
 * 
 * Brandon Watt: Inital release (1.0) Translated arduino code into c#
 * Based on driver files found at "https://github.com/adafruit/Adafruit-PWM-Servo-Driver-Library"
 * 
 */
using System;
using Microsoft.SPOT;
using System.Threading;
using Toolbox.NETMF.Hardware;

namespace Adafruit_16channel
{

    class Adafruit_PWMServoDriver
    {
        private MultiI2C _Device;

        private const byte PCS9685_SUBADR1 = 0x2;
        private const byte PCA9685_SUBADR2 = 0x3;
        private const byte PCA9685_SUBADR3 = 0x4;

        private const byte PCA9685_MODE1 = 0x0;
        private const byte PCA9685_PRESCALE = 0xFE;

        private const byte LED0_ON_L = 0x6;
        private const byte LED0_ON_H = 0x7;
        private const byte LED0_OFF_L = 0x8;
        private const byte LED0_OFF_H = 0x9;

        private const byte ALLLED_ON_L = 0xFA;
        private const byte ALLLED_ON_H = 0xFB;
        private const byte ALLLED_OFF_L = 0xFC;
        private const byte ALLLED_OFF_H = 0xFD;

        private byte _i2caddr;

        public Adafruit_PWMServoDriver(byte addr = 0x40, int ClockRateKhz = 200)
        {
            _i2caddr = addr;
            this._Device = new MultiI2C(_i2caddr, ClockRateKhz);
        }
        public void Begin()
        {
            Reset();
        }
        public void Reset()
        {
            write8(PCA9685_MODE1, 0x0);
        }
        public void setPWMFreq(float freq)
        {
            float prescaleval = 25000000;
            prescaleval /= 4096;
            prescaleval /= freq;
            prescaleval -= 1;
           // Debug.Print("Estimated pre-scale: " + prescaleval);
            byte prescale = (byte)System.Math.Floor(prescaleval + 0.5);
           // Debug.Print("Final Pre-scale: " + prescale);

            byte oldmode = read8(PCA9685_MODE1);
            byte newmode = (byte)((oldmode & 0x7F) | 0x10); // sleep
            write8(PCA9685_MODE1, newmode); // go to sleep
            write8(PCA9685_PRESCALE, prescale); // set the prescaler
            write8(PCA9685_MODE1, oldmode);
            Thread.Sleep(5);
            write8(PCA9685_MODE1, (byte)(oldmode | 0x80));

        }
        public void setPWM(byte num, UInt16 on, UInt16 off)
        {
            write8((byte)(LED0_ON_L + 4 * num), (byte)on);
            write8((byte)(LED0_ON_H + 4 * num), (byte)(on >> 8));
            write8((byte)(LED0_OFF_L + 4 * num), (byte)off);
            write8((byte)(LED0_OFF_H + 4 * num), (byte)(off >> 8));
        }

        private byte read8(byte addr)
        {
            byte[] ReadBuffer = new byte[1];
            this._Device.WriteRead(new byte[] { addr }, ReadBuffer);
            return ReadBuffer[0];
        }
        private void write8(byte addr, byte d)
        {
            this._Device.Write(new byte[] { addr, d });
        }
    }
}

To use this driver you must have the .Net MF toolkit as it uses the MultiI2c Device class

To setup the driver for your servo first call on the instance:
pwm.setPWMFreq(50); // This sets the frequency pre-scale to 50hz

To set the servo or PWM values you call:
pwm.setPWM(0, 0, PulseLength);  // (servo number 0-15, start of pulse, end of pulse)

Because of the prescale, the values for pulse length are lower then you expect. Since they correlate to percentage of entire on/off cycle, using 12 bits gives values between 0 to 4096 so to control a standard servo, the range runs from about 150 to 600. Or you can use the following function that does the calculation to map the values for you.

public static void setServoPulse(byte n, double pulse) 
        {
            double pulselength;
            pulselength = 20000; // 1,000,000 us per second
            pulselength /= 50; // 50 Hz
           
            pulselength /= 4096; // 12 bits of resolution
           
            pulse *= 1000;
            pulse /= pulselength;

            Debug.Print("Pulse " + pulse);
            pwm.setPWM(n, 0, (ushort)pulse);
        }

Figured someone else may want to use this board, and this will save you some time.



#36555 Many many PWMs

Posted by BrandonW6 on 05 October 2012 - 01:07 AM in General Discussion

Does anyone know if there are drivers available for that Adafruit 16 channel pwm driver? Any idea how hard it would be to get that working?



#36326 Servo Motor Keyframing

Posted by BrandonW6 on 30 September 2012 - 11:14 PM in Project Showcase

Hey Paul,

Very interesting idea about monitoring current draw. That's something I never would have thought of.
After some more tinkering this afternoon, I think I have a decent start. I decided that the solution was to implement a servo controller class that could handle both situations. Then use the appropriate method where applicable.

Keyframes are stored in a queue that are executed in order.

The servo controller has two methods:
void AddFrame(double targetAngle, double pause)
- go to this angle and wait before going to another angle
void AddFramesAtDuration(double targetAngle, double duration, int steps, double pause)
- go to target angle, making it get there in the given duration, how many between steps, then pause before next key

Next Steps include an "Ease In/Out routines" using a sigmoid curve to control acceleration and deceleration.
Sample code for Controller class below.
*Note, this class is designed to work with the Servo Controller class by Chris Seto which can be found on another thread*

/*
 * Servo NETMF Controller
 *      Coded by Brandon Watt Sept 2012
 *      
 * 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:
 * 
 * Brandon Watt: Initial release (1.0)
 * 
 * */

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

namespace Servo_API
{
    /// <summary>
    /// Class to Store KeyFrames (What angle, and how long to wait before sending the next angle)
    /// </summary>
    public class servoKeyFrame
    {
        public double angle;
        public double seconds;

        public servoKeyFrame(double targetAngle, double howManySeconds)
        {
            this.angle = targetAngle;
            this.seconds = howManySeconds;
        }
    }

    class ServoController : IDisposable
    {
        // Servo to Control
        public Servo servo;

        // Queue of keyframes (FIFO)
        private System.Collections.Queue frames = new System.Collections.Queue();

        // Private Thread for this servo, used to manage position and saves CPU cycles since mostly sleeping
        public Thread servoThread;

        // Most recent angle added, for comparing angular difference
        private double lastAngleAdded;

        /// <summary>
        /// Initializes a servo on given channel
        /// </summary>
        /// <param name="channelPin"></param>
        public ServoController(Cpu.PWMChannel channelPin)
        {
            servo = new Servo(channelPin);
            servoThread = new Thread(new ThreadStart(ServoThreadFunction));
            servoThread.Start();
        }

        /// <summary>
        /// Add a keyframe
        /// </summary>
        /// <param name="targetAngle">Angle to Move to</param>
        /// <param name="pause">How long to pause afer arrival</param>
        public void AddFrame(double targetAngle, double pause)
        {
            frames.Enqueue(new servoKeyFrame(targetAngle, pause)); // add the latest keyframe
            lastAngleAdded = targetAngle;  // used in 'AddFramesAtDuration'

            // if the thread is suspended, wake it.
            if (servoThread.ThreadState == ThreadState.Suspended)
            {
                servoThread.Resume();
            }
        }

        /// <summary>
        /// Add a set of frames, enabling you to control how long it takes to hit the target angle
        /// </summary>
        /// <param name="targetAngle">Angle to Move to</param>
        /// <param name="duration">How long should it take to get there?</param>
        /// <param name="steps">How many incremental steps should it make?</param>
        /// <param name="pause">How long to Pause after arrival?</param>
        public void AddFramesAtDuration(double targetAngle, double duration, int steps, double pause)
        {
            // figure out, how far we are actually going to move
            double startAngle = lastAngleAdded;
            double diff = targetAngle - startAngle;

            double anglePerStep = diff / (steps + 1); // degrees per step
            double pausePerStep = duration / (steps + 1); // pause per step

            for (int s = 1; s < steps; s++)
            {
                frames.Enqueue(new servoKeyFrame(startAngle + s * anglePerStep, pausePerStep));  // enqueue all those steps
            }

            AddFrame(targetAngle, pause); // Add the final step and wake thread
        }

        /// <summary>
        /// Main worker thread function, moves servo to position and waits
        /// </summary>
        private void ServoThreadFunction()
        {
            servoKeyFrame nextKey = null;
            while (true)
            {
                if (frames.Count > 0)
                {
                    nextKey = (servoKeyFrame)frames.Dequeue();
                    servo.Degree = nextKey.angle;

                    Thread.Sleep((int)(nextKey.seconds * 1000)); // sleep until ready for next move
                }
                else servoThread.Suspend();  //  Completed all the steps, goto sleep
            }
        }

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


    }
}

To use this code

using System;
using System.Threading;
using Microsoft.SPOT;
using Microsoft.SPOT.Hardware;
using SecretLabs.NETMF.Hardware;
using SecretLabs.NETMF.Hardware.Netduino;
using Servo_API;

namespace NetduinoApplication5
{
    public class Program
    {

        static ServoController s1 = new ServoController(PWMChannels.PWM_PIN_D9);
        static ServoController s2 = new ServoController(PWMChannels.PWM_PIN_D10);

        static InterruptPort sw = new InterruptPort(Pins.ONBOARD_SW1, false, Port.ResistorMode.Disabled, Port.InterruptMode.InterruptEdgeLow);
        static bool runMainThread = true;

        public static void Main()
        {
            sw.OnInterrupt += new NativeEventHandler(sw_OnInterrupt);
            EnqueueDemoFrames();

            while (runMainThread)
            {
                // Do something else
                TimeSpan t = Microsoft.SPOT.Hardware.Utility.GetMachineTime();
                double seconds = t.Ticks / TimeSpan.TicksPerSecond;
                Debug.Print(seconds.ToString());
                Thread.Sleep(1000);
            }
        }

        public static void EnqueueDemoFrames()
        {
            // This demo will show that total movement time for both motors can remain synced (for the most part)
            s1.AddFrame(0, 0);
            s1.AddFrame(180, 2.5);
            s1.AddFramesAtDuration(0, 2, 100, 0.5);
            s1.AddFrame(90, 1);
            s1.AddFrame(0, 0);
            // 0 + 2.5 + 2 + 0.5 + 1 + 0 = 6 seconds

            s2.AddFrame(0, 0);
            s2.AddFramesAtDuration(180, 2, 100, 0.5);
            s2.AddFrame(0, 2.5);
            s2.AddFrame(90, 1);
            s2.AddFrame(0, 0);
            // 0 + 2 + 0.5 + 2.5 + 1 = 6 seconds
        }

        public static void sw_OnInterrupt(uint data1, uint data2, DateTime time)
        {
            //Debug.Print("Button Presses" + data1 + " " + data2);
            EnqueueDemoFrames();
        }
    }


}



#36305 Servo Motor Keyframing

Posted by BrandonW6 on 30 September 2012 - 06:48 PM in Project Showcase

Hello, I'm new to netduino programming and also to this forum. I'm wondering if you guys can perhaps provide some insight onto a topic I'm working on. Basically, I am writing some controllers that will manage multiple servos together in an IK chain as an arm or leg configuration. My question is this, with no positional feedback from the servos, how should I track where my servo is? As I see it, there are two solutions. A: Provide many updates constantly that are only tiny angle changes. B: Provide less frequent updates, and try to "guess" how long it will take to get to that angle before sending the next one. With solution A: I will spend alot of CPU time sending updates to angles. Which isn't ideal since the servos are capable of some level of target seeking. With solution B: I have the issue of how frequently to update. If I update too slowly, the servo will have hit the target and will be stopped waiting for the next angle. But if I update too quickly, I risk the servo skipping over desired angles. This would be especially apparent when the servo direction changes. If I send "goto 45 degress, then 90 degrees, then 45 degrees" to quickly, it may not reach 90 before it returns. The end goal is to be able to keyframe a sequence of movements, and have it execute those movements as smoothly as possible with no start/stop stutter. I figure this must be an issue someone has come across. Just curious to hear what you guys think. Thanks Brandon



#36303 LCARS Home Automation PIN Pad

Posted by BrandonW6 on 30 September 2012 - 06:36 PM in Project Showcase

Nice idea! I would like to do something similar one day! Look forward to seeing the progress!



#36279 Netduino servo class

Posted by BrandonW6 on 30 September 2012 - 02:00 AM in Netduino 2 (and Netduino 1)

I updated the sample for the new PWM classes in 4.2.0.1
Changes include PWM constructor code with new parameters and code to set angle.

/*
 * 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;
using Microsoft.SPOT.Hardware;
using SecretLabs.NETMF.Hardware;
using SecretLabs.NETMF.Hardware.Netduino;

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 Channel, set it low and configure timings
        /// </summary>
        /// <param name="pin"></param>
        public Servo(Cpu.PWMChannel channelPin) 
        {
            // Init the PWM pin
            servo = new PWM((Cpu.PWMChannel)channelPin, 20000, 1500,PWM.ScaleFactor.Microseconds, false);

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

using System;
using System.Threading;
using Microsoft.SPOT;
using Microsoft.SPOT.Hardware;
using SecretLabs.NETMF.Hardware;
using SecretLabs.NETMF.Hardware.Netduino;
using Servo_API;

namespace NetduinoApplication5
{
    public class Program
    {
        public static void Main()
        {
            Servo servo = new Servo(PWMChannels.PWM_PIN_D9);
           
            // Change 'While' to 'For' to limit how many time it repeats
            for (int j = 0; j < 3; j++) 
            {
                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);
                }
            }

        }

    }
}




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.