Deepwire's Blog

Archive for August, 2011

Hacking the Adafruit Industries Arduino Motor Shield Part 2 – Netduino Motor Shield Driver

by on Aug.20, 2011, under Electronics, Programming, Technology

My last post here explained how to (theoretically) modify the Adafruit Industries Arduino Motor Shield to use the 4 PWM outputs of the Netduino to drive 4 Bi-directional DC Motors.

The shield was designed to use the 6 PWM of an Arduino, 4 for the DC motors, the other 2 for Servos.  Unfortunately, I am trying to build something using a Netduino to control 4 DC motors, using PWM.  While the Netduino does have 4 PWM outputs, only 2 of these connect to the motor inputs of the shield, the other 2 going to the servo pins.

The modifications re-route the second 2 PWM outputs of the Netduino to the second 2 motor inputs, instead of the servo pins.  Full details of the modifications are explained in my last post.  Here’s the quick version:

  1. Cut off/remove Pins 3 & 11 from the underside of the Motor Shield.
  2. Connect pin 10 to pin 11 on the motor shield.
  3. Connect pin 9 to pin 3 on the motor shield.

The next step, to use the shield with the Netduino and actually control 4 DC Motors, was the code.  The shield now uses the 4 PWM outputs from the Netduino to control the speed of the motors, but also 4 additional pins to control the Serial In/Parallel Out Shift Register.  This controls which motors are enabled, and which direction they run.  To make implementing motor control in code easier, I would need a driver to interface the Netduino with the Motor Shield.

Fortunately I was helped here by ‘UnkwnTech’ on the Netduino Forums who has already made a Netduino driver for the Adafruit Arduino Motor Shield.  The driver source code with a usage example can be found here: http://forums.netduino.com/index.php?/topic/2258-adafruit-motor-shield-driver/

This itself is a Netduino port of a driver originally written for the FEZ Domino/Panda boards (both are similar to the Netduino, and run the .NET Micro Framework).  The only changes made were to make it work with the Netduino.  This original driver for the FEZ boards, written by Nicolas ‘Nicolas3′ Ricquemaque can be found over on TinyCLR here: http://code.tinyclr.com/project/323/adafruit-motor-shield-driver/

This works with the ‘stock’ (unmodified) shield, and offers PWM control of 2 motors through PWM pins 5 & 6, switched (on/off – full speed) control of motors on pins 3 & 11, and PWM servo control on pins 9 & 10.  Because I had modified my Motor Shield, I also needed to modify this driver code to support these modifications.

My modified source code and usage example, including original comments to credit both original authors, ‘Nicolas3′ and ‘UnkwnTech’, can be found at the bottom of this post.

I have removed ALL code relating to the Servos and Stepper Motors, as my project does not use either of these (plus my modifications mean the Servo pins on the motor shield are not connected).  The motors defined in the code have been renumbered to Motors 1, 2, 3 & 4, to match the labelling on the motor shield.  Motors 3 & 4 (formerly 2A & 2B) have been redefined to use the PWM outputs of pins 9 & 10 (made possible due to my shield modifications).  The error of motor 3 & 4 being the wrong way round, as mentioned in the original source code, has been corrected, by swapping their defined PWM pin and swapping which latch state enabled the motor.

This was a triumph!  I’m making a note here: Huge Success.

With the hardware modifications to the Motor Shield, and changes to the Motor Shield Driver code, it works!  I can now control 4 DC motors using the 4 PWM outputs of the Netduino!

Please use it, and modify it, if you want to drive 4 DC motors using the PWM outputs of the Netduino.  If you have connected the pins together on the motor shield the opposite way round, you will need to modify the code to reflect this.  This would include changing the PWM pin definition in the constructor, and reversing the motors in the Switch/Case statement, so the output of the Shift Register enabled the correct motor pin. If you have any feedback, or improvements, let me know, as I can’t guarantee this is perfect.

Now for me to go and use this modified shield and code in something cool!

MotorShield.cs Netduino Modified Adafruit Motor Shield Driver:

/*  Adafruit Motor "Shield v1.0" / See: http://www.ladyada.net/make/mshield/index.html
 *  Driver v0.1a - Copyright 2011 Arron Chapman
 *
 *  Code modified to drive 4 Bi-directional DC Motors using the 4 PWM Outputs
 *  of a Netduino, using a modified Adafruit Motor Shield (see notes below).   
 * 
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License. 
 *  
 * 
 * This Adaptation is based on the code provided by Nicolas Ricquemaque
 * The original code, for the FEZ Domino/Panda boards can be found at: 
 * http://code.tinyclr.com/project/323/adafruit-motor-shield-driver/
 * 
 * The adapted version of the above code, provided by UnkwnTech,
 * for the Netduino, can be found at:
 * http://forums.netduino.com/index.php?/topic/2258-adafruit-motor-shield-driver/
 *
 *
 * Final modifications have been made to support 4 DC Motors on the modified 
 * Adafruit Motor Shield, as detailed here:
 * http://blog.deepwire.co.uk/?p=420
 *
 * NOTE: The PWM Frequency is still set to 100Hz, as in the original code.
 * I have experimented with changing this, with differing results.
 * To successfully control the speed, depending on which motors you are using,
 * you may need to change this value.  I found that it improved by increasing it.  
 *
 * This has been tested with a modified Adafruit Industries Motor Shield v1.2
 *
 */

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

namespace Robot.Drivers.Adafruit
{
    public class Mshield : IDisposable
    {
        public enum Drivers : byte { None = 0, Driver1, Driver2, Both }
        public enum Motors : byte { M1 = 0, M2, M3, M4 }

        private Drivers UsedDriver;
        //Code modified here to make all DC Motors PWM controlled, and to renumber according to Shield labels
        private PWM Motor1, Motor2, Motor3, Motor4; // Enable L293D driver #1a and #1b, #2a and #2b
        private OutputPort MotorLatch, MotorEnable, MotorClk, MotorData; // 74HCT595 Commands
        byte latch_state; // Actual 74HCT595 output state

        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="driver"> Which driver to initialize : 1=Driver 1, 2=Driver 2, 3=Both</param>
        public Mshield(Drivers driver = Drivers.Both)
        {
            UsedDriver = driver;
			// All Motor definitions have been renumbered here to match the labels 
			// shown on the Adafruit Motor Shield
            if (driver == Drivers.Driver1 || driver == Drivers.Both)
            {
                // Driver 1 has been modified to use the second pair of PWM outputs from the Netduino
				// which have been made available through the modifications to the motor shield.
				Motor1 = new PWM(Pins.GPIO_PIN_D10);
                Motor1.SetDutyCycle(0);
                Motor2 = new PWM(Pins.GPIO_PIN_D9);
                Motor2.SetDutyCycle(0);
            }
            if (driver == Drivers.Driver2 || driver == Drivers.Both)
            {
                // The Motors have been reversed here, to match the labels printed on the Motor Shield.
				// If you have a different version of the Motor Shield, you need to change these back.
				Motor3 = new PWM(Pins.GPIO_PIN_D6);
                Motor3.SetDutyCycle(0);
                Motor4 = new PWM(Pins.GPIO_PIN_D5);
                Motor4.SetDutyCycle(0);
            }
            MotorLatch = new OutputPort(Pins.GPIO_PIN_D12, true);
            MotorEnable = new OutputPort(Pins.GPIO_PIN_D7, false);
            MotorClk = new OutputPort(Pins.GPIO_PIN_D4, true);
            MotorData = new OutputPort(Pins.GPIO_PIN_D8, true);

            latch_state = 0;
            latch_tx();
        }

        #region IDisposable Members
        public void Dispose()
        {
            latch_state = 0;
            latch_tx();
            if (UsedDriver == Drivers.Driver1 || UsedDriver == Drivers.Both)
            {
                Motor1.Dispose();
                Motor2.Dispose();
            }
            if (UsedDriver == Drivers.Driver2 || UsedDriver == Drivers.Both)
            {
                Motor3.Dispose();
                Motor4.Dispose();
            }
            MotorLatch.Dispose();
            MotorEnable.Dispose();
            MotorClk.Dispose();
            MotorData.Dispose();
        }
        #endregion IDisposable Members

        // Send byte to the 74HCT595 demux
        private void latch_tx()
        {
            MotorLatch.Write(false);
            for (int i = 8; i >= 0; i--)
            {
                MotorClk.Write(false);
                MotorData.Write((latch_state & (1 << i)) > 0);
                MotorClk.Write(true);
            }
            MotorLatch.Write(true);
        }

        /// <summary>
        /// Control a motor; Non-blocking call.  Set speed to 0 to stop.
        /// Frequency might need to be adjusted depending on motor, or to match other PWMs.
        /// </summary>
        /// <param name="which">Which motor to drive.</param>
        /// <param name="speed">Speed, between 0 and 255 (0 to stop, 255 = max speed).</param>
        /// <param name="direction">True = forward, False = backward.</param>
        /// <param name="freq">Frequency in Hz of the PWM controlling the motor.</param>
        public void MotorControl(Motors which, byte speed, bool direction, int freq = 100)
        {
            uint period = (uint)(1000000000D / (double)freq);
            switch (which)
            {
                // All cases have been changed to correctly use the renamed Motor definitions
				// e.g. Motors.M2 uses Motor2, not Motor1A as before.
				// Motors.M3 and Motors.M4 have been reversed, due to the change in defined output pin.
				// This ensures the Shift Register latch is in the correct state that matches the desired
				// output pin, the motor drivers correctly.  
				case Motors.M1: // This motor can have its speed controlled through PWM
                    if (speed == 0) Motor1.SetDutyCycle(0);
                    else 
                    {
                        latch_state = (byte)((latch_state & 0xF3) | (direction ? 4 : 8));
                        latch_tx();
                        Motor1.SetPulse(period, (uint)(period * (double)speed / 255D));
                    }
                    break;

                case Motors.M2: // This motor can have its speed controlled through PWM
                    if (speed == 0) Motor2.SetDutyCycle(0);
                    else
                    {
                        latch_state = (byte)((latch_state & 0xED) | (direction ? 2 : 16));
                        latch_tx();
                        Motor2.SetPulse(period, (uint)(period * (double)speed / 255D));
                    }
                    break;
                case Motors.M3: // This motor can have its speed controlled through PWM
                    if (speed == 0) Motor3.SetDutyCycle(0);
                    else
                    {
                        latch_state = (byte)((latch_state & 0x5F) | (direction ? 32 : 128));
                        latch_tx();
                        Motor3.SetPulse(period, (uint)(period * (double)speed / 255D));
                    }
                    break;
                case Motors.M4: // This motor can have its speed controlled through PWM
                    if (speed == 0) Motor4.SetDutyCycle(0);
                    else
                    {
                        latch_state = (byte)((latch_state & 0xBE) | (direction ? 1 : 64));
                        latch_tx();
                        Motor4.SetPulse(period, (uint)(period * (double)speed / 255D));
                    }
                    break;
            }
        }
    }
}

Netduino 4 DC Motor Example Code:

using System;
using System.Threading;
using Microsoft.SPOT;
using Microsoft.SPOT.Hardware;
using SecretLabs.NETMF.Hardware;
using SecretLabs.NETMF.Hardware.Netduino;
using Robot.Drivers.Adafruit;

namespace DC_Motors
{
    public class Program
    {
        public static void Main()
        {
            // Initialize both drivers on Motor Shield
            Mshield MyMotors = new Mshield(Mshield.Drivers.Both);

            // Blink board LED
            bool ledState = false;
            OutputPort led = new OutputPort(Pins.ONBOARD_LED, ledState);
            
            while (true)
            {
                //LED State is used to control motor direction
				//All motors run in the same direction for one loop,
				//and reverse on the next loop when the LED state has changed.  
				ledState = !ledState;
                led.Write(ledState);

				//Run all 4 Motors using all 4 PWM Outputs of the Netduino.
				//Each motor is run up to full speed, then decreases speed until it stops.
				//The next motor in the sequence is then run.
				//All  4, in sequence, will turn in the same direction.
				//
				//When the code loops, the LED changes state, and the direction will reverse.
				//All 4 motors will then run in the same order, but in the reverse direction.  

                for (int i = 0; i <= 255; i++, Thread.Sleep(5)) MyMotors.MotorControl(Mshield.Motors.M1, (byte)i, ledState);
                // Then decrease it to zero
                for (int i = 255; i >= 0; i--, Thread.Sleep(5)) MyMotors.MotorControl(Mshield.Motors.M1, (byte)i, ledState);
                Thread.Sleep(50);

                for (int i = 0; i <= 255; i++, Thread.Sleep(5)) MyMotors.MotorControl(Mshield.Motors.M2, (byte)i, ledState);
                // Then decrease it to zero
                for (int i = 255; i >= 0; i--, Thread.Sleep(5)) MyMotors.MotorControl(Mshield.Motors.M2, (byte)i, ledState);
                Thread.Sleep(50);

                for (int i = 0; i <= 255; i++, Thread.Sleep(5)) MyMotors.MotorControl(Mshield.Motors.M3, (byte)i, ledState);
                // Then decrease it to zero
                for (int i = 255; i >= 0; i--, Thread.Sleep(5)) MyMotors.MotorControl(Mshield.Motors.M3, (byte)i, ledState);
                Thread.Sleep(50);

                for (int i = 0; i <= 255; i++, Thread.Sleep(5)) MyMotors.MotorControl(Mshield.Motors.M4, (byte)i, ledState);
                // Then decrease it to zero
                for (int i = 255; i >= 0; i--, Thread.Sleep(5)) MyMotors.MotorControl(Mshield.Motors.M4, (byte)i, ledState);
                Thread.Sleep(50);
            }
        }
    }
}
Leave a Comment :, , more...

Netduino & Hacking the Adafruit Industries Arduino Motor Shield

by on Aug.10, 2011, under Electronics, Programming, Technology

Those of you that know me, or follow me on Twitter, may have heard me talking about building electronic something recently.  I’ve been wanting to do something for a while, just didn’t know what.  Then recently, something rare happened.  I had an idea.

The updated Arduino Uno.

For most people, when this happens, they turn to the ever-faithful Arduino as the controller (brains).

I instead turned to the less well-known Netduino.  This board has an almost identical footprint, and more importantly, the same pin-out as the Arduino Uno (an improved & easier to pronounce version of the much-loved Arduino Duemilanove), with one key difference.  It runs the .NET Micro Framework.

Netduino, in all it’s glory.

My idea calls for 4 Bi-directional DC motors.  Fortunately for me, there is a shield out there which can control 4 Bi-directional DC motors – The Arduino Motor Shield from Adafruit Industries.

Unfortunately, I hit a minor limitation of the Netduino.

The Arduino has 6 hardware (8 bit) PWM outputs, which are perfect for motor speed control.  These are on Digital I/O pins 3, 5, 6, 9, 10 & 11.

Adafruit Industries Arduino Motor Shield.

The Netduino on the other hand only has 4 hardware (but 16 bit) PWM outputs.  These are on Digital I/O pins 5, 6, 9 & 10.  As you will notice, they match the inner 4 of the Arduino.  This does make it compatible with many Arduino Shields.  Not here though.

The Adafruit Motor Driver shield uses the PWMs on pins 3, 5, 6 & 11 to control the 4 motors.  The other two, on pins 9 & 10 are used to control 2 Servos.

What I needed was a way to connect pins 5, 6, 9 & 10 from the Netduino, to pins 3, 5, 6 & 11 on the Motor Shield.  Fortunately for me, pins 9 and 10 on the Motor Shield are connected directly to the Servo headers, through no additional components, which makes my hack (solution) possible.

My solution (currently untested by the way) is:

  1. Remove (cut off) Digital I/O pins 3 & 11 on the underside of the Motor Shield.  This will mean pins 3 & 11 of the Netduino become permanently disconnected above the shield.
  2. Jumper pin 9 to pin 11, and pin 10 to pin 3 (or vice versa).  I have just inserted wire into the pin headers on the top side of the Motor Shield.  (I had intentionally not soldered on the Servo headers, as I had no intention of using them.)
  3. If you wish to connect any shield above the motor board, you may need to remove pins 3, 9 10 & 11 from the underside, as there will be jumper wire in the headers.

Alternatively, you could solder jumpers between Digital pins 9 & 11, and 10 & 3 on the underside of the Motor Shield or the through hole points available in front of the pin headers.  This will mean the pin headers on the top side are not obstructed, and additional shields can be connected without modification.  Be aware though that with the pairs of pins joined together, this could cause problems with any shields above that you use, even if you using a part of the shield which does not directly use those pins.  All I can say is – be careful!  If in doubt, don’t do it.

These modifications mean all 6 ‘Arduino’ PWM pins are ‘used’, and not available for any other shield.  All 4 from the Netduino, pins 5, 6, 9 & 10, connect to the 4 DC Motor pins on the Motor Shield, on pins 3, 5, 6 & 11.  Pins 9 & 10 on the Motor shield are in use to jumper to the required pins 3 & 11.  The Adafruit Motor Shield also uses Digital I/O pins 4, 7, 8, & 12 for control.

That leaves Digital pins 0, 1, 2, 13, 14 & 15 available to shield above the motor board.  All 6 Analog Inputs (including I2C on Analog pins 4 & 5) are connected and free for use by other shields.

As I mentioned earlier, this is completely UNTESTED.

I have planned it through fully, but that is still not a guarantee it will work.  I am not responsible for any damage that may occur to anything should you attempt this modification.

I will report back here when it has been tested, and post my results.

1 Comment :, more...

Looking for something?

Use the form below to search the site:

Still not finding what you're looking for? Drop a comment on a post or contact us so we can take care of it!