Micro Maestro info for sentry-gun makers

I have recently purchased a Micro Maestro servo controller to use in an (open source) autonomous sentry gun project i’m making to get me through the European winter. (members.upc.nl/a.kutsenko/guide.htm)

The project has always recommended your servo controllers and they have developed software that runs beautifully with the USB 16 servo controller, but the price was an issue for making little projects. The Micro Maestro has come to the rescue, but we (I) and some others on various forums I’ve come across are having major trouble getting the controller to communicate with the software that co-ordinates the servos with the corresponding movement info from a webcam.

I read in another recent thread on this forum:

“Finally, we will be releasing source code in the next few days, for Windows and Linux, that will allow you to communicate with the device over our custom USB interface, completely bypassing the COM port. Our example code is in C#”

I was wondering if you could let me know (via this thread) when this becomes available. I believe it will be of great interest in getting this controller working with the existing sentry-gun software and will probably result in quite a few more sales of the unit.

I read that you sponsored a maker of these sentry guns in the past, (which resulted in my learning of the existence of pololu) and so would you happen to have any experience with the sentry-projects and if so do you have any other recommendations for us to get the controllers communicating with the software?

cheers n beers,
Ben.

Hello, Ben.

We just released the Pololu USB Software Development Kit which shows how to use native USB to communicate with the Maestro. You can read the announcement for more info.

It looks like you have already integrated a .NET motion detection package in to your software, so integrating our .NET class library for the maestro should not be too hard. I recommend adding the Usc project to your application (and the assembly it depends on, UsbWrapper_Windows/UsbWrapper.dll). There are two example programs, MaestroExample and UscCmd that show how to use Usc to control the Maestro.

Please let me know if you have any questions or comments! I’d be glad to help.

–David Grayson

Thanks Mate, i’ll let you know how I go.

Regards,

Ben.

Hi guys, I’ve had a look through the SDK you put up, and I was wondering if I could request one additional bit of code.

I’m having trouble understanding how to control the SC due to lack of experience.
Could we possibly have the code for the Software (release 091120) under “resources” that operates the controller.

This would be a great working example to help get the software we have at the moment talking with the µMaestro.

Cheers
Ben.

Hi guys,

I posted my last message over the christmas period, so can understand that it could have slipped under the radar, but I was wondering if you were able to help me out in regards to my last post.

Cheers,

Ben.

Hello, Ben.

Sorry for taking a long time to respond.

The source code for UscCmd is available in the Pololu USB SDK. By looking at that and reading the Maestro’s User’s Guide you should be able to figure out everything you need to know to control the Maestro over USB. If you have any specific questions about it, I would be glad to help.

We have not released the source code for the Maestro Control Center. Is that what you wanted?

-David

Yeah, thats exactly what i’m after!

There within is exactly the example I’m after.
I’ve had a look through the example code, and it’s really not clear enough for me to get it to do what I want.
I’m not much of a writer (programmer) i’m more of a manipulator, fiddling with existing code until it works the way I want it to.

I’ve got this, which works with the old Pololu Protocol, but my mission is to now get it working with Maestro.
Once it’s up and working, I’m sure it will help you guys move a few more units.

example code:
Based on PololuServoExample.SerialPortClass in “Controlling Servo Motors, Using the Pololu Servo Controller in .NET”, a Tutorial and Example Program written by Colin Karpfinger

            //*********************************
            //********** POLOLU MODE **********
            //*********************************
            //# OF BYTES: 5 or 6
            //---------------------------------
            //     BYTE 1: Start Byte (0x80) 
            //     BYTE 2: Device type number (0x01 for 8 serial controller)
            //     BYTE 3: Specify Servo Command 
            //             COMMAND 0: Parameters (1 byte)
            //             COMMAND 1: Speed (1 byte)
            //             COMMAND 2: Position, 7 bit (1 byte) 
            //             COMMAND 3: Position, 8 bit (2 bytes)
            //             COMMAND 4: Position, Absolute (2 bytes)
            //             COMMAND 5: Neutral (2 bytes)
            //     BYTE 4: Servo Number 
            //     BYTE 5: Command Data Values (in conjunction with BYTE 3)
            //     BYTE 6: Command Data Values ((in conjunction with BYTE 3)(additional.  Not always necessary)


            //*************************************************************************************
            //FIRST: lets check to make sure our coordinates are within the mechanical range of servos
            //these variables are constants are defined in the beginning of the class.
            if (ServoPos < MIN_ANGLE)
            {
                throw new ArgumentOutOfRangeException("ServoPos", ServoPos, string.Format(
                    "The Servo Position {0} being sent was SMALLER than the MIN_ANGLE {1} Allowed.",
                    ServoPos, MIN_ANGLE));
            }
            else if (ServoPos > MAX_ANGLE)
            {
                throw new ArgumentOutOfRangeException("ServoPos", ServoPos, string.Format(
                    "The Servo Position {0} being sent was LARGER than the MAX_ANGLE {1} Allowed.",
                    ServoPos, MAX_ANGLE));
            }


            //code to convert integer servo position (500-5500) into 2 7 bit bytes.
            int[] binaryArray = new int[13] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
            int[] upperBits = new int[6];
            int upperBitsInt = 0;
            int[] lowerBits = new int[7];
            int lowerBitsInt = 0;
            string[] binarystring = new string[13];
            //2^12 == 4096
            int pow = 4096;

            //MSB to LSB
            for (int i = 0; i < 13; i++)
            {
                if (ServoPos >= pow)
                {
                    binaryArray[i] = 1;
                    ServoPos = ServoPos - pow;
                    binarystring[i] = "1";
                }
                //reduce the power of 2
                pow = pow / 2;
            }
            //LOWER BITS
            //COPY 
            for (int i = 6; i < 12; i++)
            {
                lowerBits[i - 6] = binaryArray[i];
            }
            //convert lowerbits to decimal
            pow = 1;
            for (int i = 6; i >= 0; i--)  //start at 6 and go down so that we start with the LSB (pow = 1) and go up to the MSB
            {
                if (lowerBits[i] == 1)
                {
                    lowerBitsInt = lowerBitsInt + pow;
                }
                pow = pow * 2;
            }
            //UPPER BITS
            //COPY
            for (int i = 0; i < 6; i++)
            {
                upperBits[i] = binaryArray[i];
            }
            //convert upper bits to decimal
            pow = 1;
            for (int i = 5; i >= 0; i--) //start at 6 and go down so that we start with the LSB (pow = 1) and go up to the MSB
            {
                if (upperBits[i] == 1)
                {
                    upperBitsInt = upperBitsInt + pow;
                }
                pow = pow * 2;
            }
            string upperBitsHex = upperBitsInt.ToString("X");
            byte upperBitsByte = byte.Parse(upperBitsHex, System.Globalization.NumberStyles.HexNumber);

            string lowerBitsHex = lowerBitsInt.ToString("X");
            byte lowerBitsByte = byte.Parse(lowerBitsHex, System.Globalization.NumberStyles.HexNumber);

            //************************************************************************************

Hope this helps to see what i’m after.

cheers.
Ben.

It looks like you posted some code for setting the target of a servo. To set the target of a servo on the Maestro using its custom USB interface (instead of the COM port) via the Pololu USB Software Development Kit, you should use the Maestro’s setTarget command:

usc.setTarget(servoNumber, servoTarget);

The prerequisites for successfully running the code above are:

  1. usc should be an instance of the Usc class. See the code in UscCmd or MaestroExample for how to connect to a Maestro and create the Usc object that represents that connection.
  2. servoNumber should be 0, 1, 2, 3, 4, or 5.
  3. servoTarget should be a target pulse width for the servo in units of quarter-microseconds (e.g. 1500 microseconds is represented as 6000 here).

UscCmd does not call setTarget, but MaestroExample does so you can look at its code to see a working example.

The custom USB interface has many advantages over the virtual COM port, but if you don’t want to use the custom USB interface, then you can use Microsoft’s SerialPort class and send the Set Target serial command documented in the Maestro User’s Guide Serial Servo Commands section.

-David

(I’ve cut a lot of crap out of this post.)

I’m still not up and running yet.

I’m going to stick to Pololu serial mode for the moment (neither USB or MiniSSC) as the rest of the software is designed to use this and I’m not sure how hard it would be to try, but i’m pretty sure that re-writing the byte conversion from the Pololu 16 channel Servo Controller to the Micro Maestro will be simpler.

I’m opening a SerialPort, and using the settings:

SerialPort port = new SerialPort(ComPort, BaudRate, Parity.None, 8, StopBits.One);

According to the SKD handbook the serial settings are “PortMode, CRC enable, DeviceNumber, MiniSSCoffset, Timeout, NeverSleep”

SerialPort port = new  SerialPort(ComPort, BaudRate, Parity.None, 8, StopBits.One, PortMode, CRC enable, DeviceNumber, MiniSSCoffset, Timeout, NeverSleep);

can’t be right.

Where would I define the ComPort, BaudRate, etc. or the PortMode, CRC etc.

Thanks for the help guys.

-Ben

code.google.com/p/weaponsgradekavelaars/

I still haven’t got my project working, but I’m making headway.

I believe I have the serial command sending table sorted out, and now have a few more specific questions.

my conversion table now looks like this, modified according to the information in the SDK guide.

        //********************************* 
        //********** MAESTRO MODE ********* 
        //********************************* 
        //# OF BYTES: 5 or 6 
        //--------------------------------- 
        //     BYTE 1: Start Byte (0xAA)
        //     BYTE 2: Device type number (0x12 for Maestro Controller) 
        //     BYTE 3: Specify Servo Command
        //             COMMAND 4: (0x04) Target (2 bytes 1Low/2High) 
        //             COMMAND 7: (0x07) Speed, (2 bytes 1Low/2High) 
        //             COMMAND 9: (0x09) Acceleration (1 byte?)
        //     BYTE 4: Servo Number eg: Servo 1 (0x01? or 0x00) 
        //     BYTE 5: Values from Command (in conjunction with BYTE 3) Low byte
        //     BYTE 6: Command Data Values ((in conjunction with BYTE 3) High byte (if needed)

So, Assuming i’ve understood that correctly, the code i’m using to send the comands looks like this:

        //Set Target: 0xAA, device number, 0x04, servo number, target low bits, target high bits
        port.Write(new byte[] { 
            0xAA, //synch value (always 0xAA)
            0x12, //device ID (0x12 for Maestro servo controller)
            ServoNumberByte, //servo number
            lowerBitsByte //Data Byte 1: This byte is composed of the upper bits of an integer ranging from 500-5500.
                           //             This is so because we are trying to send 13 bits to a controller which can only read 7,
                           //             therefore the upper 6 bits must be sent in one byte, and later we will send the lower 7.
            upperBitsByte, //Data Byte 2: Byte 2 is composed of the 7 remaining bits (from bit 0 up to and including bit 6)
        }, 0, 6);[/code]

It’s not working for me at the moment, and it’s so annoying as i’ve been working on this for about a month now, and I know that if I had a little more C# knowledge, i’d have the project running faster than it will take me to write this post!!!

My issues could also lie here:
The software we’re using is breaking the speed/target values into the nessecary 2, 7 bit bytes. (in Pololu mode)
The code i’m working with was developed for the pololu 16 servo USB controller and it’s resolution.

Do i need to modify the resolution calculation of the target value for the Maestro.

Meaning, if it’s approximately 0.025 degree steps, it’s about 7200 steps per 180 degrees.
Is this the same resolution as the USB 16 servo controller?

(Actually the range that the Maestro Control Centre uses is perfect, if you know what it uses, i’d love to know!)

Here’s the current value converter.

        //code to convert integer servo position (500-5500) into 2 7 bit bytes.
        int[] binaryArray = new int[13] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
        int[] upperBits = new int[6];
        int upperBitsInt = 0;
        int[] lowerBits = new int[7];
        int lowerBitsInt = 0;
        string[] binarystring = new string[13];
        //2^12 == 4096 maximum number of binary combinations
        int pow = 4096;

        //MSB to LSB: working from left to right working out the exact value for the binary conversion.
        for (int i = 0; i < 13; i++)
        {
            if (ServoPos >= pow)
            {
                binaryArray[i] = 1;
                ServoPos = ServoPos - pow;
                binarystring[i] = "1";
            }
            // reduce the power of 2, eg, 2^4, 2^3, 2^2, etc so the computer can decide in the next loop
            // 
            
            pow = pow / 2;
        }
        //LOWER BITS
        //COPY 
        for (int i = 6; i < 12; i++)
        {
            lowerBits[i - 6] = binaryArray[i];
        }
        //convert lowerbits to decimal
        pow = 1;
        for (int i = 6; i >= 0; i--)  //start at 6 and go down so that we start with the LSB (pow = 1) and go up to the MSB
        {
            if (lowerBits[i] == 1)
            {
                lowerBitsInt = lowerBitsInt + pow;
            }
            pow = pow * 2;
        }
        //UPPER BITS
        //COPY
        for (int i = 0; i < 6; i++)
        {
            upperBits[i] = binaryArray[i];
        }
        //convert upper bits to decimal
        pow = 1;
        for (int i = 5; i >= 0; i--) //start at 6 and go down so that we start with the LSB (pow = 1) and go up to the MSB
        {
            if (upperBits[i] == 1)
            {
                upperBitsInt = upperBitsInt + pow;
            }
            pow = pow * 2;
        }[/code]

From this information, can you see where my problem lies. If the code above doesn’t have any major issues, I know I need to look else where.

For the moment it’s not throwing any errors, it’s just not reacting.

-Ben.

working a little further forward, have another question…

In regards to Acceleation
A value of 0 means no limit (0x00 in hex?) but 0x01 is the most limited.
So a value of 0xFE (254) would be about 99% limit (faster)?

            //Set Acceleration: : 0xAA, device number, 0x09, servo number, acceleration
            port.Write(new byte[] { 
                0xAA, //synch value (always 0xAA)
                0x12, //device ID (0x12 for Maestro servo controller)
                0x09, //servo command (setting Acceleration is command 9)
                ServoNumberByte, //servo number
                AccelerationByte // what are some examples I could add here?
            }, 0, 5);

Hi Ben,
Have you gotten any serial commands to work? I suggest you start with the specific examples that are given explicitly in hex in the User’s Guide, make sure they work, then go on to write your code.

Have you configured your Maestro to be in USB dual port or USB chained mode, or are you using some other serial adapter? Without that, it has no chance of working.

I have a lot of trouble following your code, but if it works, it is probably the least efficient and most confusing way possible to get those two binary bytes! The example we give in the manual is already written out for you in C. All you need is this:

low = target & 0x7F;
high = (target >> 7) & 0x7F;

The target is specified in 0.25us resolution. The safe range for servos is generally 1-2ms, which would be 4000-8000 in the numerical target values.

Your understanding of acceleration is correct. You can get a sense for how it works by playing around in the control center.

Finally, I wonder why you are using the expanded “Pololu protocol”. If you are just controlling a single Maestro on that serial line, the “Compact protocol” will save you two bytes.

-Paul

I opened C# for the first time a month or two ago, and it’s the first time i’ve attempted any code since a bit of HTML in highschool. (10 years ago thereabouts.)

I’m trying to make software work, that has already been written for the Pololu USB 16 channel controller.
If i had a little more C# knowledge I’d have it running in 2 minutes, but as I don’t all I can do is read what code is there, and compare it to the notes in the SDK and try to get it working. I’m really in no position to start writing my own code, I’d struggle with “Hello World”.

Regardless, hours and hours later I think i’m pretty close now. I’ve modified the collin karpfinger example, and it’s building without any errors.

The values for the low/high bytes are sent from a trackbar and then sent to the controller with a button.
Does that small piece of C you sent me take a single integer and change it into a 2 7 bit bytes?
If so i’m over the moon!

A friend once told me “Ben, you can find the hardest way to do anything”.
To date, she’s been pretty spot on.

How would that C code look in C#? any different?

Ben,
It makes your two bytes from a single integer. I guess I should have said that the code is exactly the same in C, C#, java, ruby, … pretty much any modern language uses the same set of basic operators. Do a Google search for “C binary operators” if you want to understand exactly what that code does.

I still recommend that you start with the examples given in the manual, so that you can be sure your Maestro is actually configured correctly! Also, one of the great things about using Visual Studio with C# is that you can very easily step through your code and see exactly what each line is doing. Make sure that you take advantage of that if you get confused.

Good luck,
-Paul

Thanks mate.

I’ll let you know if I have any success.

-Ben.