Simple Linux program using Mini SSC protocol

Hi,

I needed to move servos in Linux and created this very simple starter application. It works well and is built on the standard libraries (iostream, fstream and ctime). It should give you some ideas and can be expanded to use the other protocols. It also has a wait(sec) function, which I have to admit I found somewhere on the internet. (but it’s trick!) It’s a demo program for two servos on the Micro Maestro 6. Note: this is a C++ application, so compile with g++. I have tested it on a couple of desktops running Ubuntu, and it also runs on the Gumstix Overo (ARM9) after cross-compiling. Using the Mini SSC protocol simplifies basic servo movement control.

Hope it helps…
Mark

/*
 * micro6.cpp
 *
 *  Created on: Jul 3, 2010
 *      Author: mwille
 *
 * Description: Sample program using simple filestream object and 
 *              Mini SSC protocol.
 */

#include <iostream>
#include <fstream>
#include <ctime>

using namespace std;

#define USBDEV "/dev/ttyACM0"


void wait ( int seconds )
{
  clock_t endwait;
  endwait = clock () + seconds * CLOCKS_PER_SEC ;
  while (clock() < endwait) {}
}

int main(void)
{
	int i,j;

	//small array holds mini ssc command set- (xFF, servo id, servo position)
	int SetTarget[3]= {255,0,0};        //(should probably be char array technically).

	fstream micro6;     //instantiate fstream object

	micro6.open(USBDEV,ios::out); //open for output
	if(micro6.fail())
	{
		cout << "Did not open Micro6!" << endl;
		return 0;
	}else
	{
		cout << "Opened Micro6 Device!" << endl;
	}

    // first loop controls servo 0
	for(j=0;j<3;j++)
	{
		SetTarget[1] = 0;

		cout << "Sending Position Data to Servo 0" << endl;

		switch(j)   // change servo 0 position each iteration
		{
		case 0: SetTarget[2] = 0;
				cout << SetTarget[0]<< " " << SetTarget[1] << " " << SetTarget[2] << endl;
				break;
		case 1: SetTarget[2] = 127;
				cout << SetTarget[0]<< " " << SetTarget[1] << " " << SetTarget[2] << endl;
				break;
		case 2: SetTarget[2] = 254;
				cout << SetTarget[0]<< " " << SetTarget[1] << " " << SetTarget[2] << endl;
				break;
		}

		//sending commands - (loop for sending each value)
		for(i=0;i<3;i++)          
		{
			micro6.put(SetTarget[i]);
		}

		micro6.flush();  //**** NOTE: very important to flush(push) command set from buffer.

		wait(1);

		SetTarget[1] = 1; //change to servo 1

		cout << "Sending Position Data to Servo 1" << endl;

		switch(j)
		{
			case 0: SetTarget[2]= 254;
					cout << SetTarget[0]<< " " << SetTarget[1] << " " << SetTarget[2] << endl;
					break;
			case 1: SetTarget[2]= 127;
					cout << SetTarget[0]<< " " << SetTarget[1] << " " << SetTarget[2] << endl;
					break;
			case 2: SetTarget[2]= 0;
					cout << SetTarget[0]<< " " << SetTarget[1] << " " << SetTarget[2] << endl;
					break;
		}

		//sending commands
		for(i=0;i<3;i++)
		{
			micro6.put(SetTarget[i]);
		}

		micro6.flush();

		wait(1);

		}
	}
	cout << "Closing the Micro6..." << endl;
	//closing micro6
	micro6.close();  //**** NOTE: must close the filestream when done!

	cout << "End of program..." << endl;

	return 0;
}

Hello,

Thanks for posting this example.

One thing I noticed was that your wait() function seems really bad: It will be using 100% of the available processor time while it is waiting, and it specifically waits until it has used n seconds of processor time - if I understand it correctly. Why not use the built in sleep() function, which already does exactly what you want? You could also use usleep() to get more precision.

-Paul

Yes - an excellent suggestion. I believe that it is widely supported in unistd.h This was just a test program to prove that stream functions could be used to provide communications with the Maestro. I am not using the wait function in my “real” code.
Here is the include and prototype info:
#include <unistd.h>
unsigned int sleep(unsigned int seconds);

Thanks, Paul

Hey,

Just a quick update. If you execute this program without the Micro6 connected, it will still run. That is an error. It should exit out saying it can’t open the USBDEV. However, as it is written above, if the M6 is not connected, it will open an output file anyway in the /dev folder and send the data into that file. My bad : ) I think you should handle that by checking to see if the file exists (the M6) and then exit if it doesn’t. The C++ code for checking for a file’s (M6) existence would look something like:

micro6.open(USBDEV, ios::in); // actually checking to see if we can open it for an input operation

if (micro6.fail()) //you got to love C++ objects/default methods
{
cout << “No Micro6 device found. Check and see if it is connected…” <<endl;
exit (0);
} else
{
micro6.close(); //closing input handle
cout << “Micro6 found…opening handle for output…” << endl;
micro6.open(USBDEV, ios::out); //open output handle
}