Timing Issue Using PySerial with Arduino Uno - arduino

Here's the big picture:
I'm trying to control a stepper motor by recording a set of positions and then playing them back. To control the steppers I am using AccelStepper.
Since the movement data is large I need to store it on my Mac and send it over to the Arduino using the Serial connection.
Also, I can't afford delays because of the way AccelStepper works.
Here's the issue:
The code below works when I insert a delay of about 60ms or more. However, this screws up AccelStepper.
My understanding of this is that the first while loop "listens" to the serial line. If there is nothing to read, I send an 'A' to the Mac to request some data. This loop breaks when there is data available to read.
The second loop reads the serial line until encountering a newline character. This code works with the delay and does not without a delay.
Does that make sense?
Thank-you.
================================
if (stepper.distanceToGo() == 0)
{
while (Serial.available() <= 0) { // Ask Mac for more data.
Serial.print("A");
delay(60); // Argh line!
stepper.runSpeedToPosition();
}
while(Serial.available() > 0) { // There's info on the serial line
character = Serial.read();
content.concat(character);
if (character == '\n') break; // Keep reading until newline
stepper.runSpeedToPosition();
}

Without delay, the while loop will take "all" your system (CPU) resources, actually delaying the interrupt from the serial line. The 60 is very specific value though.
So an option is to rewrite the loop and test if this helps:
if (stepper.distanceToGo() == 0) {
while (true) {
if(Serial.available() <= 0) { // Ask Mac for more data.
Serial.print("A");
stepper.runSpeedToPosition();
} else {
// the case for (Serial.available() > 0) There's info on the serial line
character = Serial.read();
content.concat(character);
if (character == '\n') break; // Keep reading until newline
stepper.runSpeedToPosition();
}
}
}

Related

Stuck in a for loop in Arduino IDE

I'm using Arduino to look for I2C addresses, and half way through this new glitch appeared, and I don't know if it's the IDE or if I'm going insane.
I know most of this probably isn't important, but I don't know what is going on so here is my entire loop.
void loop(){
byte error, address;
int nDevices;
Serial.println("Scanning...");
nDevices = 0;
for(address = 0; address <= 255; address++ )
{
Wire.beginTransmission(address);
error = Wire.endTransmission();
Serial.print(address);
Serial.print("|");
Serial.println(error);
if (error == 0)
{
Serial.print("I2C device found at address 0x");
if (address<16)
Serial.print("0");
Serial.print(address, HEX);
Serial.println(" !");
nDevices++;
}
else if (error==4)
{
Serial.print("Unknow error at address 0x");
if (address<16)
Serial.print("0");
Serial.println(address,HEX);
}
delay(200);
//Serial.println(address);
}
delay(150);
Serial.println("Exiting");
if (nDevices == 0)
Serial.println("No I2C devices found\n");
else
Serial.println("done\n");
delay(30000);
exit(0);
}
As you can see in the picture I included the for loop returns to address=0 without printing anything after it, or before it in the loop(). Why is this happening?
I'm sure it has to do with you declaring address as a byte which is can be the integer 255 at max. What happens is if you add 1 to a byte value of 255, it loops around again to 0.
What happens when address = 255 and when the for loop goes back up to check the conditioning, 255 passes and address++ adds 1 to address so now address = 0.
https://www.arduino.cc/en/reference/byte
Alternatively, you could use a while loop instead and increment the address counter at the very end of the loop, followed by a test to see if it has wrapped around to zero. On the first run through of the loop, the address counter will be 1, so the loop will continue until the counter has reached 255 when the increment will wrap it around to zero and execution reaches the break statement.
byte address = 0;
while( true ) // Creating an unconditional loop
{
// Run your test here
address++;
if( !address ) // If address has wrapped around to 0, exit the loop
{
break;
}
}
...or a do/while loop, which does the same thing but may be slightly larger in some cases.
byte address = 0;
do
{
// Run your test here
address++;
} while( address ); // The loop will continue until address becomes zero again
Depending on your microcontroller, this may take a few bytes more program space though it looks like the while-loop ends up the same size as the for-loop on an ATMega328. (YMMV, of course)
On 8-bit microcontrollers however, code to manipulate ints will be slower and take up more space, so depending on your code you may still be better off by being able to stick with using a byte for your address.

Arduino command timeout

I'm currently working with a Arduino to forfill one of my DIY projects.
As it currently stands, I have my fingerprint scanner (GT-511C3) connected to my Arduino and that works great. I'm able to verify enrolled fingerprints.
The verifying of the finterprints happends via Raspberry Pi command (whom is initiated by a button press)
Logically, this means, when the button is pressed, the Raspberry Pi sends a 'validate' command to the Arduino, whom in return ask the Fingerprint scanner to run the validate command.
However, I would like to have a timeout after the validate command it sent. The timeout needs to make sure that if the button pressed (and the validate command is initated) but no one puts their finger on the machine it timeouts and reverts back to a state where it waits for the validate command.
I'm not able to complete this. This is the code I've tried:
#include "FPS_GT511C3.h"
#include "SoftwareSerial.h"
FPS_GT511C3 fps(4, 5);
int val = 0;
void setup()
{
Serial.begin(9600);
delay(100);
fps.Open();
fps.SetLED(false);
}
void loop(){
if (Serial.available() > 0) {
Continue:
if(Serial.find("validate")){
fps.SetLED(true);
do {
++val;
delay(100);
}
while(fps.IsPressFinger() == false || val > 150);
if(val <= 150){
fps.SetLED(false);
goto Continue;
}
if (fps.IsPressFinger()){
fps.CaptureFinger(false);
int id = fps.Identify1_N();
if (id <200)
{
Serial.print("Verified ID:");
Serial.println(id);
fps.SetLED(false);
}
else
{
Serial.println("Finger not found");
fps.SetLED(false);
}
}
else
{
Serial.println("Please press finger");
}
delay(100);
}
}
}
The code otherwise works fine, if the finger is placed and validated, it turns off and goes back to waiting for another validate command.
Any help would be greatly appreciated!
First, get rid of the label and goto. There is no justification for it here; it's considered bad programming practice and shouldn't be used unless you know exactly what you're doing. Only in Assembly is it okay to use goto (equivalent to JMPs) liberally.
Next, your while condition is wrong. If you try to interpret it, you'll notice it doesn't make any sense:
Wait for as long as nobody has placed a finger or if the timeout has expired.
What you probably want is:
Wait for as long as nobody has placed a finger and the timeout has not expired.
which translates to:
while(fps.IsPressFinger() == false && val < 150);
The IF condition that follows, is also wrong and should mean:
if the timeout has expired
translating to:
if(val >= 150){
fps.SetLED(false);
val = 0;
continue;
}
Notice the use of the continue keyword which restarts a loop. To make it legit, change if (Serial.available() > 0) to while (Serial.available() > 0).

How to read string using Serial.read outside of loop()?

I want to read a String in Arduino from the keyboard outside of the loop() method.
I have the following method:
void readFromKeyboard(byte arrayAddress[])
{
int count = 0, i = 0;
while ((count = Serial.available()) == 0);
while (i<count)
{
arrayAddress[i++] = Serial.read();
}
}
In the loop() method I am calling it like:
readFromKeyboard(userInput);
where userInput is a byte[];
The problem is that when I input more than one characters it read the 1st character initially and it call the readFromKeyboard again an then reads the rest.
Example; if I input "asdf":
--the 1st time it will do ==> userInput = "a"
--the 2nd time it will do ==> userInput = "sdf"
I have tryed many things but the same happens again and again...
Any suggestions??
So that's what worked:
In the loop():
while(Serial.available() == 0);
delay(100);
readInputFlag = readFromKeyboard(userInput);`
And in the readFromKeyboard method:
void readFromKeyboard(byte arrayAddress[])
{
int i = 0;
while (Serial.available() > 0)
{
arrayAddress[i++] = Serial.read();
}
}
This delay, in the loop method, somehow makes the Serial get the whole string instead of just the first letter.
I know you got it working, but I wanted to show you something that I use to deal with this issue. This is a two-tiered delay system for catching bytes that come in a bit late for whatever reason. It's designed to minimize the delay needed to accomplish that task.
int received_length = 0;
byte serial_incoming_buffer[200];
while(Serial.available()) {
serial_incoming_buffer[received_length++] = Serial.read();
if(!Serial.available()) {
delay(3);
if(!Serial.available()) {
delay(20);
}
}
}
Sometimes the Arduino falls behind in picking up serial from the sender and sometimes it grabs serial too fast. Sometimes the sender lags a little bit. This code will wait 3 ms for more bytes, and if they come in it goes back to receiving as many as are available having only had that very brief delay. This repeats as necessary, then when 3 ms goes by without anything being available, it waits a bit longer (20 ms here) for more bytes. If nothing comes in after the long delay, then the transmission is most likely done and you can safely move on.
I recommend tweaking the delays based on your baud rate.

SD card image transfer using xbee

I trying to read SD card image from arduino (20KB - JPEG -using SD library) and transfer through Xbee (series 2) Due to limitation on xbee, have to break to 60 bytes and send until the complete file send. I think, the image stored in ASCII character.
void setup() {
Serial.begin(115200);
if (!SD.begin()) {
Serial.println("begin failed");
return;
}
file = SD.open("PIC00.JPG");
}
void loop() {
Serial.flush();
char buf[64];
if(file) {
while (file.position() < file.size())
{
while (file.read(buf, sizeof(buf)) == sizeof(buf)) // read chunk of 64bytes
{
Serial.write(buf); // Send to xbee via serial
delay(50);
}
}
file.close();
} }
But this method, i can not see complete image transfer at Serial Write. After a while, i came to know the start of image is Y (ascii chracter) and U (end character). I can see only end start character Y can not see the proper end character.
Please advise...trying hard solve this issue. Big Thanks...
The JPEG is actually binary data. To send it, use the version of Serial.write() that includes a length parameter for the number of bytes to send. Otherwise, it thinks you're trying to send a null-terminated string.
(Declare bytesread as a byte at the top of your function.)
while ((bytesread = file.read(buf, sizeof(buf))) > 0)
{
Serial.write(buf, bytesread); // Send to xbee via serial
delay(50);
}
Also note that the delay might not be sufficient -- you should really be using a serial port with hardware flow control (monitoring /CTS from the XBee module) so you know when it's clear to send data to it.

How to capture a variable stream of characters and process them on a Arduino using serial?

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.

Resources