I have a Spark fun 9DOF Razor IMU which outputs magnetic heading via a serial stream and a GPS shield which outputs course also via a serial stream but want to compare the two angles and output the difference as a variable for further manipulation (slip angle).
Can anyone advise how I might go about reading the stream, storing it as a variable, doing some maths and outputting the desired delta? And/or if there's some code out there to play with?
Presently I'm using the Sparkfun 9DOF Razor IMU and code plus the Tiny GPS code, but is too large to post here. The reading of the stream is done from an Arduino UNO R3 from the IMU used presently is:-
#include <SoftwareSerial.h>
SoftwareSerial mySerial(10, 11); // RX, TX
byte inputString = ""; // a string to hold incoming data
boolean stringComplete = false; // whether the string is complete
void setup()
{
Serial.begin(19200);
// while (!Serial) {
// ;
inputString.reserve(200);
// currentTime = millis();
// cloopTime = currentTime;
// set the data rate for the SoftwareSerial port
mySerial.begin(19200);
// mySerial.println("Hello, world?");
Serial.println("SF 9DOF OUTPUT...");
//delay (100);
}
void loop() {
if (stringComplete) {
Serial.print(inputString);
// clear the string:
inputString = "";
stringComplete = false;
}
}
void serialEvent() {
while (mySerial.available()) {
// get the new byte:
char inChar = (char)mySerial.read();
// add it to the inputString:
inputString += inChar;
// if the incoming character is a newline, set a flag
// so the main loop can do something about it:
if (inChar == '\n') {
stringComplete = true;
}
}
}
byte inputString = ""; // a string to hold incoming data
Your "string" is of the wrong type (should be char) and has room for exactly 0 characters. As long as you don't plan to store any additional characters in the string, you're off to a good start.
inputString.reserve(200);
bytes don't have methods.
inputString += inChar;
What exactly does ADDING (not appending) two characters accomplish? What, exactly, is 'A' + 'B'?
Can anyone advise how I might go about reading the stream, storing it as a variable, doing some maths and outputting the desired delta? And/or if there's some code out there to play with?
There are plenty of examples around for reading and storing serial data. None of them look anything like your code.
The ones that actually work use char arrays or they piss resources away on Strings.
#define SOP '<'
#define EOP '>'
bool started = false;
bool ended = false;
char inData[80];
byte index;
void setup()
{
Serial.begin(57600);
// Other stuff...
}
void loop()
{
// Read all serial data available, as fast as possible
while(Serial.available() > 0)
{
char inChar = Serial.read();
if(inChar == SOP)
{
index = 0;
inData[index] = '\0';
started = true;
ended = false;
}
else if(inChar == EOP)
{
ended = true;
break;
}
else
{
if(index < 79)
{
inData[index] = inChar;
index++;
inData[index] = '\0';
}
}
}
// We are here either because all pending serial
// data has been read OR because an end of
// packet marker arrived. Which is it?
if(started && ended)
{
// The end of packet marker arrived. Process the packet
// Reset for the next packet
started = false;
ended = false;
index = 0;
inData[index] = '\0';
}
}
mlubbock:
Can anyone advise how I might go about reading the stream, storing it as a variable, doing some maths and outputting the desired delta? And/or if there's some code out there to play with?
The compass will give you a bearing. You should be able to find code examples that read the bearing from the sensor.
The GPS receiver will give you a serial data stream that contains position information. There are libraries available to decode the serial stream for you and you should be able to find code examples that do this and give you a sequence of positions. You would need to write some code to determine the difference between positions to work out your heading. Because the positional resolution of GPS is not very good, you will need to ensure that the positions you're comparing are a sufficient distance apart to keep the resolution of the calculated heading acceptable. For example if you do the comparison every few hundred yards you could probably get a very accurate heading, but if you a comparing positions within a few yards of each other the heading will be all over the place.
Paul & Peter,
many thanks for your advice.
Paul,
I've modified your example code slightly to read from the serial interface via pins 10 & 11 & print to the serial window for interest.
The output prints the magnetic heading (i.e. 135.00) to the serial window. If I wanted to add a numerical value (i.e. 5) to the inChar input, such that the result would yield 140.00, how would I do that, Serial.println(inChar + 5) offers 163816.34927.
In the fullness of time I'd like the 'numerical value' to obtained from the a GPS course value but I fear that's a long way down the road (forgive the pun).
Here's the modified code...
#include <SoftwareSerial.h>
#define SOP '<' //place this character at start of transmission from IMU Mag Heading output?
#define EOP '>' //place this character at end of transmission from IMU Mag Heading output?
SoftwareSerial mySerial(10, 11); // RX, TX - set up 10 & 11 for serial input
bool started = false;
bool ended = false;
char inData[6];
byte index;
void setup()
{
Serial.begin(19200); // serial window baud rate
// Other stuff...
mySerial.begin(19200); // IMU baud rate
Serial.println("SF 9DOF MAG Heading OUTPUT..."); // Serial window title
}
void loop()
{
// Read all serial data available, as fast as possible
while(mySerial.available() > 0)
{
char inChar = mySerial.read();
if(inChar == SOP)
{
index = 0;
inData[index] = '\0';
started = true;
ended = false;
}
else if(inChar == EOP)
{
ended = true;
break;
}
else
{
if(index < 7)
{
inData[index] = inChar;
index++;
inData[index] = '\0';
// Serial.write("inChar");
Serial.write(inChar); // happily prints inChar data to serial window
//Serial.write(inChar + 5); // prints "163816.34927" to serial window
}
}
}
// We are here either because all pending serial
// data has been read OR because an end of
// packet marker arrived. Which is it?
if(started && ended)
{
// The end of packet marker arrived. Process the packet
// Reset for the next packet
started = false;
ended = false;
index = 0;
inData[index] = '\0';
// Serial.write("inData"); // print inData to serial window?
// Serial.write(inData); // print inData to serial window?
}
}
At the moment you don't do anything with the data being read from the serial port. You need to parse the received text to extract the numbers from it. There are several standard functions to do this - sscanf() is very flexible, and atoi() (and related functions) are simpler to use but require you to have stripped off everything except the digits. You'll also find examples where people have written their own parsers which just works through each character at a time checking whether it's a digit ('0' - '9'), converts that digit to the corresponding number 0 - 9 and adds to an accumulator i.e. multiply the existing value by 10 and add the new digit. Which ever approach you take, the end result will be in the firm of a number rather than a string. Once you have a number, adding and subtracting headings and bearings and so on is trivial, and there are lots of ways to print the answer out as a string.
The output prints the magnetic heading (i.e. "elephant") to the serial window.
If I wanted to add a numerical value (i.e. 5) to the inChar input, such that the result would yield
What does "elephant" plus 5 equal?
You can't perform arithmetic on strings. You could convert the string to an int or to a float, using stoi(0 or atof(). Then, you can perform arithmetic on the two related values.