Sunday, January 4, 2009

iRobot C Sharp Create interface

I've found this great interface for the iRobot Create.
Here is the link

CreateOI interface


I've spent tonight extending the interface by adding a command that was left out that allows the iRobot Create to have each of its wheels controlled independently instead of dealing with having to figure out the weird arch system.

So first download the code from sourceforge, it will unzip into a folder named CreateOI, with CreateOI_Examples, iRobot, Kevin_Logging, and Visualizer as subfolders.
In order to add a command to the irobot.dll interface we need to go down a few levels to iRobot\iRobot folder

Now open irobot.csproj in Visual Studio.

The dll is broken down very hierarchically and is meant to work for both the roomba and the irobot create. In order to add my DirectDrive function I went to the Types.cs
under the CreateOI folder and added
public const byte DriveDirect = 145;
after
public const byte Pause_Resume_Stream = 145;

Then under Create.cs under Chasis folder

I added my DriveDirect function which is as following

///
/// This command lets you control the forward and backward
/// motion of Create’s drive wheels independently. It takes
/// four data bytes, which are interpreted as two 16-bit signed
/// values using two’s complement. The first two bytes specify
/// the velocity of the right wheel in millimeters per second
/// (mm/s), with the high byte sent first. The next two bytes
/// specify the velocity of the left wheel, in the same format.
/// A positive velocity makes that wheel drive forward, while a
/// negative velocity makes it drive backward.
/// • Serial sequence: [145] [Right velocity high byte]
/// [Right velocity low byte] [Left velocity high byte]
/// [Left velocity low byte]
/// • Available in modes: Safe or Full
/// • Changes mode to: No Change
/// • Drive Direct data byte 1: Right wheel velocity
/// (-500 – 500 mm/s)
/// • Drive Direct data byte 1: Left wheel velocity
/// (-500 – 500 mm/s)
///

///
///
///
public bool DriveDirect(Int16 leftVelocity, Int16 rightVelocity)
{
this.ErrorText = "";

bool bSafe = this.Mode == OI_Mode.Safe;
bool bFull = this.Mode == OI_Mode.Full;
bool bError = (!bSafe) & (!bFull);

//Push back at the user
if (bError)
{
throw new RoombaException("Roomba must be in Safe or Full mode before running Calling the Drive Function: ");
}

//Sample from the SCI Spec:
//Serial sequence: [145] [Right velocity high byte][Right velocity low byte] [Left velocity high byte][Left velocity low byte]


//divide up leftVelocity & rightVelocity into 2 bytes each
byte leftVelocityHi = (byte)( leftVelocity >> 8);
byte leftVelocityLo = (byte)( leftVelocity & 255);

byte rightVelocityHi = (byte)(rightVelocity >> 8);
byte rightVelocityLo = (byte)(rightVelocity & 255);

bool bSuccess = false;

List lSend = new List();
lSend.Add(CreateOI.OpCode.DriveDirect);
lSend.Add(rightVelocityHi);
lSend.Add(rightVelocityLo);
lSend.Add(leftVelocityHi);
lSend.Add(leftVelocityLo);

string sDebugSend = "[" + lSend[0].ToString() + "][" + lSend[1].ToString() + "][" + lSend[2].ToString() + "][" + lSend[3].ToString() + "][" + lSend[4].ToString() + "]";

try
{
Log.This("Drive Action: " + sDebugSend, c_sCommonChassis, this.Log_OICommands);

this.IO.RtsEnable = false;
this.IO.Write(lSend.ToArray(), 0, lSend.Count);
//this.Macro.SetAction("DRIVE\t" + sDebugSend);

this.p_leftVelocity = leftVelocity;
this.p_rightVelocity = rightVelocity;
//this.p_rRadius = rAngle; //may need to add equivalent for this class

bSuccess = true;
Log.This("Drive Action Success " + bSuccess.ToString() + " leftVelocity: " + this.p_leftVelocity.ToString() + " rightVelocity: " + this.p_rightVelocity.ToString(), c_sCommonChassis, this.Log_OICommands);
}
catch (Exception ex)
{
Log.This("Drive Action Fail: " + ex.Message, c_sCommonChassis, this.Log_OICommands);
}

return bSuccess;
}


Then save all changes and goto the iRobot project descriptor at the very top of the Solution Explorer, right click it and click rebuild. The iRobot.dll will be located in
CreateOI\CreateOI\iRobot\iRobot\bin\Release

add this .dll under References in solution explorer for whatever project you may have and it will allow you to use the DirectDrive function I implemented

Sunday, September 28, 2008

Sidewinder Force Feedback Pro Windows XP

For those looking for a solution to getting the force feedback 2 joystick working in XP take a look here:

Force Feedback Article

However this brief reminder is that he old Force Feedback Pro joysticks do work under XP and they work pretty well. Only problem is that the forces are too strong. This makes them pretty hard to use under most situations except if you are doing the programming yourself. In which case, download the newest version of Visual C# Express Edition, or for that matter any of the visual languages and download the newest Microsoft DirectX SDK. I used 2006.

Go down a few levels and you'll find a cool utility that allows you to test out all the forces on the joystick.
EX:
C:\Program Files\Microsoft DirectX SDK (February 2006)\Samples\Managed\DirectInput\Bin\x86\csFeedback

You can also go up and edit the programs to your hearts desire. If you are using anything other than a joystick, you may have problems and will have to set the number of axes to 1 instead of two, but this is a well known problem.

Tuesday, July 29, 2008

SHARP 2Y3A001 F Arduino filtering

I'm using the Sharp 5 beam sensor in a project of mine and I was having trouble with the measurements varying a lot. Stupid me, after checking it out with my Parallax USB Oscilloscope I realized that the input voltage to the sensor wasn't right, I simply didn't have it plugged in right. That stabilized the output and my mean analog readings were close, but I felt that taking the mean wasn't necessarily the best way to go about it, because if you look at the output of the sensor under an oscilloscope it spikes then oscillates, so if you simply do an average of a lot of readings that initial spike will affect your output. I figured that the best value would come from the mode and not from the mean. A mean of the top two frequencies would also work, but for simplicity, I"m just using one. Here is the code I used on the arduino platform. (Essentially just C)

I took 50 samples, put them in an array, applied an insertion sort, and then searched through the list once finding the highest mode. Then I printed out the average mode and min and max to the screen. I also made use of a printFloat function I found floating on the net. Notice I'm also only reading one out of the 5 beams at the moment, I wanted to get the algorithm to work first before changing, but its just a matter of uncommenting a few lines and making some changes. The output from the sensor is not rock solid when you place it down and aim it at an object.


// printFloat prints out the float 'value' rounded to 'places' places after the decimal point
void printFloat(float value, int places) {
// this is used to cast digits
int digit;
float tens = 0.1;
int tenscount = 0;
int i;
float tempfloat = value;

// make sure we round properly. this could use pow from , but doesn't seem worth the import
// if this rounding step isn't here, the value 54.321 prints as 54.3209

// calculate rounding term d: 0.5/pow(10,places)
float d = 0.5;
if (value < 0)
d *= -1.0;
// divide by ten for each decimal place
for (i = 0; i < places; i++)
d/= 10.0;
// this small addition, combined with truncation will round our values properly
tempfloat += d;

// first get value tens to be the large power of ten less than value
// tenscount isn't necessary but it would be useful if you wanted to know after this how many chars the number will take

if (value < 0)
tempfloat *= -1.0;
while ((tens * 10.0) <= tempfloat) {
tens *= 10.0;
tenscount += 1;
}


// write out the negative if needed
if (value < 0)
Serial.print('-');

if (tenscount == 0)
Serial.print(0, DEC);

for (i=0; i< tenscount; i++) {
digit = (int) (tempfloat/tens);
Serial.print(digit, DEC);
tempfloat = tempfloat - ((float)digit * tens);
tens /= 10.0;
}

// if no places after decimal, stop now and return
if (places <= 0)
return;

// otherwise, write the point and continue on
Serial.print('.');

// now write out each decimal place by shifting digits one by one into the ones place and writing the truncated value
for (i = 0; i < places; i++) {
tempfloat *= 10.0;
digit = (int) tempfloat;
Serial.print(digit,DEC);
// once written, subtract off that digit
tempfloat = tempfloat - (float) digit;
}
}





float rawData = 0;
float distance =0;
float alpha[5] = {7545.2,7522,7860.2,8373.9,8093.6};
float beta[5] = {-1.3297,-1.3272,-1.3341,-1.3445,-1.339};
//will be used in equations for different LEDs example : LED1 = 9009x^-1.3591
int iterations = 50;
byte measurements[50];
int mode, TempModeValue;
byte HighestFrequency, TempFrequency;
int i,j,z;
byte key;

void setup(){
Serial.begin(9600); // set up Serial library at 9600 bps
pinMode(13, OUTPUT);
pinMode(11, OUTPUT);
digitalWrite(18,LOW);
for(i=5;i<=9;i++)
digitalWrite(i,HIGH);



}
void loop(){

//distance = rawData;
//Serial.println((int)rawData);
//delay(500);
//Serial.print("?f");//clear screen
rawData =0;
//for(i=4;i<=8;i++)
i=4;
{

///TIME CRITICAL READINGS
digitalWrite(i,LOW);//10cm sensor is inverted
digitalWrite(9,HIGH);
delay(20);
for(z =0;z {
measurements[z] = analogRead(0);
rawData += measurements[z];
}
digitalWrite(i,HIGH);
digitalWrite(9,LOW);
///TIME CRITICAL READINGS OVER


//sort list
for(j=1;j {
key=measurements[j];
i=j-1;
while(measurements[i]>key && i>=0)
{
measurements[i+1]=measurements[i];
i--;
}
measurements[i+1]=key;
}
//take first value as highest
mode = TempModeValue = measurements[0];
HighestFrequency = TempFrequency = 0;

for(i=1;i {
if (measurements[i] == TempModeValue)
TempFrequency++;//represents highest frequency
else
{
TempModeValue = measurements[i];
TempFrequency = 1;
}

if(TempFrequency > HighestFrequency)
{
mode = TempModeValue;
HighestFrequency = TempFrequency;
}
}




rawData /= iterations;
//distance = 1148*pow(rawData,-1.0

//measurements[i-4]= pow(rawData,-1.3591);
//rawData = alpha[i-4]*pow(rawData,beta[i-4]);
for(z=0;z {
printFloat(rawData,2);
Serial.print(',');
Serial.print(measurements[0],DEC);
Serial.print(',');
Serial.print(measurements[49],DEC);
Serial.println();
}

//printFloat(rawData,6);
if(i<8)
//Serial.print(',');
//measurements[i-4] = rawData;
delay(5);
}
// Serial.println();
delay(250);




/*if(Serial.available() > 0)
{
temp = Serial.read();
if( temp == 'r')
{
//printFloat(distance,2);
for(i=0;i<4;i++)
{
printFloat(measurements[i],6);
Serial.print(',');
}
printFloat(measurements[4],6);//so we don't have an extra comma
Serial.println();
/* }
}*/
}

Monday, July 28, 2008

Saturday, July 26, 2008

Saturday, July 19, 2008

compiling issues

I found a site that illustrates the proper order for directives when using g++ as a compiler. I was having the problem that I could make a program compile using relative pathname in the -I option but not when using an absolute path name.

The following worked with relative pathnames


$(CXX) main.cpp -o test -I./.. -L. -lsmile

But i wanted to use absolute path names and i tried this:


$(CXX) main.cpp -o test -I/home/santiago/thesis/SmileHeaderfiles -L -lsmile

which didn't work.
This did work


g++ -I/home/santiago/thesis/SmileHeaderfiles main.cpp -o test -L. -lsmile

Friday, July 18, 2008

Player/Stage Ubuntu 7.10 update

I got player version 2.1.1 and stage 3.0.0 working, player was not too difficult, I just needed to install libglu1-mesa-dev to get rid of some of the dependency issues I was having.

Stage was more difficult, For some reason the program needed me to manually export
export LD_LIBRARY_PATH=/usr/local/lib
for stage to work.

I was getting this error before for google reference:

stage: error while loading shared libraries: libstage.so.3.0.0: cannot open shared object file: No such file or directory


So I added:
export LD_LIBRARY_PATH=/usr/local/lib
to .bashrc and called it a day.