Serial communication: Sending data from C++ to Arduino - c++

i'm trying to send data from a C++ program over serial communication to an Arduino. I formed a struct for sending the data as an object:
typedef struct
{
double width;
double height;
bool passBoard;
} MachineParameters;
I'm using this Serial library: http://wjwwood.github.com/serial/ for sending the data like this:
MachineParameters mp;
mp.width = 100;
mp.height = 200;
mp.passBoard = true;
ser.write((const uint8_t *)&mp, sizeof(mp));
The library makes it possible to send the data as uint8_t, std::vector or std::string.
The Arduino does receive data, but i don't know how to parse the data into the struct. I'm using the same struct as in the cpp code.
// In Arduio
MachineParameters mp;
int byte_size = 24;
loop() {
if(Serial.available() >= 24) {
Serial.readBytes((char*) &mp , 24);
}
}
// Goal: Read received mp data just like
// mp.width or mp.height
After hours of trying, i still cannot figure it out, how to send this struct to the arduino successfully. Is there another way of sending this data to the arduino? It worked sending the data as string, but that did not seem right.
I am pretty new to programming with C++, so please excuse any obvious questions...
Thank you for helping!
UPDATE: Working solution below
After a view more tries and thanks to your tips, i figured it out. Here is the code, which worked for me. I found out that my problem was the wrong byte size, used for parsing the buffer. The size of the struct in C++ is 12, whereas on the arduino it's 9. Using the original size (12) for parsing the buffer on the Arduino, the struct was parsed correctly.
/* --- C++ CODE --- */
typedef struct
{
double width;
double height;
bool passBoard;
} MachineParameters;
// sizeof(MachineParameters) returns 12.
MachineParameters mp;
mp.width = 11.1;
mp.passBoard = false;
mp.height = 22.2;
ser.write((uint8_t *)&mp, sizeof(mp));
/* --- END OF C++ --- */
/* --- Arduino Code --- */
#define BYTE_SIZE 12
char messageBuffer[BYTE_SIZE];
typedef struct
{
double width;
double height;
bool passBoard;
} MachineParameters;
MachineParameters mp;
void setup() {
Serial.begin(9600);
}
void loop() {
if (Serial.available() >= BYTE_SIZE) {
Serial.readBytes(messageBuffer , BYTE_SIZE);
memcpy(&mp, &messageBuffer, BYTE_SIZE);
// mp.width returns 11.1
// Success :)
}
}
/* --- END OF ARDUINO --- */

on the arduino you receive the data in a buffer as raw bytes
now you have to parse this, you can do this using memcpy to copy the data in the struct
however for doing this the data has to be aligned meaning that you have to know exactly where it begins. so you should send a synchronization byte ( start / stop bytes ) to be able to fix where the data begins
then you can use the code in parsing buffer data into struct :
struct abc {
char a;
char b;
char c;
char d[2];
};
int main() {
char arr[5] = { 'a', 'b', 'c', 'd', 'e' };
struct abc sa;
memcpy(&sa, arr, 5);
return 0;
}
here arr is incoming buffer, and with memcpy all the contents are copied appropriately.
ser.write((const uint8_t *)&mp, sizeof(mp)); is correct
you can create an identical structure mp_arduino on the arduino and copy the content of the receive buffer into this structure with
memcpy ( &mp_arduino, receive_buffer+n, sizeof(mp_arduino) ); where n indicates the position / byte in receive_buffer where your data begins and receive_buffer is defined as uint8_t receive_buffer[] ( or uint8_t* receive_buffer is the same... )
( http://www.cplusplus.com/reference/cstring/memcpy/ )
this is how a struct is stored in memory : How is a struct stored in memory?
on both systems a float should be 32 bit https://www.arduino.cc/reference/en/language/variables/data-types/float/

Related

Comparing a char pointer in an array with an integer

So I'm currently working on a project where it involves two lora devices (Arduino Mega + Dragino LoRa shield) exchanging data with each other.
How it works:
Client will send the speed of motor reading to the server, it will also receive the distance reading from the server.
Server will receive the speed of motor reading and also send its distance reading to the client.
I'm kinda new in C++ programming and here is the issue. The value i received from client is stored in char type buf. How can i compare it with an integer so that i can proceed with a threshold?
if ((char*)buf) < 10){ // (char*)buf contains the distance value sent by the server, I want to compare it with a certain value to trigger a buzzer
sound = 1000;
tone(buzzer,sound);
}
I recieved an error message error: ISO C++ forbids comparison between pointer and integer
Here is the sending code:
char data[3];
itoa(reading, data, 10);
rf95.send((uint8_t*)data,sizeof(data));
Any idea on how i can solve this issue.
Sender:
char data[3]; // I suggest making this bigger because it is
itoa(reading, data, 10); // now only safe if `reading` is in the range [-9, 99]
rf95.send((uint8_t*)data, strlen(data) + 1); // only send just enough
I suggest using sprintf(data, "%d", reading); instead of the non-standard itoa though.
If reading is a float as the comments suggest, you need to do this instead:
sprintf(data, "%.0f", reading); // there's no space for decimals in data
Receiver:
// read into buf until a \0 is encountered (and store that \0), then
int reading;
// if buf is an uint8_t[] as suggested in the comments, cast it:
if(sscanf(reinterpret_cast<const char*>(buf), "%d", &reading) == 1) {
// an int was decoded
if(reading < 10) {
sound = 1000;
tone(buzzer,sound);
}
}
If you have installed Arduino STL you may have access to a lot more functions and classes that could help - but afaik, Arduino STL is very outdated so I used sscanf that I think is included in the base Arduino package.
Since you probably want to send different types over the radio and you'll have to cast between the char* and uint8* a lot, you could add two helper function templates to do that:
template<uint8_t N> // returns true if sent ok
bool rf95send(const char(&buf)[N], uint8_t len) {
if(N < len) return false;
return rf95.send(reinterpret_cast<const uint8_t*>(buf), len);
}
template<uint8_t N> // returns true if received ok
bool rf95receive(char(&buf)[N]) {
uint8_t len = N;
return rf95.recv(reinterpret_cast<uint8_t*>(buf), &len);
}
You can then add helper functions for the types you'd like to support:
bool rf95send_float(float f) { // returns true if sent ok
char buf[45]; // room for all floats
int len = sprintf(buf, "%.2f", f);
return len > 0 && rf95send(buf, len + 1); // +1 for the null terminator
}
bool rf95receive_float(float& f) { // returns true if received ok
char buf[45];
if(rf95receive(buf)) {
return sscanf(buf, "%f", &f) == 1;
}
return false;
}
Then in your sender code:
float reading;
if(rf95send_float(reading)) { // sent ok
and the receiving side:
float reading;
if(rf95receive_float(reading)) { // received ok
if(reading < 10) {
sound = 1000;
tone(buzzer,sound);
}
}

How to capture and store sensor data from Arduino into C++

I am writing a code to capture serial readings from the Arduino to C++
Is there a way to capture the readings line by line and then store it into an array? I have read another post similar to mine, but I am still unable to apply it.
Any help is greatly appreciated, thank you.
Environment setup:
Arduino UNO
ADXL 335 accelerometer
Ubuntu 16.04
C++
[Updated] applied solution from Bart
Cpp file
The reason why I added the "for-loop with print and break" is to analyze the array contents.
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <unistd.h>
using namespace std;
char serialPortFilename[] = "/dev/ttyACM0";
int main()
{
char readBuffer[1024];
FILE *serPort = fopen(serialPortFilename, "r");
if (serPort == NULL)
{
printf("ERROR");
return 0;
}
while(1)
{
usleep(1000); //sync up Linux and Arduino
memset(readBuffer, 0, 1024);
fread(readBuffer, sizeof(char),1024,serPort);
for(int i=0; i<1024; i++){
printf("%c",readBuffer[i]);
}
break;
}
return 0;
}
Ino file
Fetching data from the Accelerometer
#include <stdio.h>
const int xPin = A0;
const int yPin = A1;
const int zPin = A2;
void setup() {
Serial.begin(9600);
}
void loop() {
int x = 0, y = 0, z = 0;
x = analogRead(xPin);
y = analogRead(yPin);
z = analogRead(zPin);
char buffer[16];
int n;
n = sprintf(buffer,"<%d,%d,%d>",x,y,z);
Serial.write(buffer);
}
Results
Running the code for three times
Click Here
The ideal outputs should be
<a,b,c><a,b,c><a,b,c>...
but right now, some of the outputs has the values inside "corrupted" (please see the fourth line from the top).
Even if use the start and end markers to determine a correct dataset, the data within the set is still wrong. I suspect the issue lies with the char array from C++, due to it being unsynchronized with Arduino. Else I need to send by Bytes from Arduino (not really sure how)
When dealing with two programs running on different processors they will never start sending/receiving at the same time. What you likely see is not that the results are merged wrong it is more likely the reading program started and stopped half way through the data.
When sending data over a line it is best that you:
On the Arduino:
First frame the data.
Send the frame.
On Linux:
Read in data in a buffer.
Search the buffer for a complete frame and deframe.
1. Framing the data
With framing the data I mean that you need a structure which you can recognize and validate on the receiving side. For example you could add the characters STX and ETX as control characters around your data. When the length of your data varies it is also required to send this.
In the following example we take that the data array is never longer than 255 bytes. This means that you can store the length in a single byte. Below you see pseudo code of how a frame could look like:
STX LENGTH DATA_ARRAY ETX
The total length of the bytes which will be send are thus the length of the data plus three.
2. Sending
Next you do not use println but Serial.write(buf, len) instead.
3. Receiving
On the receiving side you have a buffer in which all data received will be appended.
4. Deframing
Next each time new data has been added search for an STX character, assume the next character is the length. Using the length +1 you should find a ETX. If so you have found a valid frame and you can use the data. Next remove it from the buffer.
for(uint32_t i = 0; i < (buffer.size() - 2); ++i)
{
if(STX == buffer[i])
{
uint8_t length = buffer[i+2];
if(buffer.size() > (i + length + 3) && (ETX == buffer[i + length + 2]))
{
// Do something with the data.
// Clear the buffer from every thing before i + length + 3
buffer.clear(0, i + length + 3);
// Break the loop as by clearing the data the current index becomes invalid.
break;
}
}
}
For an example also using a Cyclic Redundancy Check (CRC) see here

How to use Viterbi decoder from GNU Radio library

I need to make Viterbi decoding of some convolutional-encoded signal. My application shall work with large files, therefore I cannot insert all the signal into a heap, so I need to process a data by a sequence of separate buffers. I have found a good library for Viterbi decoding - Encoder and a Viterbi decoder in C++ on the dr. Dobbs. I have applied the decoder from the libarary, it works correct, but doesn't provide a function for continuous use (call a function many times for each signal buffer with considering of previous calculations). Then I have found the GNU Radio C++ library which provide the necessary functions. But I don't understand how to use its functions, because it doesn't provide a documentation. It contains the example of Viterbi decoding with is present below:
extern "C" {
#include <gnuradio/fec/viterbi.h>
}
#include <cstdio>
#include <cmath>
#define MAXCHUNKSIZE 4096
#define MAXENCSIZE MAXCHUNKSIZE*16
int main()
{
unsigned char data[MAXCHUNKSIZE];
signed char syms[MAXENCSIZE];
int count = 0;
// Initialize metric table
int mettab[2][256];
int amp = 100; // What is it? ***
float RATE=0.5;
float ebn0 = 12.0;
float esn0 = RATE*pow(10.0, ebn0/10);
gen_met(mettab, amp, esn0, 0.0, 4);
// Initialize decoder state
struct viterbi_state state0[64];
struct viterbi_state state1[64];
unsigned char viterbi_in[16];
viterbi_chunks_init(state0);
while (!feof(stdin)) {
unsigned int n = fread(syms, 1, MAXENCSIZE, stdin);
unsigned char *out = data;
for (unsigned int i = 0; i < n; i++) {
// FIXME: This implements hard decoding by slicing the input stream
unsigned char sym = syms[i] > 0 ? -amp : amp; // What is it? ***
// Write the symbol to the decoder input
viterbi_in[count % 4] = sym;
// Every four symbols, perform the butterfly2 operation
if ((count % 4) == 3) {
viterbi_butterfly2(viterbi_in, mettab, state0, state1);
// Every sixteen symbols, perform the readback operation
if ((count > 64) && (count % 16) == 11) {
viterbi_get_output(state0, out);
fwrite(out++, 1, 1, stdout);
}
}
count++;
}
}
return 0;
}
File viterbi.c from it also contains the next function viterbi(), without a declaration:
/* Viterbi decoder */
int viterbi(unsigned long *metric, /* Final path metric (returned value) */
unsigned char *data, /* Decoded output data */
unsigned char *symbols, /* Raw deinterleaved input symbols */
unsigned int nbits, /* Number of output bits */
int mettab[2][256] /* Metric table, [sent sym][rx symbol] */
) { ...
Also I found one more implementation for Viterbi decoding - The Spiral project. But it also doesn't contain a normal description and doesn't want to compile. And two more implementation on the ExpertCore and Forward Error Correction DSP library.
My question: Can anyone understand how to use the above GNU Radio's implementation of the Viterbi algorithm for continuous use for binary interleaved digital signal (Encoder parameters of my signal: K=7 rate=1/2, every bit in my file is a demodulated sample of a signal)?

Best way to pass variables between Arduino and PC over serial?

I've written an Arduino sketch which reads data from a remote control receiver and returns a value between 0 and 1023 for that channel. I basically want to send this data (something in the format of channel:value, eg, Channel 1 : 1023, Channel 2 : 511) to a PC program (which I plan to write myself).
The most efficient way I can think to do this is to use two bytes of data, with the first 6 bits representing the channel (2^6 = 64 possible channels, way more than I need), and the last ten representing the value (2^10 = 1024, perfect). But I'm not sure on the best way to implement this in C++, or if this is even the most ideal way to do this. So:
What is the best way to craft individual bytes and work with binary numbers in C++? Preferably storing the values in memory as such (ie, no bool arrays, where each index takes up it's own byte). Two bytes of data is more than enough for what I need.
Is this the easiest/simplest/most efficient/recommended way to implement what I am trying to achieve? I basically want to pass variables as is between programs, are there any other ways to do this?
You can declare a packed struct to hold these two values:
struct chan_value_t
{
uint8_t channel : 6;
uint16_t value : 10;
};
But to send it as two bytes, you'll need to either (1) "union" it with a two-byte array:
union chan_value_t
{
struct {
uint8_t channel : 6;
uint16_t value : 10;
};
uint8_t bytes[2];
};
chan_value_t cv;
void setup()
{
Serial.begin( 9600 );
cv.channel = 2;
cv.value = 800;
for (int i=0; i<sizeof(cv.bytes); i++) {
Serial.print( cv.bytes[i], HEX );
Serial.print( ' ' );
}
Serial.println();
}
void loop() {}
(The struct is anonymous when nested in this union; the union has the name.)
Or (2) cast a pointer to the struct to a pointer to bytes:
struct chan_value_t {
uint8_t channel : 6;
uint16_t value : 10;
};
chan_value_t cv;
void setup()
{
Serial.begin( 9600 );
cv.channel = 2;
cv.value = 800;
uint8_t *bytes = (uint8_t *) &cv; // cast &cv to a pointer to bytes
for (int i=0; i<sizeof(cv); i++) {
Serial.print( bytes[i], HEX );
Serial.print( ' ' );
}
Serial.println();
}
void loop() {}
They both print the hexadecimal value of the bytes: 0x02 and 0xC8. 800 is 0x320, shifted left by 6 bits is 0xC800.
To send this to the PC, you may want to start with a special character sequence and finish with a checksum of some sort (Fletcher checksum is easy). Then it's easy to throw away garbage characters and know when there are transmission errors.
This is aimed at your no. 2 question.
OSC (OpenSoundControl) is a convenient way to send messages across different platforms and devices. Libraries exist for most platforms.
You could use the library OSC for Arduino and implement your own solution to the specification or using a library that fits your context.
The message you mention could be sent as /channel/1 /value/1023

Transmitting Float Values Across Xbee Network

I am having trouble transmitting a float across a simple 2 node Xbee Network.
I am aware that the Xbee system transmits packages via bytes, so I can send a char, but I am having trouble sending anything more than that, and I can't seem to find any documentation anywhere.
Here is my current (basic) code.
Sender:
(... appropriate setup...)
void loop()
{
sensorValue = analogRead(analogInPin);
sensorValueTemp = sensorValue / 9.31; //LM35 measurement into Centigrade
Serial.print(sensorValueTemp);
delay(1000);
}
Receiver:
(...appropriate setup...)
void loop() {
lcd.setCursor(0, 0);
if (Serial.available() > 0) {
lcd.print(incomingByte);
}
delay(1000);
}
Any hint as to get the float to be transmitted successfully would be great? Or if it is already being transmitted properly, how to read it properly?
Thanks
You can send the float in bytes and reconstruct the float at the receiver.
The following example may help you:
Sender side:
float x = 1128.476;
char b[sizeof(x)];
memcpy(b, &x, sizeof(x));
// Iterate over b and send bytes
// [...]
Receiver side:
float y = 0;
char b[sizeof(x)];
// Store 4 bytes representing the float into b
// [...]
// Rebuild the float
memcpy(&y, b, sizeof(y));
At the end, you have float y on the receiver side, which has the same representation of float x on the sender side.
You can send all the binary data you want between two machines of an identical architecture, memory layout, byte-endianness, etc. by simply taking a byte-sized pointer (char *) on the "sending" side, and iterating over the referenced object for the number of bytes in that object. On the "receiving" side, you allocate an object of the same size (float, long, struct foo), and receiving the bytes, one by one, into a byte-sized pointer which is post-incremented after each byte is received.
On the sending side --
void sendObject(const void *object, size_t size) {
char *outputCursor = (char *) object;
for (;size > 0;size--)
yourSendAByteFunction(*outputCursor++);
}
On the receiving side, assuming yourReceiveAByteFunction() return 0..255 for a valid byte and -1 for a "receiving error", you can do this --
int receiveObject(void *object, size_t size) {
char *inputCursor = (char *) object;
for (;size > 0;size--) {
int nextByte = yourReceiveAByteFunction();
if (nextByte < 0)
return FALSE;
*inputCursor++ = nextByte;
}
return TRUE;
}
You can do the same I/O error checking in the sendObject() function by declaring yourSendAByteFunction() so it returns TRUE or FALSE depending on whether or not an error occurred in the output. It all depends on how much complexity you can stand, and whether or not you have a reliable transmission link.
You can also do a bit of data encapsulation if you have bytes you can't transmit by having a "shift" byte and set of byte values that are prefixed by the "shift" byte to represent some other byte.
Your original sender is sending an ASCII string that represents the float value.
In order to receive and display the value you need to modify the lines as shown below:
(...appropriate setup...)
void loop() {
lcd.setCursor(0, 0);
while (Serial.available() > 0) { //Changed Line
incomingByte = Serial.read(); //Added Line
lcd.print(incomingByte);
}
delay(1000);
}
Note: If would be better to terminate the serial output with a CR to synchronize the devices instead of the delay(1000);