I want to parse two integers that are sent from one arduino to another. The integers can be between 1 and 3 digits and they can be the same but still I must be able to tell which one is which.
Tried to search the already answerd questions regarding this but cannot find any good answear.
I have tried with this on the reciever (I print the inputstring2 on a LCD screen where I also reset the Inputstring2):
if(incomingByte == 'b'){
incomingByte = Serial.read();
while(incomingByte >= '0' && incomingByte <= '9'){
inputString2 += incomingByte;
incomingByte = Serial.read();
}
stringComplete2= true;//
The error is that I sometimes get only one of the digits if the integer is 25 I only get 2...
Sender:
Serial1.print('a');
Serial1.print(temp2);
Serial1.print('b');
Serial1.print(encoderValue);
Serial1.print('n');
When you send the value, also send a "tail character" to indicate to the receiver that the data characters has no more characters, i.e.:
Serial1.print('a');
Serial1.print(temp2);
Serial1.print('a');
Serial1.print('b');
Serial1.print(encoderValue);
Serial1.print('b');
In this way you enclose the data in a packet (a data a), so on the receiving end you test for the start of the packet, then read the remaining characters until you read the end of the packet.
Related
I'm going to write 5 bytes of data to a COM port and expect to receive 11 with the last byte of 0xFF to receive. I store the receiving bytes in pantilt_value variable.
This is a code which works:
(I receive the 11 bytes as expected with the last byte of 0xFF)
_port->write(data_pantilt, 5);
QByteArray pantilt_value = _port->readAll();
while (_port->waitForReadyRead(100))
pantilt_value.append(_port->readAll());
This is a code which doesn't work:
(I receive just a first 2 bytes)
_port->write(data_pantilt, 5);
char d;
QByteArray pantilt_value;
while (_port->waitForReadyRead(100)){
_port->read(&d,1);
pantilt_value.append(d);
if (d == 0xff)
break;
}
Can you explain why the second code doesn't work.
waitForReadyRead() returns true only when there is new data available. In your second case, the while loop has time to execute twice before all data is received. Use QSerialPort::bytesAvailable to see how much data there is to be read.
It seems that, The first time you call waitForReadyRead() to check if there is a data on serial port to read, it returns true, but you should read the whole data on the serial port after you call that method because if you fail to read the whole data after calling waitForReadyRead(), next time you call that method, it returns false, although there is still some data left to read from the port.
So my second code should be changed to something like this:
_port->write(data_pantilt, 5);
char d;
QByteArray pantilt_value;
while(_port->waitForReadyRead(100)){
while (_port->bytesAvailable() > 0){
_port->read(&d,1);
pantilt_value.append(d);
if (d == 0xff)
break;
}
}
When I test Serial.available() or Serial.available() > 0 in my loop() function, it appears to return true twice each time I enter serial data. The second time, it sets the throttle value in my code to 0. Here is the code:
#include <Servo.h>
Servo rc_rotor;
int throttle = 0; // servo position indicates throttle position.
String s_throttle_set = "Throttle set to: ";
String s_throttle_read = "Reading throttle value: ";
String s_action_error = "No action known for input value: ";
void setup()
{
rc_rotor.attach(9);
Serial.begin(9600);
while(! Serial);
Serial.println("Throttle value: 0 through 255, or 999 to read current value.");
}
void loop()
{
rc_rotor.write(throttle);
delay(20);
if (Serial.available())
{
int temp_throttle = Serial.parseInt();
if (temp_throttle >= 0 && temp_throttle <= 180)
{
throttle = temp_throttle;
Serial.println(s_throttle_set + throttle);
}
else if (temp_throttle == 999)
{
Serial.println(s_throttle_read + throttle);
}
else
{
Serial.println(s_action_error + temp_throttle);
}
}
}
Please note this code is not my final masterpiece. Much of it is from publicly available examples. Anyway, the statement if (Serial.available()) succeeds twice. By that I mean, it is true when I type in a value such as 125, and a moment later it will be 'true' again when I have typed in nothing additional. I only expect one value to go through this way. The result is that my throttle is being set to the value I enter, and then almost immediately re-set to 0. Why would something like this happen?
It turns out there is no mysterious problem with the hardware or the code, as I first suspected there was. Actually, the solution is simply to select "no line ending" in the Arduino Serial Monitor's dropdown option (by default, I guess mine was set to "New Line"). Without the additional character being inserted by the Serial Monitor, everything behaves as expected.
One thing I did not expect is how the Arduino software interprets the newline. I debugged by printing the ascii values that were making it through my if-statement. First of all, the Serial Monitor sent the number I typed in, followed moments later by ascii 10, which is the line feed character. Fine, no problem. But then Serial.parseInt() chewed on that line feed for a moment (there was a slight but noticeable delay), then fed the numeral 0 to my function. It took me a little while to figure out why. Here is an explanation from the Serial part of the Arduino Language Reference:
parseInt()
Description
Looks for the next valid integer in the incoming serial stream.
parseInt() inherits from the Stream utility class.
In particular:
Initial characters that are not digits or a minus sign, are skipped;
Parsing stops when no characters have been read for a configurable
time-out value, or a non-digit is read;
If no valid digits were read
when the time-out (see Serial.setTimeout()) occurs, 0 is returned;
So Serial.available() is true after the line feed character enters the buffer, but there is no "valid digit" according to Serial.parseInt(). Understandably... we are looking at an empty buffer that finally times out. Therefore Serial.parseInt() returns 0 and the code that follows proceeds with that value.
The code in the question assumed that the only input would be integers coming over the serial connection, which is actually a pretty fragile assumption. If you need to use Serial.parseInt in a situation where empty buffers (null), line feeds or other unexpected characters might come through, it should just be a matter of filtering the input better than I did in the example code.
I need to send two separate integers from one arduino to another. There's no problem with the distance and communication, but I'm not sure how to do this.
I need to send the two integers, each from -15000 to 15000, in a matter of 0.2 seconds.
So one arduino is sending and another one is reading.
You can try with Serial.print(int)
look at this
sorry for my bad english
Assuming you have a serial link between the two items, you can
1) send it in a text-based way:
// Sender
Serial.print(value);
// Receiver
int value = Serial.parseInt();
2) send it in a binary-based way:
byte arr[4];
// Sender
for (i=0;i<4;i++)
arr[i] = (value >> (8*(3-i))) & 0xFF;
Serial.write(arr,4);
// Receiver
if (Serial.available() > 4)
{
Serial.readBytes(arr,4);
value = 0
for (i=0;i<4;i++)
value = (value << 8) | (((int)arr[i]) & 0xFF);
}
The first way is easier, the second is more optimized and can become more reliable if you add some controls.
If you are not using a serial communication, you will have to change these functions (but probably any interface lets you send and receive byte arrays, so the second can be applied in almost any case)
I'm trying to read variable streams of characters and process them on the Arduino once a certain string of bytes is read on the Arduino. I have a sample sketch like the following, but I can't figure out how to compare the "readString" to process something on the Arduino. I would like the Arduino to process "commands" such as {blink}, {open_valve}, {close_valve}, etc.
// Serial - read bytes into string variable for string
String readString;
// Arduino serial read - example
int incomingByte;
// flow_A LED
int led = 4;
void setup() {
Serial.begin(2400); // Open serial port and set Baud rate to 2400.
Serial.write("Power on test");
}
void loop() {
while (Serial.available()) {
delay(10);
if (Serial.available() > 0) {
char c = Serial.read(); // Gets one byte from serial buffer
readString += c; // Makes the string readString
}
}
if (readString.length() > 0) {
Serial.println( readString); // See what was received
}
if (readString == '{blink_Flow_A}') {
digitalWrite(led, HIGH); // Turn the LED on (HIGH is the voltage level).
delay(1000); // Wait for one second.
digitalWrite(led, LOW); // Turn the LED off by making the voltage LOW.
delay(1000); // Wait for a second.
}
Some definitions first:
SOP = Start Of Packet (in your case, an opening brace)
EOP = End Of Packet (in your case, a closing brace)
PAYLOAD = the characters between SOP and EOP
PACKET = SOP + PAYLOAD + EOP
Example:
PACKET= {Abc}
SOP = {
EOP = }
PAYLOAD = Abc
Your code should process one character at a time, and should be structured as a state machine.
When the code starts, the parser state is "I'm waiting for the SOP character". While in this state, you throw away every character you receive unless it's equal to SOP.
When you find you received a SOP char, you change the parser state to "I'm receiving the payload". You store every character from now on into a buffer, until you either see an EOP character or exhaust the buffer (more on this in a moment). If you see the EOP char, you "close" the buffer by appending a NULL character (i.e. 0x00) so that it becomes a standard NULL-terminated C-string, and you can work on it with the standard functions (strcmp, strstr, strchr, etc.).
At this point you pass the buffer to a "process()" function, which executes the operation specified by the payload (1)
You have to specify the maximum length of a packet, and size the receive buffer accordingly. You also have to keep track of the current payload length during the "payload receive" state, so you don't accidentally try to store more payload bytes into the temporary buffer than it can hold (otherwise you get memory corruption).
If you fill the receive buffer without seeing an EOP character, then that packet is either malformed (too long) or a transmission error changed the EOP character into something else. In either case you should discard the buffer contents and go back to "Waiting for SOP" state.
Depending on the protocol design, you could send an error code to the PC so the person typing at the terminal or the software on that side knows the last command it sent was invalid or not received correctly.
Finally, the blink code in you snipped should be replaced by non-blocking "blink-without-delay"-style code (look at the example that come with the Arduino IDE).
(1) Example of a "process" function:
void process(char* cmd) {
if (strcmp(cmd, "open_valve") == 0) {
open_valve();
}
else if (strcmp(cmd, "close_valve") == 0) {
close_valve();
}
else {
print_error("Unrecognized command.");
}
}
It seems you are comparing the string in this statement:
if( readString == '{blink_Flow_A}' )
So I don't get your question re :
but I can't figure out how to compare the "readString" to process something
Are you really asking:
How do I extract the commands from an incoming stream of characters?
If that is the case then treat each command as a "packet". The packet is enclosed in brackets: {}. Knowing that the {} brackets are start and end of a packet, it is easy to write a routine to get at the command in the packet.
Once the command is extracted just go through a if-then-else statement to do what each command is supposed to do.
If I totally misunderstood your question I apologize :)
EDIT:
see http://arduino.cc/en/Tutorial/StringComparisonOperators
if( readString == "{blink_Flow_A}" ) should be correct syntax.
Since you have a statement
Serial.println( readString);
you should see the string received.
I'm writing an app to control my robot with my Android phone over Bluetooth, everything is goes well, data is echoed and verified, but I'm having some trouble with the protocol, specifically I want my robot's wheels to turn when I send a command such as s,10,100 or s,-30,-10... (values in percent).
My problem is that when I want to parse my wheel speed command on my Arduino I must parse from up to 4 separate bytes to int, for example s,-100,-100 makes my robot go backwards at full speed, but how do I parse this so I can call setSpeed(left, right); with leftand right equal to -100?
I know I can separately analyse every byte and put them together to get an integer, but it's not very elegant and there's probably a better solution to all this already, unfortunately I haven't found it yet.
EDIT
Here's my Arduino function for parsing my commands:
void parseCommand(char* command, int* returnValues)
{
// parsing state machine
byte i = 2, j = 0, sign = 0;
int temp = 0;
while(*(command + i) != '\0')
{
switch(*(command + i))
{
case ',':
returnValues[j++] = sign?-temp:temp;
sign = 0;
temp = 0;
break;
case '-':
sign = 1;
break;
default:
temp = temp * 10 + *(command + i) - 48;
}
i++;
}
// set last return value
returnValues[j] = sign?-temp:temp;
}
You call it this way when parsing something like s,100,-100 (must be \0 terminated):
char serialData[16];
void loop()
{
if(Serial.available() > 0)
{
Serial.readBytesUntil('\0', serialData, 15);
switch(serialData[0])
{
case 's':
int speed[2];
parseCommand(serialData, speed);
setSpeed(speed[0], speed[1]);
break;
}
// always echo
Serial.write(serialData);
// end of message is maked with a \0
Serial.print('\0');
// clear serialData array
memset(serialData, 0, sizeof(serialData));
}
}
Just read character by character into a state machine. It's simple and efficient.
To read in a number digit by digit, do this: Start with zero. For each digit, multiply the number by ten and add the value of the digit. So, for example, reading 97 would work like this:
You read in a digit with no prior digit, you start with 0.
You read in 9 and compute (0*10)+9 -> 9
You read in 7 and compute (9*10)+7 -> 97
You read in a non-digit, you output the 97.
Here's a fuller example s,10,100:
You start in the "ready to read command state".
You read "s", "s" is the command. You switch to the "ready to read first comma" state.
You read the first comma, you switch to the "ready to figure out the sign of the first parameter" state.
You read a digit. Since this wasn't a "-", the first parameter is positive. You set the first number to the value of the digit, 1. You are now in "reading first number" state.
You read a digit, 0. You set the first number to 1*10+0 -> 10. You are still in "reading first number" state.
You read a comma. You are now in the "ready to figure out sign of the second parameter" state.
You read 1. The second number is positive (since this wasn't a "-"). You set the second number to 1. You are in the "reading second number" state.
You read 0. The second number is now set to 1x10+0 -> 10. You are still in "reading second number" state.
You read 0. The second number is now set to 10x10+0 -> 100. You are still in "reading second number" state.
You read an end of line. You execute your results: The command is "s", the first number is positive, the first number is 10, the second number is positive, the second number is 100.
You switch back to "ready to read command" state.
I like the answer by David Swartz, but thought I'd play devil's advocate.
Reading the data in as binary can be elegant, it just depends on what you need to do with it.
In the following example, data is read from serial until it sees the binary delimiter 0X7F. The bytes read are stored in the inData char array. Take a look at the documentation for Serial.readBytesUntil()
char inData[16];
int bRead;
bRead = Serial.readBytesUntil(0x7F,inData,4);
This byte can then be cast to an integer or otherwise manipulated. Keep in mind the maximum value for this would be +/-126 because this is a signed char (127 is a delimiter and wouldn't be seen as a value).
You could access these values by with something like the following:
Serial.print("Bytes Read: ");
Serial.println(bRead);
Serial.println("First Byte");
Serial.println((int)inData[0]);
Serial.println(
map((int)inData[0],0,126,0,1024)
);
Serial.println("Second Byte");
Serial.println((int)inData[1]);
I tested this out with the following bash command (after making sure serial speeds were set properly):
echo -ne '\x01\x02\x7F' > /dev/ttyACM0
Some rough sample code that I wrote can be found Here