Thursday, October 15, 2009

How to Connect and Communicate With a Phidgets Interface Kit in C#

I have a bunch of there 8/8/8 kits. They are great. First, I would suggest getting their newest API package for your favorite platform.

I use visual studio, so I will have biased examples. I could regurgitate their examples, but mine hopefully don't suck.

From a simple command line application. You may get into some static thread issues, but they are generally avoidable.
in your main()...

try
{
InterfaceKit ik1 = new InterfaceKit();
ik1.open();
}
catch (Exception _exc)
{
Console.WriteLine("interface kit error : " + _exc.Message + "\n",);
}

This is pretty simple, and just opens the IK for management. You have to set up some events. In a constructor method, I dump the following code after you execute the Open() method.

do
{

if (ik1.Attached)
{

Console.WriteLine("ik1 attached.");

//interface kit events
ik1.Attach += phidgets_Attach;
ik1.Detach += phidgets_Detach;
ik1.Error += phidgets_Error;
ik1.SensorChange += _ik1_SensorChange;
ik1.OutputChange += _ik1_OutputChange;
ik1.InputChange += _ik1_InputChange;
}
else
{
Console.WriteLine(("retry : " + retry + " waiting for ik1 attach");
}
retry++;
} while (retry < 10 && !ik1.Attached);


I like these do loops for the initialization setups. Why, because it retries and does not fail just because. It says which instrument is having an issue before it proceeds. I use the phidgets_xxx methods to have a standard system for handling the major Phidgets methods .

#region Phidgets event handlers
///
/// handle the phidget device discovery events
///

/// /// protected void phidgets_Attach(object Sender, AttachEventArgs Args)
{
try
{
Console.WriteLine(Args.Device.Type + " attached.");
}
catch (Exception _exc)
{
throw new Exception(className +
" protected void phidgets_Attach( Sender, Args) :: " + _exc.Message +"\n");
}
} //phidgets_Attach
///
/// handle the phidget device discovery events
///

/// /// protected void phidgets_Detach(object Sender, DetachEventArgs Args)
{
try
{
Console.WriteLine(Args.Device.Type + " detached.");
}
catch (Exception _exc)
{
throw new Exception(className + " protected void phidgets_Detach( Sender, Args) :: " + _exc.Message +"\n");
}
} //phidgets_Detach
protected void phidgets_Error(object Sender, ErrorEventArgs Args)
{
try
{
Console.WriteLine("phidgets error : " + Args.Code + " " + Args.Description);
}
catch (Exception _exc)
{
throw new Exception(className +
" protected void phidgets_Error( Sender, Args) :: " + _exc.Message +"\n");
}
} //phidgets_Error
Then some simple methods to catch changes per port. I connect different instruments to each port. I have to calibrate the readings for each port so that the readings make sense directly from the Read() methods.

protected void _ik1_SensorChange(object Sender, SensorChangeEventArgs Args)
{
try
{
InstrumentType _type = InstrumentType.notset;
int _index = 0;

switch (Args.Index)
{
case 7:
_type = InstrumentType.notset;
_index = 4;
break;
case 6:
_type = InstrumentType.notset;
_index = 3;
break;
case 5:
_type = InstrumentType.notset;
_index = 2;
break;
case 4:
_type = InstrumentType.notset;
_index = 1;
break;
case 3:
_type = InstrumentType.notset;
_index = 0;
break;
case 2:
_type = InstrumentType.notset;
break;
case 1:
_type = InstrumentType.gyro;
gyro.SetRollData(
convertVoltageToUnit(InstrumentType.gyro, Args.Value, 1));
break;
case 0:
_type = InstrumentType.gyro;
gyro.SetPitchData(
convertVoltageToUnit(InstrumentType.gyro, Args.Value, 0));
break;
}
if (_type == InstrumentType.ultrasonicRangeFinder)
{
rangeFinders[_index] = convertVoltageToUnit(
InstrumentType.ultrasonicRangeFinder, Args.Value, _index);
}
Console.WriteLine(className +
" instrument change " + _type + " value: " + Args.Value);
}
catch (Exception _exc)
{
Console.WriteLine(className +
" protected void _ik1_SensorChange( Sender, Args) :: " + _exc.Message + "\n");

}
} //_ik0_SensorChange
protected void _ik1_InputChange(object Sender, InputChangeEventArgs Args)
{
try
{
}
catch (Exception _exc)
{
Console.WriteLine(className +
" protected void _ik1_InputChange( Sender, Args) :: " + _exc.Message + "\n");
}
} //_ik0_InputChange
protected void _ik1_OutputChange(object Sender, OutputChangeEventArgs Args)
{
try
{
}
catch (Exception _exc)
{
Console.WriteLine(className +
" protected void _ik1_OutputChange( Sender, Args) :: " +
_exc.Message + "\n");
}
} //_ik1_OutputChange

///
/// converts the read value, probably in volts to the correct units
/// this will also apply a 6:4 smooth, old value*0.6 + new value*0.4 to help
/// smooth out the readings
///

/// type of instrument read, to get the correct coeefficients/// reading of the instrument/// some instruments are indexed/// the calibrated value
protected double convertVoltageToUnit(InstrumentType Type, double Reading, int Index)
{
double _value;
try
{
int _InstrumentTypeIndex = 0;
double _old = 0;
switch (Type)
{
case InstrumentType.accelerometer:
_InstrumentTypeIndex = 2;
_old = rawAcc[Index];
break;
case InstrumentType.gyro:
_InstrumentTypeIndex = 3;
_old = gyration[Index];
break;
case InstrumentType.pressureStatic:
_InstrumentTypeIndex = 0;
break;
case InstrumentType.temperature:
_InstrumentTypeIndex = 1;
break;
case InstrumentType.ultrasonicRangeFinder:
_InstrumentTypeIndex = 4;
_old = rangeFinders[Index];
break;
case InstrumentType.servo:
_InstrumentTypeIndex = 5;
_old = servos[Index];
break;
case InstrumentType.notset:
break;
}
double A = double.Parse(
AppSettings["instrumentCalibration" + _InstrumentTypeIndex + "A"]);
double B = double.Parse(
AppSettings["instrumentCalibration" + _InstrumentTypeIndex + "B"]);
double C = double.Parse(
AppSettings["instrumentCalibration" + _InstrumentTypeIndex + "C"]);
//apply basic filter to smooth the data
// value = Ax^2+Bx+C
if (_old != 0)
{
_value = 0.6*_old + 0.4*(A*Reading*Reading + B*Reading + C);
}
else
{
_value = A*Reading*Reading + B*Reading + C;
}
}
catch (Exception _exc)
{
throw new Exception(className +
" protected double convertVoltageToUnit( " + Type.ToString("0.000") +
" , " + Reading.ToString("0.000") + " ) :: " + _exc.Message + "\n");
}
return _value;
} //convertVoltageToUnit

It is pretty simple. I then just use events to manage the reading of the ports or inputs. It is really easy at this point. I put the whole session into a System.Timers.Timer loop or a Console.ReadLine system to control the starting and stopping of the application.