Adafruit Motor Shield together with the Fez Cerbuino Bee

Hello,

Recently i brought the Fez Cerbuino Bee together stepper motor’s to build myself a simple CNC machine.
I like to use the Adafruit Motor shield with the Fez Cerbuino Bee and i found some code for the Fez Domino here: http://www.tinyclr.com/forum/topic?id=1848 and a good starting point to use.
I have been looking to the pen naming and It looks like that only those need to be changed, i think. What i also find was that there where different pin’s having PWM possibilities, not sure of that is needed or not, while using the stepper motor’s.

Has someone already ported this lib to the Cerbuino and would it be easy to integrate that timer3 lib that someone showed on the forum?

Thanks

I do not remember seeing this ported on cerbuino but it shouldn’t be that hard. Give it a try and let us know if you face any obstacles.

NielsNL2, I modified the adafruit motor shield to function with a Panda II as described in this thread, http://www.tinyclr.com/forum/topic?id=10481 .

I’m sure there are some differences between my mods for the Panda II and what would be needed for the Cerbuino Bee, but it may give you a head start. Let me know if you want any more detail. I’ve been thinking about migrating this and other projects to the cerbuino, but still need to pin down what changes are needed.

@ idafez: Thanks i did saw your post indeed. For now i’m trying to use the default configuration of that board. It is only mend to doing some test, later i want to switch to the Grbl shield from synthetos.com. But that board is not yet available, and i want to just test my skills before i buy that shield. When i’m not happy about it, i can alway buy the Arduino with it.

@ gus, Although i played with C# and NetMF some time ago, together with the FEZmini and FEZ domino, my knowledge is very pore.
Trying to understand the getting started doc’s but i’m lost between the different version of NetMF and how i should do it in Cerbunio.
I’m already stuck on finding the right port definitions etc.

When someone else want to give me a direction how to start. then i’m very happy. Because i’m a bit lost now.
A small demo that uses the PWM, digital port’s etc. together with the Cerbunio would be nice. Because that is the part where i’m lost atm.

thanks

Thank you very much. Sadly i read most of them already before. But somehow i was not able to find the right answer to connect those doc’s to my FEZ Cebruino.
Somehow i find what is was looking for and now it was a peace of cake.
I made changes to it as well. Now the lib does only work for stepper motors.
Sadly my stepper motor did not want to rotate yet. But i think thats because the power supply.

using System;
using Microsoft.SPOT;
using System.Threading;
using Microsoft.SPOT.Hardware;
using GHI.OSHW.Hardware;
//using GHI.Premium.Hardware;

//using GHIElectronics.NETMF.FEZ;

namespace Mshield
{
    public class Program
    {
        public static void Main()
        {
            // Initialize both driver on Motor Shield
            Mshield MyMotors = new Mshield(Mshield.Drivers.Stepper,Mshield.Drivers.None);

            // Create servo motors (not used in this example)
    //        pin.PWM servo1 = new pin.PWM(MyMotors.Servo1);
    //        PWM servo2 = new PWM(MyMotors.Servo2);

            // Blink board LED
            bool ledState = false;
            OutputPort led = new OutputPort((Cpu.Pin)FEZCerbuino.Pin.Digital.LED1, ledState);

            while (true)
            {
                ledState = !ledState;
                led.Write(ledState);

                // We have one stepper connected on driver1 (M0/M1)
                // Have it run 5s in "Hi-Torque" (High power, high speed, high power usage...)
                MyMotors.StepperMove(Mshield.Steppers.S1,  0, true, 0, 5000, false);
                Thread.Sleep(1000);

                // Then 5s in the other direction
                MyMotors.StepperMove(Mshield.Steppers.S1,  0, false, 0, 5000, false);
                Thread.Sleep(1000);
            }
        }

    }

    /*  Adafruit motor "Shield v1.0" / See: <a href="http://www.ladyada.net/make/mshield/index.html" target="_blank">http://www.ladyada.net/make/mshield/index.html</a>
    *  Driver v0.1a - Copyright 2011 Nicolas Ricquemaque
    * 
    *  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
    *
    *      <a href="http://www.apache.org/licenses/LICENSE-2.0" target="_blank">http://www.apache.org/licenses/LICENSE-2.0</a>
    *
    *  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. 
    *
    * ------------------------------------------------------------------------
    * 
    *  The Adafruit Motor Shield can drive up to four motors (including speed and direction)
    *  or max 2 steppers motors (each stepper using one of the 2 shield drivers, instead of 2 motors).
    *  Two servo connectors are available on the shield, directly from pins DI9 and DI10 (no control
    *  of servos is made by the board or by this driver, however there use is simple, just look at the
    *  beginner's guide).
    *  
    *  Due of timing constraints, no micro-stepping is performed
    *  (that would need RLP programming which we are not doing here)
    *  The handling of stepper motors is blocking untill the action requested is completed
    *  However, this is not the case for simple motors: just set a state, and the motor will keep it.
    *  
    *  Please report bugs to f1iqf (at) hotmail (dot) com
    *  
    */

    public class Mshield : IDisposable
    {
        public enum Drivers : byte { None = 0, Stepper}
        public enum Steppers : byte { S1 = 0, S2 }
        public enum BipolarStepping : byte { WaveDrive = 0, HiTorque, HalfStep }
        public BipolarStepping mode = BipolarStepping.WaveDrive;
        /// 
        /// On board Servo1 connector, for external reference only
        /// 
        public PWM Servo1 = new PWM(FEZCerbuino.Pin.PWM.D9, 20000, 1500, PWM.ScaleFactor.Microseconds, false);//PWM( FEZCerbuino.Pin.PWM.D9,);
        /// 
        /// On board Servo2 connector, for external reference only
        /// 
        public PWM Servo2 = new PWM(FEZCerbuino.Pin.PWM.D10, 20000, 1500, PWM.ScaleFactor.Microseconds, false);//(PWM.Pin)FEZ_Pin.PWM.Di10;

        private Drivers[] UsedDriver = new Drivers[] {Drivers.None,Drivers.None};
        private OutputPort Motor1A, Motor1B; // Enable L293D driver #1a and #1b
        private OutputPort Motor2A, Motor2B; // Enable L293D driver #1a and #1b
        private OutputPort MotorLatch, MotorEnable, MotorClk, MotorData; // 74HCT595 commands
        byte latch_state; // Actual 74HCT595 output state

        // Steper sequences for each stepper. Have a look here : <a href="http://www.stepperworld.com/Tutorials/pgBipolarTutorial.htm" target="_blank">http://www.stepperworld.com/Tutorials/pgBipolarTutorial.htm</a>
        private byte[][] BipolarSteppingWaveDrive = new byte[][] {  new byte [] {4,2,8,16},
                                                                    new byte [] {1,128,64,32}};
        private byte[][] BipolarSteppingHiTorque = new byte[][] {   new byte [] {20,24,10,6},
                                                                    new byte [] {129,192,96,33}};
        private byte[][] BipolarSteppingHalfStep = new byte[][] {   new byte [] {4,20,16,24,8,10,2,6},
                                                                    new byte [] {1,129,128,192,64,96,32,33}};
        private byte[] lastpos = new byte[] { 0, 0 };
        /// 
        /// Constructor
        /// 
        ///  Which driver to initialize : 1=driver 1, 2=driver 2, 3=both
        public Mshield(Drivers driver1 = Drivers.None, Drivers driver2 = Drivers.None)
        {
            UsedDriver[0] = driver1;
            UsedDriver[1] = driver2;
            if (driver1 != Drivers.None)
            {
                Motor1A = new OutputPort((Cpu.Pin)FEZCerbuino.Pin.Digital.D11, false);
                Motor1B = new OutputPort((Cpu.Pin)FEZCerbuino.Pin.Digital.D3, false);
            }
            if (driver2 != Drivers.None)
            {
                Motor2A = new OutputPort((Cpu.Pin)FEZCerbuino.Pin.Digital.D5, false);
                Motor2B = new OutputPort((Cpu.Pin)FEZCerbuino.Pin.Digital.D6, false);
     /*           Motor2A = new PWM(FEZCerbuino.Pin.PWM.D5, 20000, 1500, PWM.ScaleFactor.Microseconds, false);//new PWM((PWM.Pin)FEZ_Pin.PWM.Di5);
                Motor2A.Stop();// (false);
                Motor2B = new PWM(FEZCerbuino.Pin.PWM.D6, 20000, 1500, PWM.ScaleFactor.Microseconds, false);//new PWM((PWM.Pin)FEZ_Pin.PWM.Di6);
                Motor2B.Stop();// Set(false);*/
            }
            MotorLatch  = new OutputPort((Cpu.Pin)FEZCerbuino.Pin.Digital.D12, true);
            MotorEnable = new OutputPort((Cpu.Pin)FEZCerbuino.Pin.Digital.D7, false);
            MotorClk = new OutputPort((Cpu.Pin)FEZCerbuino.Pin.Digital.D4, true);
            MotorData = new OutputPort((Cpu.Pin)FEZCerbuino.Pin.Digital.D8, true);

            latch_state = 0;
            latch_tx();
        }

        #region IDisposable Members
        public void Dispose()
        {
            latch_state = 0;
            latch_tx();

            if (UsedDriver[0] != Drivers.None)
            {
                Motor1A.Dispose();
                Motor1B.Dispose();
            }
            if (UsedDriver[1] != Drivers.None)
            {
                Motor2A.Dispose();
                Motor2B.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);
    }

        /// 
        /// Move a stepper. Only one param between steps and msec but be set different from 0.
        /// Blocking call.
        /// 
        /// Which stepper to drive
        /// Stepping mode
        /// Number of ms between each step (0 : no pause=max speed)
        /// True = foward, False = backward
        /// If non-zero, number of steps to run
        /// If non-zero, number of ms to run
        /// True if stepper shall stay energized when task done
        /// Number of steps ran
        public uint StepperMove(Steppers which, int speed, bool direction, int steps, int msec, bool hold = false)
        {
            if (UsedDriver[(byte)which] == Drivers.None) return 0;
 
            // Find where we stopped last time
            byte last = lastpos[(byte)which];
            int pos ;
            uint step = 0;
            byte[] MotorSteps = BipolarSteppingWaveDrive[(byte)which]; // Get the stepping pattern
            
            if (mode == BipolarStepping.HiTorque) MotorSteps = BipolarSteppingHiTorque[(byte)which];
            if (mode == BipolarStepping.HalfStep) MotorSteps = BipolarSteppingHalfStep[(byte)which];

            if (which == 0)
                last = (byte)(latch_state & 0x1E);
            else
                last = (byte)(latch_state & 0xE1);
            for (pos = 0; pos < MotorSteps.Length; pos++)
            {
                if (MotorSteps[pos] == last) break;
            }
            if (pos == MotorSteps.Length) pos = 0;

            if (which == 0) { 
                Motor1A.Write(true); Motor1B.Write(true);
            } else {
                Motor2A.Write(true); Motor2B.Write(true);
            }

            byte Mask = (byte)((which == 0) ? 0xE1 : 0x1E);

            if (steps > 0) // user chose to move from a number of steps
            {
                for (; step < steps; step++)
                {
                    if (direction) pos = (pos + 1) % MotorSteps.Length;
                    else if (--pos < 0) pos = MotorSteps.Length - 1;
                    latch_state = (byte)((latch_state & Mask) | MotorSteps[pos]);
                    latch_tx();
                    if (speed > 0) Thread.Sleep(speed);
                }

            }
            else // So no number of steps, the user must have given a time to run
            {
                long endtime = DateTime.Now.Ticks + msec * TimeSpan.TicksPerMillisecond;
                for (; DateTime.Now.Ticks < endtime; step++)
                {
                    if (direction) pos = (pos + 1) % MotorSteps.Length;
                    else if (--pos < 0) pos = MotorSteps.Length - 1;
                    latch_state = (byte)((latch_state & Mask) | MotorSteps[pos]);
                    latch_tx();
                    if (speed > 0) Thread.Sleep(speed);
                }
            }

            if (!hold) // Remove energy from stepper
            {
                if (which == 0)
                {
                    Motor1A.Write(false); Motor1B.Write(false);                }
                else
                {
                    Motor2A.Write(false); Motor2B.Write(false);
                }
            }

            return step;
        }
    }
}

NielsNL2,
Thanks for your post. I tried your code with my Adafruit Motor Shield and Cerbuino with no luck, my stepper motor is also not rotating. Did you ever figure out what was wrong with yours?
thanks

Nope,

So it was not my board. I decided to drop it in favor for the gbrlshield board much simpler to control and does have 3 stepper controllers on-board.

I hope someone else can find what was wrong with the above code. But it can be a timing issue or so. Or i choose the wrong pin’s to control the latch.

I only know i burnt on of my steppers with it.

Good luck.