Openframeworks, reading serial data from Arduino - c++

I'm trying to read serial data from an Arduino UNO using an ofSerialobject and assign it as an int.
I am able to read in individual bytes, however, the values I'm receiving in the openframeworks console are not the same as the values I'm reading in the Arduino serial monitor.
I have provided screenshots of the respective consoles:
My Arduino code is simply the basic "AnalogReadSerial" example available with the Arduino IDE.
// the setup routine runs once when you press reset:
void setup() {
// initialize serial communication at 9600 bits per second:
Serial.begin(9600);
}
// the loop routine runs over and over again forever:
void loop() {
// read the input on analog pin 0:
int sensorValue = analogRead(A0);
// print out the value you read:
Serial.println(sensorValue);
delay(1); // delay in between reads for stability
}
Whereas my C++ code is mostly copied from the documentation for the ofSerial readByte function.
void serialReader::setup()
{
serial.listDevices();
vector <ofSerialDeviceInfo> deviceList = serial.getDeviceList();
serial.setup("COM4", 9600); //open the first device and talk to it at 9600 baud
}
void serialReader::printByteToConsole()
{
int myByte = 0;
myByte = serial.readByte();
if ( myByte == OF_SERIAL_NO_DATA )
printf("\nno data was read");
else if ( myByte == OF_SERIAL_ERROR )
printf("\nan error occurred");
else
printf("\nmyByte is %d ", myByte);
}
Any insight into what may be causing this disparity between the readings would be greatly appreciated. Thank you.

Arduino's Serial.println translates the raw bytes into their ASCII equivalent and then sends those bytes followed by linefeed (10) and carriage return (13) bytes. So, the raw byte 12 is sent as 4 total bytes -- two bytes representing the ASCII 1 (49), 2 (50) and then (10) and (13) for the new line characters. So, since openFrameworks does not automatically translate the ASCII values back into raw bytes, you are seeing the ASCII version. The Arduino console shows you the ASCII version as readable text.
You can see the translation between ASCII and raw bytes (Decimal / aka DEC) here:
http://www.asciitable.com/
If you want the two numbers to match on both sides, consider using Serial.write in Arduino to write the raw bytes without ASCII translation and new line characters.

Related

I want to receive multiple data from arduino to raspberry pi using I2C

Thank you to whoever is kind enough to look into this question.
I want to receive multiple data from arduino to raspberry pi using I2C.
I can obtain 1 data from arduino, but once I move to more than one data, it fails to do so.
I have tried multiple methods so far, and I found this method to work the best to obtain data from Arduino.
My previous attempt in obtaining data from arduino is as follows:
I want to read from Arduino using I2C using Raspberry Pi
Raspberry Pi's terminal response has weird font that cannot be recognized
Which are all solved by now.
Got Massive Help from link below
https://area-51.blog/2014/02/15/connecting-an-arduino-to-a-raspberry-pi-using-i2c/
Arduino Code
#include <Wire.h>
#define echoPin 7
#define trigPin 8
int number=0;
long duration;
long distance;
void setup()
{
//Join I2C bus as slave with address 8
Wire.begin(8);
//Call SendData & Receive Data
Wire.onRequest(SendData);
//Setup pins as output and input to operate ultrasonic sensor
Serial.begin(9600);
pinMode(echoPin,INPUT);
pinMode(trigPin,OUTPUT);
}
void loop ()
{
digitalWrite(trigPin,LOW);
delayMicroseconds(2);
digitalWrite(trigPin,HIGH);
delayMicroseconds(2);
digitalWrite(trigPin,LOW);
duration=pulseIn(echoPin,HIGH);
distance=duration/58.2;
Serial.print(distance);
Serial.println(" cm");
}
void SendData()
{
Wire.write(distance);
Wire.write("Why No Work?");
Wire.write(distance);
}
C++ Code
//Declare and Include the necessary header files
#include <iostream>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <linux/i2c-dev.h>
#include <sys/ioctl.h>
#include <fcntl.h>
//Define Address of Slave Address
#define ADDRESS 0x08
//Eliminate the Used of std in the future
using namespace std;
static const char *devName="/dev/i2c-1";
int main(int argc, char **argv)
{
//Check to see if C++ works
cout<<"Hello, World!\n";
cout<<"I2C: Connecting"<<endl;
int file;
if ((file = open(devName, O_RDWR))<0)
{
fprintf(stderr, "I2C: Failed to access");
exit(1);
}
if (ioctl(file, I2C_SLAVE, ADDRESS)<0)
{
cout<<"Failed to Access"<<endl;
}
char buf[0];
char dd;
for (int i=0; i<100;i++)
{
read(file,buf, 3);
float distance= (int) buf[0];
dd= buf[1];
float dist=(int) buf[2];
cout<<distance<<endl;
usleep(10000);
cout<<"doh"<<endl;
cout<<dd<<endl;
cout<<dist<<endl;
}
return 0;
}
What I would expect from the c++ code would be as follows
15
doh
Why No Work?
15
But I get
15
doh
weird font can't be recognized
255
Wire.write(distance);
wants to write a long onto the I2C bus. For an Arduino This is 32 bits, 4 bytes, of data. I'm not sure exactly what wire.write does because the documentation I can find is substandard to the point of being garbage, but the documentation looks like it's going to send exactly 1 of the 4 bytes you wanted to send. In order to send more than one byte, it looks like you need to use the array version: Wire.write(&distance, sizeof (distance));, but even this may not be sufficient. I'll get back into that later.
Wire.write("Why No Work?");
writes a null-terminated string (specifically a const char[13]) onto the I2C bus. I don't know arduino well enough to know if this also sends the terminating null.
so
Wire.write(distance);
Wire.write("Why No Work?");
Wire.write(distance);
needed to write at least 4 + 12 + 4 bytes onto the I2C bus. and probably only wrote 1 + 12 + 1.
On the Pi side,
read(file,buf, 3);
read out 3 bytes. This isn't enough to get the whole of distance, let alone the array of characters and second write of distance. You need to read all of the data you wrote, at least 20 bytes.
In addition,
char buf[0];
defines an array of 0 length. There isn't much you can do with it as there is no space to store anything here. It cannot hold 3 characters, let alone the 20 or 21 necessary. read of 3 bytes wrote into invalid memory and the program can no longer be counted on for sane results.
This means that at best
float distance= (int) buf[0];
dd= buf[1];
float dist=(int) buf[2];
got only one byte of the four bytes of distance and it's dumb luck that the result was the same as expected. dd got exactly one character, not the whole string, and this is turning out to be nonsense because of one of the preceding mistakes. dist is similarly garbage.
To successfully move data from one machine to another, you need to establish a communication protocol. You can't just write a long onto a wire. long doesn't have the same size on all platforms, nor does it always have the same encoding. You have to make absolutely certain that both sides agree on how the long is to be written (size and byte order) and read.
Exactly how you are going to do this is up to you, but here are some pointers and a search term, serialization, to assist you in further research.

Sending and receiving int value to/from serial port

I am developing a window's application that sends and receives data to an Arduino via the serial port.
The problem I have is when I try to send an int value to the serial port and pick it up in the Arduino program. I am using WriteFile() in the window's program to send the int and pick it up in the Arduino using Serial.parseInt(). When I send char values I can pick them up with no problems.
If I want to send int values the only time I receive an integer in the arduino is if I send integers 48 to 57 which give me an int value of 0 to 9 which are the ASCII characters for decimal 48 to 57, weird. e.g. 57, The Arduino seems to pick this up as 9 which is the char value for ASCII 57.
below is the code in the windows program and the Arduino
C++ code:
DWORD ComPort::WriteAnalogData(int *buffer)
{
if (!connected)
return 0;
DWORD bytesSent;
DWORD errors;
if (!WriteFile(hCom, (void *)buffer, sizeof(buffer), &bytesSent, 0))
ClearCommError(hCom, &errors, NULL); // If it fails, clear com errors
else return bytesSent; // Return the number of bytes sent
return 0; // Or return 0 on failure
}
the return value(bytesSent) after the int is written is 4 so I think this function is working. I have a similar function for sending single bytes of data which works and the Arduino picks the data up ok
Arduino Code:
int scadaAnalogVal;
scadaAnalogVal = Serial.parseInt();
digitalWrite(scadaAnalogVal,HIGH);
can anyone tell me what's going on. Probably something simple but i can't see what the issue is, thanks.
The Arduino parseInt() method has a long return type (32-bits) in the Arduino architecture. I think you should change your Arduino code to:
long scadaAnalogVal;
ParseInt documentation

QSerialPort reads hex values sepereatly

I'm using Qt's QSerialPort library to communicate with RS232. I connected ReadyRead signal to my readData() slot;
connect(comms,SIGNAL(readyRead()),this,SLOT(readData()));
When i send a string like "Hello World!" I can read all of data with comms.readAll() and comms.bytesAvailable() returns 12.
But when i send "Hello World!\n\r" it reads "Hello World!" and "\n\r" parts sepereatly and comms.bytesAvailable() returns 12 first, then 2.
And it's getting worse when i send hex bytes like (with no spaces)
0x0F 0x00 0x43 0x11 0x00 0x04 0x11 0x00 0x02 0x70
It reads values correctly but 1 or 2 bytes at a time. I tried waitForRead() but that doesn't help.
How can i read all incoming bytes at a time even it's not standart letter?
Try reading from the port while bytes are available:
if (f_port->bytesAvailable()) { // If there are bytes available
QByteArray f_data; // data container
f_data.clear();
if (f_port->open(QIODevice::ReadWrite)) { // Try to open the port
while(f_port->bytesAvailable()) { // Reading loop
f_data.append(f_port->readAll());
}
f_port->flush();
f_port->close();
}
qDebug() << f_data; // Check the result
}
Unfortunately you cannot be sure to have read all data.
You have to collect incoming data in some intermediate buffer and analyse it for commands complying to your protocol definition. That is, is must meet certain requirements like fixed length or particular starting byte (0x02 for instance) or ending byte (\r comes to mind) or a combination of those.
One way to do it is accumulating a buffer with the bytes you obtain.
Then verify if it's a correct command(that is up to you decide what is correct) and trigger the command you wanna do.
Also you should have a timer to remove trash from the buffer.
Let's see with an small pseudocode
static QByteArrray s_vBuffer;
readData()
{
s_vBuffer.append(....);
bool bValidCommand=VerifyCommand(s_vBuffer);
if(bValidCommand)
{
QByteArray vCommand=ExtractCommand(s_vBuffer);//also removing the part of the command
ExecuteCommand(vCommand);
}
else
{
//if timeout clear s_vBuffer
}
}
Other techniques involves checksums , CRC etc at the end of your command.etc

Serial communication - I'm having trouble turning an incoming char array into an int

I'm trying to receive a number from an Arduino as an integer in C++. The full code is below:
#define STRICT
#include <tchar.h>
#include <windows.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "Serial.h"
#include <boost\lexical_cast.hpp>
enum { EOF_Char = 27 };
int __cdecl _tmain(int /*argc*/, char** /*argv*/)
{
CSerial serial;
LONG lLastError = ERROR_SUCCESS;
// Attempt to open the serial port (COM4)
lLastError = serial.Open(_T("COM4"), 0, 0, false);
// Setup the serial port (9600,8N1, which is the default setting)
lLastError = serial.Setup(CSerial::EBaud9600, CSerial::EData8, CSerial::EParNone, CSerial::EStop1);
// Register only for the receive event
lLastError = serial.SetMask(CSerial::EEventBreak |
CSerial::EEventCTS |
CSerial::EEventDSR |
CSerial::EEventError |
CSerial::EEventRing |
CSerial::EEventRLSD |
CSerial::EEventRecv);
// Use 'non-blocking' reads, because we don't know how many bytes
// will be received. This is normally the most convenient mode
// (and also the default mode for reading data).
lLastError = serial.SetupReadTimeouts(CSerial::EReadTimeoutNonblocking);
// Keep reading data, until an EOF (CTRL-Z) has been received
bool fContinue = true;
do
{
// Wait for an event
lLastError = serial.WaitEvent();
// Save event
const CSerial::EEvent eEvent = serial.GetEventType();
// Handle data receive event
if (eEvent & CSerial::EEventRecv)
{
// Read data, until there is nothing left
DWORD dwBytesRead = 0;
char szBuffer[101];
do
{
// Read data from the COM-port
lLastError = serial.Read(szBuffer, sizeof(szBuffer) - 1, &dwBytesRead);
if (dwBytesRead > 0)
{
// Finalize the data, so it is a valid string
szBuffer[dwBytesRead] = '\0';
// Display the data
printf("%s", szBuffer);
// Check if EOF (CTRL+'[') has been specified
if (strchr(szBuffer, EOF_Char))
fContinue = false;
}
} while (dwBytesRead == sizeof(szBuffer) - 1);
}
} while (fContinue);
// Close the port again
serial.Close();
return 0;
}
I have my Arduino constantly sending out the number 51. This code works fine and consistently displays "51". However, I want an int to manipulate in C++.
First I added
std::stringstream str(szBuffer);
int tester;
str >> tester;
printf("My number is: %d\n", tester+1);
right after
printf("%s", szBuffer);
A typical result looks like:
51My number is: 52
51My number is: 52
51My number is: 52
51My number is: 52
51My number is: 52
5My number is: 6
1My number is: 2
After doing it perfectly 5 or 6 times, the output always separates the incoming digits once or twice in a row (I haven't been able to find a specific pattern yet, but it's always 5-6 and 1-2).
My other attempt was to use the boost library:
int tester = boost::lexical_cast<int>(szBuffer);
printf("My number is: %d\n", tester);
right after
printf("%s", szBuffer);
and I get the same result (1-2 errors after 5-6 correct ones). I don't think the Arduino is sending bad data, since just a
printf("%s", szBuffer);
will never deviate from the number it's supposed to be. Could the conversion be messing up the receiving of data? Thanks.
EDIT: The Arduino code is:
void setup() {
Serial.begin(9600); // same as in your c++ script
}
void loop() {
Serial.print(51);
delay(1000);
}
With serial ports, there is no mechanism where a transmitter can inform a receiver how many bytes were transmitted as a block. I.e. there's no "hidden" marker where Serial.print(51); tells the receiver that it sent two characters as one number. You have to add some kind of indication (spaces, commas, line ends, initial byte counts, whatever) to your serial protocol.
Because of this, the number of characters you get from serial.Read depends on the number of characters you asked it to read (the second parameter) and how many characters are in the serial port's receive buffer, whichever is smaller. Most of the time, it seems the Arduino sends both digits before you call serial.Read, but sometimes it only gets one out in time... and the second is read the next time through the loop.
So let's assume you decided to use line ends to separate your numbers. All you have to do on the Arduino end is change to Serial.println(51);. The receive end is a little more complex.
I don't know what your serial library has in it. Most have some kind of "read line" function, and you would just replace the serial.Read call with something like:
serial.Readline(szBuffer, sizeof(szBuffer) - 1);
and it will take care of null-terminating the output. If it doesn't take care of null-termination, you'll need to find the line end and change it to a \0 yourself. From this point on, your code will work fine, because the serial.Readline function will block until it gets the whole line.
If you don't have a "read line" or at least a "read until this character" function, it's a bit harder. You have to repeatedly call serial.Read, moving through your buffer, until you see the line end character. Further, you run the risk of reading part or all of the next line, so you can't just discard all the data you read when you're done reading the number; you have to move teh data in the buffer so the next line's data (and further) is at the start of the buffer.
If you're using Boost (are you? it has no CSerial that I see), it looks like it has a read_until function. This takes three parameters: the stream you're reading from, a stream buffer to store the data in, and something to stop on. In this case, the stream buffer for storage is the one in your std::stringstream:
std::stringstream buffer;
size_t chars = boost::asio::read_until(serial, buffer.rdbuf(), '\n');
if(chars == 0) return;
int tester;
buffer >> tester;
printf("My number is: %d\n", tester+1);

What buffer size should be chosen for serial communication of sensor readings?

I have an arduino board that is connected to a sensor. From Arduino IDE serial monitor, I see the readings are mostly 160, 150, etc. Arduino has a 10 bit ADC, so I assume the readings range from 0 to 1024.
I want to fetch that readings to my computer so that I can do further processing. It must be done this way up to this point. Now, I wrote a c++ program to read serial port buffer with Windows APIs (DCB). The transfer speed of the serial ports are set to 115200 on both the Arduino IDE and the c++ program.
I will describe my problem first: Since I want to send the readings to my computer, I expect the data looks like the following:
124
154
342
232
...
But now it looks like
321
43
5
2
123
...
As shown, the data are concatenated. I knew it because I tried to display them with [], and the data are truly messed up.
The section of the code that is doing the serial port reading on the computer is as here:
// Read
int n = 10;
char szBuff[10 + 1] = {0};
DWORD dwBytesRead = 0;
int i;
for (i = 0; i < 200; i++){
{
if(!ReadFile(hSerial, szBuff, n, &dwBytesRead, NULL)){
//error occurred. Report to user.
printf("Cannot read.\n");
}
else{
printf("%s\n" , szBuff);
}
}
}
The Arduino code that's doing the serial port sending is:
char buffer [10] = { 0 };
int analogIn = 0;
int A0_val = 0;
void setup() {
Serial.begin(115200);
}
void loop() {
A0_val = analogRead(analogIn);
sprintf(buffer, "%d", A0_val);
Serial.println(buffer);
}
I suspect that the messing up of the data is caused by different size of the buffer used to transmit and receive data in the serial port. What is the good suggestion for the size of the buffer and even better method to guarantee the successful transmission of valid data?
Thanks very much!
Your reciever code cannot assume a single read from the serial port will yield a complete line (i.e. the 2 or 3 digits followed by a '\n' that the arduino continuously sends).
It is up to the receiver to synthetize complete lines of text on reception, and only then try to use them as meaningful numbers.
Since the serial interface is extremely slow compared with your average PC computing power, there is little point in reading more than one character at a time: literally millions of CPU cycles will be spent waiting for the next character, so you really don't need to react fast to the arduino input.
Since in that particular case it will not hinder performances in the slightest, I find it more convenient to read one character at a time. That will save you the hassle of moving bits of strings around. At least it makes writing an educational example easier.
// return the next value received from the arduino as an integer
int read_arduino (HANDLE hserial)
{
char buffer[4]; // any value longer than 3 digits must come
// from a faulty transmission
// the 4th caracter is used for a terminating '\0'
size_t buf_index = 0; // storage position of received characters
for (;;)
{
char c; // read one byte at a time
if (!ReadFile(
hSerial,
&c, // 1 byte buffer
1, // of length 1
NULL, // we will read exactly one byte or die trying,
// so length checking is pointless
NULL)){
/*
* This error means something is wrong with serial port config,
* and I assume your port configuration is hard-coded,
* so the code won't work unless you modify and recompile it.
* No point in keeping the progam running, then.
*/
fprintf (stderr, "Dang! Messed up the serial port config AGAIN!");
exit(-1);
}
else // our read succeded. That's a start.
{
if (c == '\n') // we're done receiving a complete value
{
int result; // the decoded value we might return
// check for buffer overflow
if (buf_index == sizeof (buffer))
{
// warn the user and discard the input
fprintf (stderr,
"Too many characters received, input flushed\n");
}
else // valid number of characters received
{
// add a string terminator to the buffer
buffer[buf_index] = '\0';
// convert to integer
result = atoi (buffer);
if (result == 0)
{
/*
* assuming 0 is not a legit value returned by the arduino, this means the
* string contained something else than digits. It could happen in case
* of electricval problems on the line, typically if you plug/unplug the cable
* while the arduino is sending (or Mr Fluffy is busy gnawing at it).
*/
fprintf (stderr, "Wrong value received: '%s'\n", buffer);
}
else // valid value decoded
{
// at last, return the coveted value
return res; // <-- this is the only exit point
}
}
// reset buffer index to prepare receiving the next line
buf_index = 0;
}
else // character other than '\n' received
{
// store it as long as our buffer does not overflow
if (buf_index < sizeof (buffer))
{
buffer[buf_index++] = c;
/*
* if, for some reason, we receive more than the expected max number of
* characters, the input will be discarded until the next '\n' allow us
* to re-synchronize.
*/
}
}
}
}
}
CAVEAT: this is just code off the top of my head. I might have left a few typos here and there, so don't expect it to run or even compile out of the box.
A couple of basic problems here. First, it is unlikely that the PC can reliably keep up with 115,200 baud data if you only read 10 bytes at a time with ReadFile. Try a slower baud rate and/or change the buffer size and number of bytes per read to something that will get around 20 milliseconds of data, or more.
Second, after you read some data put a nul at the end of it
szBuf[dwBytesRead] = 0;
before you pass it to printf or any other C string code.