Transmitting Float Values Across Xbee Network - c++

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);

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);
}
}

Arduino +ESP8266 sending POST once but fails every other time

I'm using esp8266 with my arduino Mega and controlling it over serial with AT commands( i know that it is not the best way of working with ESP but I didn't know how to do it other way)...So my problem is that I have my POST request formulated and send over to my webpage ....It works fine at first try ,but after that, in every loop try, it fails...Please can someone check my code and see if you can find some error that can cause this?
This is my function for sending data:
void SendData(){
cmd = "AT+CIPSTART=\"TCP\",\"";
cmd+= server;
cmd+="\",80";
Serial1.println(cmd);
Serial.println(cmd);
delay(1000);
if(Serial1.find("OK"))
{
Serial.println("\r\nReady to send data!");
}
String retazec="cz="+cas_zaznamu; ////DATA from sensors etc.
retazec=retazec+"&tep="+t;
retazec=retazec+"&vlhv="+vv;
retazec=retazec+"&vlhp="+vp;
retazec=retazec+"&zav="+za;
retazec=retazec+"&kur="+ku;
retazec=retazec+"&vet="+ve;
retazec=retazec+"&pz="+datum_zavlaha;
int retazec_len=retazec.length();
retazec.toCharArray(retaz,70);
cmd = "POST /arduino.php"; ////POST request
cmd+=" HTTP/1.1\r\n";
cmd+="Host: myhost.com\r\n";
cmd+="Content-Type: application/x-www-form-urlencoded\r\n";
cmd+="Connection:Close\r\n";
cmd+="Content-Length: ";
cmd+=retazec_len;
cmd+="\r\n\r\n";
int size=cmd.length()+retazec_len+2;
Serial1.print("AT+CIPSEND=");
Serial1.println(size);
Serial.print("AT+CIPSEND=");
Serial.println(size);
delay(2000);
if (Serial1.find(">")){
Serial.println("Sending data...");
} else {
Serial1.println("AT+CIPCLOSE");
Serial.println("COnnection closed");
return;
}
Serial.print(cmd);
Serial1.print(cmd);
for(int i=0;i<=retazec_len;i++){
Serial.print(retaz[i]);
Serial1.print(retaz[i]);
}
Serial1.print("\r\n");
if(Serial1.find("OK"))
{
Serial.println("Succesfuly send!");
}
ReadString(); /// emptying the buffer by reading serial1
delay(5000);
Serial.println("-----end");
}
Also I have different function for GET request ,very similar to the one above , and that one worked multiple times in a row(dont want to say every time bcs it was running only for few minutes).
Please please any suggestions will be deeply appreciated. :)
My educated guess:The String class in combination with at commandsTry to get rid of the String class in webbased scenarios. Reason: You want to have a stable environment running for a long time. String class uses heap memory to dynamicly build and destroy the underlying structures it needs for e.g. append strings (... = .. + .. + ..). As there is no so called garbagge collection (and would have not enough memory anyway) the relativeley small memory is cut into small units, in which (at a certain length) the String does not fit anymore -> crash, reset => lost POST or GET request.Use fixed global char array(s) to build your messages, these are compiled into the flash and stop the "memory bleeding". Enclosed an example (although I dont understand - from your language - the name or the content of variables and with no type given I had to guess)
char retazec[256] = {'\0'}; /* Defined globally - Used for retazec functions max 255 chars */
char cmd[512] = {'\0'}; /* Defined globally - Used for POST/GET functions max 511 chars */
char numBuffer[16] = {'\0'}; /* Defined globally - Used for uint32_t or smaller number conversions to char */
unsigned long timeStamp = 0;
unsigned long delayTime = 2000;
setup(){...}
//The parts you gave "translated"into char manuipulation
const char* cmdStart[] = "POST /arduino.php HTTP/1.1\r\n Host: myhost.com\r\nContent-Type: application/x-www-form-urlencoded\r\nConnection:Close\r\nContent-Length: ";
const char* cmdEnd[] = "\r\n\r\n";
strcpy (retazec, "cz=");
itoa(cas_zaznamu, numBuffer, 10); // convert int DATA from sensors etc.
// If its a float use this command
// dtostrf(floatvar, StringLengthIncDecimalPoint, numVarsAfterDecimal, charbuf);
// dtostrf(cas_zaznamu, 3, 2, numBuffer); // -> xx.xx
strcat(retazec, numBuffer);
strcat(retazec, "&tep=");
itoa(t, numBuffer, 10);
// or dtostrf(t, 4, 2, numBuffer); // -> xxx.xx
strcat(retazec, numBuffer);
strcat(retazec, "&vlhv=");
....
// ... till datum_zavlaha;
int retazec_len=strlen(retazec); // gives you the length
// not needed we have a char array allready retazec.toCharArray(retaz,70);
strcpy(cmd, cmdStart);
iota (retazec_len, numBuffer);
strcat(cmd, numBuffer);
strcat(cmd, cmdEnd);
int size=strlen(cmd)+retazec_len+2;
if (millis() - timeStamp > delayTime) {
Serial1.print("AT+CIPSEND=");
Serial1.println(size);
Serial.print("AT+CIPSEND=");
Serial.println(size);
timeStamp = millis();
}
// NO NEVER delay(2000);
if (Serial1.find(">")){
Serial.println("Sending data...");
} else {
Serial1.println("AT+CIPCLOSE");
Serial.println("COnnection closed");
return;
}
The second issue is delay (it stops processing dead in its tracks) So the cpu waits in your case 2 sec before restarting - not a clever idea when using communication protocols. I implemented a non-blocking delay - if you need it somewhere else as I said you only gave fragments of code
EDIT after OPs feedback
String class as a whole should be avoided in dynamic communication scenarios so in all parts of the programm.Should I use one big string (small s = char array) thats just coping what the original code does but instead of String with char array. So imho the structure has just to be adapted to char array without big changes (exept expicitly converting numbers to char) Btw the same takes place when you add a variable to String
uint8_t aNumber = 12;
String myBigString = "A number is " + aNumber;
does internally in the String library the same as
uint8_t aNumber = 12;
char numBuffer [16] = {'\0'} ;
char myBigString [32] = {'\0'} ;
strcpy (myBigString, "A number is ");
iota (aNumber, numBuffer, 10);
strcat (myBigString, numBuffer);
The difference is - you write the lines instead of lazely using a bad library but with full control over memory and the advantage to compile it to flash, saving memory. Const char are actually called via pointer - so for later there are functions to get only certain parts of an array handy to create variable messages out of one big array.After a code analysis on github there is one other big problem: The use of blocking delay():
loop() {
delay(1000);
// lot of code
delay(3000);
}
replace with a non blocking delay
unsigned long timeStamp = 0;
setup(){}
loop() {
if (millis() - timeStamp > 4000) {
// lot of code
timeStamp = millis(); // reset the timer
}
}
and as written before get rid of all Strings (e.g)
///////////PREMENNE PRIJIMANÝCH ÚDAJOV///////
String mode;
String inzavlaha;
String inkurenie;
String invetranie;
String invlhkost_p;
String invlhkost_v;
String incas;
String intrvanie;
String inopakovanie;
String inteplota;
and as a final tio.If you want worldwide help, start to write all of your program in English (variables and comments) it makes it easier to help.

using write() function in C/C++ on Linux to write 70kB via UART Beaglebone Black

I'm trying to write a image via UART on Beaglebone Black. But when I use the write() function in library .
int write(int handle, void *buffer, int nbyte);
Regardless of the agurment nbyte has int type, I can not transfer 70kB at once. I displayed the number of byte which is transfered, and the result is the number of byte = 4111.
length = write(fd,body.c_str(),strlen(body.c_str())); //
cout<<length<<endl; // result length = 4111;
cout<<strlen(body.c_str())<<endl; // result strlen(body.c_str()) = 72255;
I hope to hear from you!
The write call does not assure that you can write the amount of data supplied, that's why it as an integer as its return, not a Boolean. The behavior you see is actually common among different operating systems, it may be due to the underline device might does not have sufficient buffer or storage for you to write 70kb. What you need is to write in a loop, each write will write the amount that is left unwritten:
int total = body.length(); // or strlen(body.c_str())
char *buffer = body.c_str();
int written = 0;
int ret;
while (written < total) {
ret = write(fd, buffer + written, total - written);
if (ret < 0) {
// error
break;
}
written += ret;
}

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

Missing bytes when reading serial data(sent via arduino/bluetooth) with .cpp program

I have been sending serial data with an arduino via bluetooth to my computer. Here is the sample arduino code.
long interval=10;
long previousMs=0;
int k=1000;
int K=9999;
void setup() {
Serial1.begin(115200);
}
void loop() {
unsigned long currentMs = millis();
if(currentMs - previousMs > interval) {
previousMs = currentMs;
k=k+1;
Serial1.println(k);
if(k>K){
k=1000;
}
}
}
This is the relevant part of my .cpp code that reads the data. I changed it a bit to print out the number of bytes read. It should be 6 every time (4 digits, carriage return, new line), but every once in a while it will give 5,4,3,2, or 1.
int read_bt(PORTTYPE port, char *buf, int bytes_to_read)
{
COMMTIMEOUTS timeout;
DWORD n = 0;
BOOL r;
FILE *fp;
fp = fopen("C:\\Users\\Myname\\Documents\\Visual Studio 2013\\Projects\\Project2\\Debug\\BT_Constant.txt", "w+t");
GetCommTimeouts(port, &timeout);
timeout.ReadIntervalTimeout = MAXDWORD; // non-blocking
timeout.ReadTotalTimeoutMultiplier = 0;
timeout.ReadTotalTimeoutConstant = 0;
SetCommTimeouts(port, &timeout);
while (1){
// Get and clear current errors on the port.
if (!ClearCommError(fd, &dwErrors, &comStat))
// Report error in ClearCommError.
exit(0);
// Get error flags.
fDNS = dwErrors & CE_DNS;
fIOE = dwErrors & CE_IOE;
fOOP = dwErrors & CE_OOP;
fPTO = dwErrors & CE_PTO;
fMODE = dwErrors & CE_MODE;
fBREAK = dwErrors & CE_BREAK;
fFRAME = dwErrors & CE_FRAME;
fRXOVER = dwErrors & CE_RXOVER;
fTXFULL = dwErrors & CE_TXFULL;
fOVERRUN = dwErrors & CE_OVERRUN;
fRXPARITY = dwErrors & CE_RXPARITY;
if (comStat.cbInQue != 0){
// comStat.cbInQue bytes have been received, but not read
r = ReadFile(fd,
buf,
bytes_to_read,
&n,
NULL);
}
fprintf(fp,"%d\n", n);
printf("%d\n", n);
}
}
I thought about sharing the output text file but I can't think of the best way to do that. Basically it is just a ton of "6"'s and its scattered with 1-5 in various spots.
I am working on an project with EEG data so a very high resolution and low latency is required. I was wondering if there was an issue with any of my code or if it was more likely a hardware issue with the bluetooth module I am using (HC-05 BT 2.0EDR).
If anyone can shed some light on to why this is happening I would definitely appreciate it!
The OS sends a "received new bytes on the interface" whenever it wants. If you send, let's say, the string "Hello" (5 bytes), it can (and usually does this) just notify you once that you received 5 bytes, but that's not guaranteed. It can notify you the first two bytes and then the other three, or 3-2, or even 1-1-1-1-1.
That's why you should see the return value of ReadFile which, I suppose, gives you the actual number of read bytes, and then loop until you read every byte you need.
We don't know what is the actual output of your program, but I bet that whenever you found some "5-4-3-2-1" they were paired in such a way that the sum was exactly 6..
Anyway, you say that you need a "low latency system". Then avoid printing it in text format (6 bytes), but use the binary mode (for any number under 65536 you need just two bytes).
Bye