Arduino sketch for connection with MPU-9150
I recently managed to connect an MPU-9150 breakout board to a Unity3D application, using a Teensy2.0 as an interface (also got it working with Teensy++ 2.0 and Arduino Uno). With this combination I can easily rotate an object in the real world and have a counterpart in a virtual world do the same in real time. I chose the MPU-9150 because its”sensor fusion” functions make this possible without much mathematics.
I quite like the result, and I want to share my experiences and code! On this page, I go into the details of the Arduino (Teensy) sketch. What did I add/change in my Arduino sketch, relative to the standard MPU6050_DMP6 example? The whole story (including Arduino and Unity code) can be found here.
Arduino sketch details
The Arduino sketch that I use is basically a combination of the standard MPU6050_DMP6 example, by Jeff Rowberg and RGSteele, and the “Unity Arduino Serial Connection” by Tiuri de Jong. Installation and setup are detailed on the main page of this project
Step 1: setup a connection to Unity
In the header of the sketch, I include a reference to the ConnUnity library, and create a new instance of this class:
#include <ConnUnity.h> char pinConfig[] = { 'i', 'i', 'i', 'i', 'i', 'i', 'o', 'o', 'o', 'o', 'o', 'o' }; ConnUnity connUnity = ConnUnity(true, true, pinConfig);
ConnUnity is the class that will connect us to Unity, it is my library version of the “Unity Arduino Serial Connection”.
pinConfig is an array with the virtual pin configuration of the Arduino. I did not change the default configuration, but is really not important since we only use the first digital pin as an input, the rest is irrelevant.
(If you change any values here, you must remember to change them in the Unity code as well). The value ‘i’ stands for input, ‘o’ for output, and ‘p’ for pwm.
Next, I create a connUnity instance which uses the pinConfig as defined above, and which uses “fake” Digital pins (true) and “fake” Analog pins (true). I.e., fake means, I pass the values of other computations as if these are actual values of the pins defined.
For the serial connection I use a speed of 57600 baud (since it worked at this speed in the examples by Tiuri de Jong). So in the setup, there is a line
Serial.begin(57600);
Step 2: Acquire quaternion data
I want the quaternion data for the rotation values of the MPU-9150, so based on the MPU6050_DMP6 sketch, I set
#define OUTPUT_READABLE_QUATERNION
and comment out all other outputs, e.g.,
//#define OUTPUT_TEAPOT
Now in the main loop of the sketch, the MPU-9150 will send data through the I2C connection, data which will be stored in the fifobuffer variable. The quaternion data is extracted to Quaternion q in the section
#ifdef OUTPUT_READABLE_QUATERNION // display quaternion values in easy matrix form: w x y z mpu.dmpGetQuaternion(&q, fifoBuffer); //Serial.print("quat\t"); //Serial.print(q.w); //Serial.print("\t"); //Serial.print(q.x); //Serial.print("\t"); //Serial.print(q.y); //Serial.print("\t"); //Serial.println(q.z); #endif
Notice that I commented out all “Serial.print” statements, since these must not interfere with the format used by ConnUnity to send the serial data. The next step is to send the quaternion data as if it were analog values.
Step 3: Send quaternion data as values of analog pins
At the end of the main loop, the quaternion data is converted to values for analog pins, and sent to the PC through a serial connection. This is what happens in
// process inputs/outputs receiveQuaternionData(); // communicate with Flash/Unity connUnity.processSerial();
(Notice that if I had correctly connected the interrupt pin on the MPU-9150, this code should be inside the “while (!mpuInterrupt …” loop. See this section for more details on the interrupt handling). The actual details of the conversion of quaternion data to analog input values are simple:
void receiveQuaternionData() { // pass the Quaternion values as fake analog signals, and scale them to integers 0..1000 connUnity.readVirtualAnalog(0, (int) (q.x * 1000)); connUnity.readVirtualAnalog(1, (int) (q.y * 1000)); connUnity.readVirtualAnalog(2, (int) (q.z * 1000)); connUnity.readVirtualAnalog(3, (int) (q.w * 1000));// pass the button value to Unity connUnity.readVirtualDigital(0,digitalRead(BUTTON_PIN)); }
Normal analog pin values are integers between 0 and 1023, so I scale the quaternion float values to about the same range. You may notice that I pass the BUTTON_PIN value as a virtual digital pin value, where of course this is unnecessary – I thought it was more “symmetrical”.
In “connUnity.processSerial” the Arduino (Teensy) passes the data to the PC. This is done in the normal way as defined in the “Unity Arduino Serial Connection” by Tiuri de Jong. I.e., the program waits until it gets a character from the PC, (updates outputs on the Arduino if necessary), and responds with a string detailing all Arduino inputs. The actual frequency of communication is thus set by the Unity program.
Conclusion
In my opinion, the Arduino sketch for communication between the MPU-9150 and the PC is pretty straightforward.