Netduino Driver for SMC05A

Good New Year Everyone,

I’ve been working with a Netduino and the SMC05A and couldn’t find a driver for it.
I did’t change anything on the SMC05A so this is the way mine worked out of the box.
I am going to use this to drive a Tamiya 70168.

/// 
/// <summary>
/// This class is intended to allow a Netduino to drive a 
/// Pololu Low-Voltage Dual Serial Motor Controller (DSMC) Pololu item #: 120  (SMC05A)
/// This class requires a reference to Microsoft.SPOT.Hardware.SerialPort as part of the project
/// </summary>
/// <remarks>
/// The SMC50A holds state.  When a motor is given a direction and speed the settings hold
/// until it recieves another set of parameters. 
/// </remarks>
/// 
/// 

using System;
using System.Threading;
using System.IO.Ports;
using System.Text;
using Microsoft.SPOT;
using SecretLabs.NETMF.Hardware.Netduino;

namespace MotorTest
{
    class DualSerialMotorController
    {
        /// <summary>
        /// The four-byte motor controller command
        /// byte 1: Start Byte - Always 0x80 (128) to signify the beginning of a command
        /// byte 2: Device Type - This should always be 0x00 for commands sent to the SMC05a
        /// byte 3: Motor and Direction - This byte has three parts
        ///     bit 0 - Specifies the direction of the motor 1 = forward, 0 = backwards
        ///     bits 1 - 6 - Specifies the motor number.  All motors respond to 0 and 1 if in dual-motor mode
        ///     bit 7 - Must always be 0
        ///     To calculate byte 3 (motor number x 2) + ( zero for forward or one for reverse)
        /// byte 4: Motor Speed - The most significant bit (MSB) must always be 0.  Range 0x00 - 0x7F
        ///     0x00 = STOP
        ///     0x7F = Full Speed
        /// </summary>
        SerialPort serialPort;

        static byte[] stopMotor0 = new byte[4] { 0x80, 0, 0x00, 0 };        // Stop Motor Zero
        static byte[] stopMotor1 = new byte[4] { 0x80, 0, 0x02, 0 };        // Stop Motor One

        static byte[] forwardMotor0 = new byte[4] { 0x80, 0, 0x00, 0 };     // Forward speed passed by caller
        static byte[] forwardMotor1 = new byte[4] { 0x80, 0, 0x02, 0 };     // Forward speed passed by caller

        static byte[] reverseMotor0 = new byte[4] { 0x80, 0, 0x01, 0 };     // Reverse speed passed by caller
        static byte[] reverseMotor1 = new byte[4] { 0x80, 0, 0x03, 0 };     // Reverse speed passed by caller

        public DualSerialMotorController(string portName = SerialPorts.COM1, int baudRate = 9600, Parity parity = Parity.None, int dataBits = 8, StopBits stopBits = StopBits.One)
        {
            serialPort = new SerialPort(portName, baudRate);
            serialPort.Open();
        }

        // Motor Zero forward
        public void Forward0(int speed)
        {
            forwardMotor0[3] = (byte)speed;
            serialPort.Write(forwardMotor0, 0, 4);
        }

        // Motor One forward
        public void Forward1(int speed)
        {
            forwardMotor1[3] = (byte)speed;
            serialPort.Write(forwardMotor1, 0, 4);
        }

        // Motor Zero and One forward
        public void ForwardAll(int speed)
        {
            forwardMotor0[3] = (byte)speed;
            forwardMotor1[3] = (byte)speed;
            serialPort.Write(forwardMotor0, 0, 4);
            serialPort.Write(forwardMotor1, 0, 4);
        }

        // Motor Zero backward
        public void Reverse0(int speed)
        {
            reverseMotor0[3] = (byte)speed;
            serialPort.Write(reverseMotor0, 0, 4);
        }

        // Motor One backward
        public void Reverse1(int speed)
        {
            reverseMotor1[3] = (byte)speed;
            serialPort.Write(reverseMotor1, 0, 4);
        }

        // Motor Zero and One backward
        public void ReverseAll(int speed)
        {
            reverseMotor0[3] = (byte)speed;
            reverseMotor1[3] = (byte)speed;
            serialPort.Write(reverseMotor0, 0, 4);
            serialPort.Write(reverseMotor1, 0, 4);
        }

        // Motor Zero forward and One backward
        public void SpinLeft(int speed)
        {
            forwardMotor0[3] = (byte)speed;
            reverseMotor1[3] = (byte)speed;
            serialPort.Write(forwardMotor0, 0, 4);
            serialPort.Write(reverseMotor1, 0, 4);
        }

        // Motor Zero backward and One forward
        public void SpinRight(int speed)
        {
            forwardMotor1[3] = (byte)speed;
            reverseMotor0[3] = (byte)speed;
            serialPort.Write(forwardMotor1, 0, 4);
            serialPort.Write(reverseMotor0, 0, 4);
        }

        // Stop both motors
        public void Stop()
        {
            serialPort.Write(stopMotor0, 0, 4);
            serialPort.Write(stopMotor1, 0, 4);
        }

    }
}

For right now all the little guys does is a test pattern when you turn him on.

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

namespace MotorTest
{
    public class Program
    {
        public static void Main()
        {
            Thread.Sleep(500);
            DualSerialMotorController dsmc = new DualSerialMotorController();
            OutputPort led = new OutputPort(Pins.ONBOARD_LED, false);
            
            led.Write(true);               // turn on the LED

            dsmc.ForwardAll(127);          // Tell the controller to spin motor Zero forward and motor One forward
            Thread.Sleep(1000);
            dsmc.Stop();                   // All stop

            dsmc.ReverseAll(127);          // Tell the controller to spin motor Zero backward and motor One backward
            Thread.Sleep(1000);
            dsmc.Stop();                   // All stop

            dsmc.SpinLeft(127);             // Tell the controller to spin the robot left
            Thread.Sleep(1000);
            dsmc.Stop();                    // All stop

            dsmc.SpinRight(127);            // Tell the controller to spin the robot left
            Thread.Sleep(1000);
            dsmc.Stop();                    // All stop

            led.Write(false);               // turn off the LED
        }

    }
}

I think he needs to “see” next.

Cheers
PenZenMaster

1 Like

Thanks for posting this!

Just a few suggestions:

You should get rid of the parity, dataBits, and stopBits arguments to the constructor. Each of these arguments has only one correct value. Allowing the user to choose a different value will not do any good.

The “serialPort” should be an instance field rather than a static field so when you make multiple instances of the class it will work properly and let you control multiple DSMCs. I’m not sure how multi-threading works on the Netduino, but you might need to make the byte arrays be instance fields (or local variables) to avoid the situation where different instances are modifying those arrays and messing each other up.

This code is unnecessarily inefficient and complicated:

forwardMotor1[3] = Byte.Parse(speed.ToString());

You can replace it with:

forwardMotor1[3] = (byte)speed;

Feel free to use the “Edit” button to edit your post above with improved code!

–David

Thanks for the code review David.
I’ll hook up my Netduino tonight and refactor the post.

Posted a slightly re-factored driver.
Changed serialPort from static to an instance.
Cleaned up forwardMotor1[3] = Byte.Parse(speed.ToString()); to use forwardMotor1[3] = (byte)speed;
I’m going to hold off on changing the byte arrays until I have more than one controller to test with.

I will continue to update this as the project “rolls” along.

Cheers
PenZenMaster