Data conversion problem from IMU to mini pro.

Im working on a project involving an ArduIMU v2 flat and an Arudino pro mini.

Here is the IMU I am using: http://code.google.com/p/ardu-imu/wiki/Hardware

Basically, I have the IMU and the mini board set up for serial communication. For simplicity, I have the IMU outputting only one degree (Pitch) of raw accelerometer data. The communication works fine- as in- I get the same outputs via the mini board’s serial monitor as i get on the IMUs. The problem I am having is manipulating the data into something usable. Here is the typical output followed by my current code.

490
490
491
492
492
493
493
494
494
496
497
499
499
499
500
500
501
502
504
504
503
504
505
505
503
504
504
508
522
496
488
533
536
#include <NewSoftSerial.h>


#define rxPin 8  // pin 8 will recieve serial comm
#define txPin 7  // pin 7 will transmit serial comm
#define controlPin 13  
#define forward HIGH 
#define reverse LOW 


NewSoftSerial serialIMU(rxPin, txPin); // initialize digital pins for serial comm

byte imudata ;

void setup()
{
  pinMode(controlPin, OUTPUT);
  pinMode(rxPin, INPUT);
  pinMode(txPin, OUTPUT); 
  // initialize serial communications at 9600 bps:
  Serial.begin(9600); 
  serialIMU.begin(4800); // initialize bps for soft serial at 4800 bps. 
}

  void loop() 
  {
      if (serialIMU.available() > 0){
       imudata = serialIMU.read();
      } 
       if (imudata >= 500){
      digitalWrite(controlPin, forward);
      } 
      else {
     digitalWrite(controlPin, reverse);
    }
  Serial.print(imudata);
   delay(1);   
   }

The problem arises when i either try to change the “imudata” type to ‘int’ instead of ‘byte’ or when i try converting the read bytes to an int. The program is supposed to simply turn the pin 13 LED to ON when the value is above 500, and turn it OFF when it is below. When i run the program as is, the LED just stays on and does not respond to the IF statement in the code above.

Also, in the testing i have done: I noticed that when i look at the IMU serial monitor it is outputting whole 3 digit numbers… i assume int’s. I know this because i simply put a delay and watched it print. When i do the same at the end of the mini board program (the one above) it will print one digit at a time… i assume this is because it is a byte type?

Any conversions I’ve been trying just yield garbage numbers that do not respond to the movement of the IMU.

To clarify, there are TWO programs running here… the one on the IMU and the one on the mini pro. Its the one on the mini pro that is shown above and that is giving me trouble.

I’m pretty new at this, so let me know if something else needs clarification.

Thanks for your help.

A byte can hold a value in the range of 0 to 255. Since 255 is not greater or equal 500, the pin never gets turned on.

The Serial.read() function returns an int, but only so that it can return a negative value if there was nothing to read. The actual value in the int is in the low byte.

Clearly the other code, the one that is generating the output shown, is reading in multiple bytes, and properly combining them into the int being printed.

Thanks for your reply!

I just changed the IMU program to output values between 0 and 255... here is the program that is on the IMU.

void setup()
{
  Serial.begin(4800);
}
void loop()
{
  int analogP = analogRead(0);


int mappedVal = map(analogP,395,630,0,255);  // this should fix the range problem...i think???
  Serial.println(mappedVal);
}

The IMU now outputs values between 0 and 255 depending on its orientation (pitch). So the mini is receiving those values and will output them to the serial monitor just fine, however, the LED still does not react to the threshold- which i changed to:

if (imudata >= 120)
  {
  digitalWrite(controlPin, forward);

The actual value in the int is in the low byte.

I'm not quite sure what you mean. The fact that serial.read() returns an int makes sense, but im not sure about the "actual value" you mentioned.

On a slightly different note: i notice if i increase the delay at the bottom of the mini program (code in the first post) from delay(1); i get garbage numbers... but keeping it at 1 works perfectly... do you know why this happens?

Thanks again for your help.

I just changed the IMU program to output values between 0 and 255... here is the program that is on the IMU.

That program is outputting a string. If analogP contains 165, for instance, the output to the serial port will be '1', '6', '5', '\n', and '\r'.

So the mini is receiving those values and will output them to the serial monitor just fine, however, the LED still does not react to the threshold- which i changed to:

Because '1' is less than 120, as is '6', '5', etc.

You can switch to using Serial.write() in the sender. This will write the value in analogP to the serial port in binary form, instead of converting it to a string.

The fact that serial.read() returns an int makes sense, but im not sure about the "actual value" you mentioned.

The Serial.read() function reads the data written by Serial.print() or Serial.write(). The print and write functions write data to the serial port one byte at a time.

Since every value in a byte (0 to 255) is valid, there would be no way for Serial.read() to indicate that there was nothing to read, if Serial.read()'s return type was byte.

In order to allow Serial.read() to return a error code, its return type must be something other than byte. The smallest type that fills that role, and can also contain all valid values is int. An int is two bytes. When Serial.read() returns valid data (one byte in size), it does it in the low order byte of the two byte int. It is that low order byte that contains the value that was sent - the "actual data".

Ok, now I understand that better. I can get the LED to stay on by setting the IF statement condition to '9' or the ascii equivalent- 57- since this is the highest single byte value that will be received, but this is of no use to me because i need to use the entire number.

You can switch to using Serial.write() in the sender. This will write the value in analogP to the serial port in binary form, instead of converting it to a string.

I am unable to use the Serial.write() because i need human readable data.

I have changed the IMU program to output the pitch in degrees accurate to two decimal places, and will also print negative values. This is my new output:

10.87 7.32 3.73 0.78 -2.12

So now this comes to the question: What is the best way to store these bytes (max of 6 i think) into an array and then somehow group them so that the program knows it is a signed floating point? Just so you know kind of where i am going with all of this- eventually i want to have the full Pitch, Roll, and Yaw values being transmitted and used to control servos.

Thanks!

I am unable to use the Serial.write() because i need human readable data.

How you print the data on the receiving end has more to do with it being readable than how it is sent.

What goes down the serial connection is a bunch of electrons. Can you read them?

I have changed the IMU program to output the pitch in degrees accurate to two decimal places, and will also print negative values. This is my new output:

You need to include an end of packet marker, so the receiver knows when to stop reading. Then, read all serial data that is available, in a while loop. Break out of that loop when the end of packet marker arrives.

Each character gets added to an array, followed by a NULL byte. Overwrite the NULL on each addition, and append a new NULL.

When the end of packet marker is received, you can use atof() to convert the string to a float.

Thanks for your help! I did what you suggested and with a little debugging worked great.