Writing an external to communicate with hardware (x-IMU sensor in this case)
I've been building a 9DOF wireless sensor thing for a bit and have finally made some good progress on it (though it is far from done), but I might have come into some funding for an art project and am considering buying a "pro" module instead of using my DIY project.
I've been eye-balling the x-IMU for a long while now (http://www.x-io.co.uk). Looking through the (open source) code and reading the paper on the math involved. Basically I've been trying to build a budget version of that. With funding I could just own that.
Now the thing itself is a 9DOF wireless (bluetooth) board with on-board processor to handle all the math/calculations, and in terms of hardware it seems ideal for what I want. It's even expandable and has on-board logging etc.. which will be useful in the future. It comes with a (windows) application to handle all the onboard settings. I wrote to them and they don't have a mac version of it, but I've managed to run X-CTU fine in a wine wrapper, so I'm sure this thing would be no different.
In terms of actually interfacing with it I asked them how that would work and they said the following:
"You would have to create your own interface app that communicates to the x-IMU via serial and then sends the OSC commands to Max. This does require you to develop and I cannot say how easy or hard this would be for you. This simple C++ library is a good starting point:
http://www.x-io.co.uk/res/sw/ximu_simple_c_receiver.zip"
(the main body of the code below)
So it looks like it would need to interface with a dedicated program. I'm wondering how difficult it would be to implement that as an external, to do everything IN max. I've never created an external before, but seeing as the code is there already, and doesn't really do anything but act as an interface between the device and Max, I'm thinking it shouldn't be too hard. I've seen a couple posts on creating externals in Max, and I think Eric Lyon was even writing a book on that (not sure if that came out yet). This is small time compared to that as this doesn't "do" much.
I asked about the bluetooth side of things and they said that connectivity is handled on the OS level, but I don't know if it would require something like the wiimote objects where you "connect" or "disconnect" the object.
Has anyone written something like this before? (Not specifically for the x-IMU, but for a dedicated piece of hardware)
How close would this be to a wiimote type external? (aka or ajh)
Was it difficult to 'wrap' the code into an external?
How about making it for windows as well as mac? (I'd like to share the results)
Here's the .c part of the code from the zip above.
//=====================================================================================================
// Example.cpp
// 06/08/2012
//=====================================================================================================
//----------------------------------------------------------------------------------------------------
// Includes
#include
#include
#include
#include
#include
#include "xIMUReceiver.h"
//----------------------------------------------------------------------------------------------------
// Functions
int main(void) {
// Serial port variables
int serialHandle;
struct termios options;
unsigned char numBytes;
unsigned char serialBuf[256];
// Packet decoding variables
unsigned char rxBuf[256];
unsigned char rxBufSize = 0;
ErrorCode ErrorCode = ErrNoError;
PacketHeader packetHeader;
// Open serial port
serialHandle = open( "/dev/ttyUSB0", O_RDWR | O_NOCTTY );
if (serialHandle == -1) {
printf("Could not open serial portn");
}
else {
fcntl(serialHandle, F_SETFL, 0);
printf("Opened serial port successfully!n");
}
bzero(&options, sizeof(options)); // set all bits to zero
options.c_cflag = B115200 | CRTSCTS | CS8 | CLOCAL | CREAD;
tcflush(serialHandle, TCIFLUSH); // clean the serial line
tcsetattr(serialHandle, TCSANOW, &options); //set the new option for the port
// Main loop
while(1) {
// Fetch data from serial port
numBytes = read(serialHandle, &serialBuf, sizeof(serialBuf));
// Process each byte
for(int i = 0; i < numBytes; i++) {
// Add data to receive buffer
rxBuf[rxBufSize++] = serialBuf[i];
// Process receive buffer if framing char received
if(xIMUReceiverIsFramingChar(serialBuf[i])) {
ErrorCode = xIMUReceiverProcess(rxBuf, rxBufSize, &packetHeader);
rxBufSize = 0; // clear receive buffer
// Print data if decoded successfully else print Error code
if(ErrorCode == ErrNoError) {
switch(packetHeader) {
case(PktCalInertialAndMagneticData):
printf("Gyr: %8.2f, %8.2f, %8.2f, Acc: %8.2f, %8.2f, %8.2f, Mag: %8.2f, %8.2f, %8.2fn",gyroscope[0], gyroscope[1], gyroscope[2], accelerometer[0], accelerometer[1], accelerometer[2], magnetometer[0], magnetometer[1], magnetometer[2]);
break;
case(PktQuaternionData):
printf("Pitch = %6.1f, tRoll = %6.1f, tYaw = %6.1fn", eulerAngles[0], eulerAngles[1], eulerAngles[2]);
break;
default:
break;
}
}
else{
printf("Error Code: %dn", ErrorCode);
}
}
}
}
}
//=====================================================================================================
// End of file
//=====================================================================================================
This thread seems to have some good resources, but I'm still not sure how bluetooth/connectivity is to be handled (or the port-ability of the above code).
I've written a fair few externals interfacing to different hardware interfaces. As long as the interface API is reasonably documented and works as advertised it's not a big deal for anyone experienced with writing externals.
That said, by the time you've read&understood the hardware API, designed&implemented a wrapper (ie the external) for Max, written some test patches and a .maxhelp file and documented the thing up, a couple of days have come and gone.
As an aside, the information you quote from the manufacturer talks about C++, but the sample code is plain-vanilla C. So the API may well be plain-vanilla (which is in some ways the most straightforward way to go). I wrote one interface that required integrating C, C++, and Objective-C code. This all can be done, but does mean you have to pay attention to which flavor of the language you're using when.
There's a full API listed here:
And it looks like it's in C# and written for Microsoft .NET (will that be a problem for writing a Mac external?)
I've not worked with hardware (or software) APIs before, so I'm not exactly sure what I'm looking at. It looks like a few dozen .cs files and a .csproj file, but I take it these are the things that the external would call/access, all of this is what would be wrapped in the external. (ie I can just pack up all the data a certain way and have it come out a single outlet (like the wiimote objects where you 'route' off the bits you need/want).
Hi,
I'm a bit late to this, but if you're on OS X you may be interested in my IMU2OSC utility:
It reads data from the x-IMU using Bluetooth or USB and sends out a stream of OSC messages when Capture
is on.
best,
Jamie
Howdie Jamie. We had exchanged a couple emails a while back.
I hadn't seen the updated version of IMU2OSC! Last one I had didn't have the Eular output, or selectable OSC port/ip. I'll definitely download and try this one.
Ah! I remembered that I'd had an exchange with someone, but hadn't made the connection with the forum.
This reminds me, I need to add support for Quaternion data as you requested. It'll be added in the next release. Here's the relevant issue if you want to follow it: https://github.com/jamiebullock/IMU2OSC/issues/11
Jamie
Quaternion data would be great!