Im trying to send inputs to Arduino MEGA using the monitor. Ive noticed that 1/6 times, the Serial skips 1 or more letters in my input. Ive tried Serial.read() and Serial.readStringUntil() but both skip input. I tried putting delay after the Serial.read() but it does nothing. I also tried doing a Serial.flush in the if(complete){...} code block but to no avail.
In this picture, "A**" was sent correctly (Ive noticed it always has as it is the 1st monitor input). But subsequent commands like the "s**100" was sent as "s*0". Is there misuse of the Serial class here? Is there a misconfiguration maybe in using the Serial monitor? (No line ending). Could it be that using other custom classes interfere with the Serial even if it didnt explicitly interact with it?
//===========================================THE IMPORTANT PART===============================================
void loop() {
digitalWrite(13, HIGH);
while (Serial.available()){
String temp = Serial.readStringUntil(';');
Serial.println(temp);
command = temp.substring(0,3);
param = temp.substring(3).toInt();
complete = true;
Serial.println("temp "+temp);
Serial.println("comm "+command);
Serial.println("para "+command);
}
//=============================================================================================================
if(complete){
Serial.println("complete");
if(command == MODE_SOLID || command == MODE_GRADIENT || command == MODE_OFF){
current_mode = command;
}
else if(command == COMMAND_BRIGHTNESS){
current_brightness = param;
}
else if(command == COMMAND_SATURATION){
current_saturation = param;
}
else if(command == COMMAND_COLOR){
current_color = param;
}
else if(command == COMMAND_RANDOM_BRIGHTNESS_UPPERLIMIT){
current_random_brightness_upper_limit = param;
}
else if(command == COMMAND_RANDOM_BRIGHTNESS_LOWERLIMIT){
current_random_brightness_lower_limit = param;
}
else if(command == COMMAND_RANDOM_SATURATION_UPPERLIMIT){
current_random_saturation_upper_limit = param;
}
else if(command == COMMAND_RANDOM_SATURATION_LOWERLIMIT){
current_random_saturation_lower_limit = param;
}
else if(command == COMMAND_RANDOM_COLOR_UPPERLIMIT){
current_random_color_upper_limit = param;
}
else if(command == COMMAND_RANDOM_COLOR_LOWERLIMIT){
current_random_color_lower_limit = param;
}
else if(command == COMMAND_COLOR){
current_color = param;
}
complete = false;
command = "";
param = 0;
}
if(current_mode == MODE_SOLID){
solid.setBrightness(current_brightness);
solid.setSaturation(current_saturation);
solid.setColor(current_color);
solid.runPattern();
}
else if(current_mode == MODE_GRADIENT){
blinkSolid.setCurrentRandomBrightnessLowerLimit(current_random_brightness_lower_limit);
blinkSolid.setCurrentRandomBrightnessUpperLimit(current_random_brightness_upper_limit);
blinkSolid.setCurrentRandomSaturationLowerLimit(current_random_saturation_lower_limit);
blinkSolid.setCurrentRandomSaturationUpperLimit(current_random_saturation_upper_limit);
blinkSolid.setCurrentRandomColorLowerLimit(current_random_color_lower_limit);
blinkSolid.setCurrentRandomColorUpperLimit(current_random_color_upper_limit);
blinkSolid.runPattern();
}
else if(current_mode == MODE_OFF){
strobePalette.runPattern();
//fill_solid( leds, NUM_LEDS, CRGB::Black);
//FastLED.show();
}
}
I've experienced similar issues with physical devices, most of the times in harsh environments or using defective wiring.
I tested your code using tinkercad with an Arduino Uno, only the communication part. This is the code I tested:
bool complete;
String command;
int param;
void setup()
{
Serial.begin(9600);
}
void loop()
{
digitalWrite(13, HIGH);
while (Serial.available()){
String temp = Serial.readStringUntil(';');
Serial.println(temp);
command = temp.substring(0,3);
param = temp.substring(3).toInt();
complete = true;
Serial.println("temp "+temp);
Serial.println("comm "+command);
Serial.println("para "+ String(param)); //I changed this line in order to see the value of "param" in the serial monitor
}
if(complete){
Serial.println("complete");
complete=false;
command="";
param=0;
}
}
I tested the code sending the string A**100;B**101;C**102;D**103; all of the parts arrived ok and they were well decoded. This is the TinkerCad output:
A**100
temp A**100
comm A**
para 100
B**101
temp B**101
comm B**
para 100
C**102
temp C**102
comm C**
para 100
D**103
temp D**103
comm D**
para 100
I also tested the code using a physical Arduino uno, and It worked as well as in Tinkercad. This is what I would do:
Let the code only with the communication part, as I did, and see how it behaves. If your code behaves ok only with the communication part, then you have something interfering in the rest of the code. It is hard to tell what could be without knowing the code of the custom clases.
If you are connecting a physical arduino to the usb port of PC, change that cable. Some defective cables may work weird and cause that kind of issues.
If you will be installing your device in a harsh environment, try to make your code resistant to those kind of errors, it is most likely that they will be present anyway. In such scenarios, I have used a starting character, an ending character and a fixed length, something like #A**100;#B**101; where # is the starting character, the semicolon (;) is the ending character, and all the commands are eight characters long. I discard all of the commands that does not fulfill those params. Using CRC is another option, but in most cases it is enough with the simple pattern I just described.
Related
I have a processing sketch which needs to set up 2 connections with USB devices. I cannot tell in advance which device is USB0 and which is USB1. (not that I am aware off atleast)
One of the devices awnsers with hello the other one does not answer at all. Therefor I have written code with a simple timeout. In the setup I check continously if there are bytes to read. But both a while and an if statement yield incorrect results
while( dccCentral.available() < 5 ) {
if( dccCentral.available() >= 5) break;
if(millis() > 5000 ) {
println("timeout occured");
println(dccCentral.available());
break;
}
}
These lines are in setup. The text "timeout occured" is always printed. Underneath it, the result of dccCentral.available() is printed. This number is 12 which is correct.
regardless, if dccCentral.available() prints 12 at that time. The first if-statement:
if( dccCentral.available() >= 5) break;
should already have break'ed out of the while loop before this time-out should occur. The while-loop itself should also quit itself when 5 or more bytes are received.
Why do both these lines
while( dccCentral.available() < 5 ) {
if( dccCentral.available() >= 5) break;
fail?
Personally I try to avoid while loops unless there isn't another way (e.g. inside a thread) and that is avoid both logic pitfalls and messing with the lifecycle of other objects that might need a bit of time to initialise.
If you send strings from Arduino and also use println() you could init the port to easily catch that using Serial's bufferUntil() in conjuction with serialEvent() to finally readString().
Once you start getting data in, you could:
use references to the serial ports you're after and a couple of extra ones until you know which port is which
use a boolean "toggle" to only handle the "hello" once
if the hello was received, you can use the serialEvent() Serial argument to assign dccCentral and by process of elimination assign the other port
Here's a commented sketch to illustrate the idea:
import processing.serial.*;
// be sure to set this to the baud rate your device use with Arduino as well
final int BAUD_RATE = 115200;
// reference to Serial port sending "Hello" (when that get's detected)
Serial dccCentral;
// reference to the other Serial port
Serial otherDevice;
// temporary references
Serial usb0;
Serial usb1;
// 'toggle' to keep track where the hello was received and handled or not (by default initialised as false)
boolean wasHelloReceived;
void setup(){
usb0 = initSerial("/dev/ttyUSB0", BAUD_RATE);
usb1 = initSerial("/dev/ttyUSB1", BAUD_RATE);
}
Serial initSerial(String portName, int baudRate){
Serial port = null;
try{
port = new Serial(this, portName, baudRate);
// if sending strings and using println() from Arduino
// you can buffer all chars until the new line ('\n') character is found
port.bufferUntil('\n');
}catch(Exception e){
println("error initialising port: " + portName);
println("double check name, cable connections and close other software using the same port");
e.printStackTrace();
}
return port;
}
void draw(){
background(0);
text("wasHelloReceived: " + wasHelloReceived + "\n"
+"dccCentral: " + dccCentral + "\n"
+"otherDevice: " + otherDevice , 10 ,15);
// do something with the devices once they're ready (e.g. send a message every 3 seconds)
if(millis() % 3000 == 0){
if(dccCentral != null){
dccCentral.write("ping\n");
}
if(otherDevice != null){
otherDevice.write("pong\n");
}
}
}
void serialEvent(Serial port){
try{
String serialString = port.readString();
// if the received string is not null, nor empty
if(serialString != null && !serialString.isEmpty()){
// for debugging purposes display the data received
println("received from serial: " + serialString);
// trim any white space
serialString = serialString.trim();
// check if "hello" was received
if(serialString.equals("hello")){
println("hello detected!");
// if the dccCEntral (hello sending) serial port wasn't assigned yet, assign it
// think of this as debouncing a button: setting the port once "hello" was received should happen only once
if(!wasHelloReceived){
// now what dccCentral is found, assign it to the named reference
dccCentral = port;
// by process elimiation, assign the other port
// (e.g. if dccCentral == usb0, then other is usb1 and vice versa)
otherDevice = (dccCentral == usb0 ? usb1 : usb0);
/*
the above is the same as
if(dccCentral == usb0){
otherDevice = usb1;
}else{
otherDevice = usb0;
}
*/
wasHelloReceived = true;
}
}
}
}catch(Exception e){
println("error processing serial data");
e.printStackTrace();
}
}
Note the above code hasn't been tested so it may include syntax errors, but hopefully the point gets across.
I can't help notice that USB0/USB1 are how serial devices sometimes show up on Linux.
If you're working with a Raspberry Pi I can recommend a slightly easier way if you're comfortable with Python. The PySerial has a few tricks up it's sleeve:
You can simply call: python -m serial.tools.list_ports -v which will list ports with extra information such as serial number of the serial converter chipset. This could be useful to tell which device is which, regardless of the manufacturer and USB port used
Other than the serial port name/location, it supports multiple ways (URLs) of accessing the port with a very clever: hwgrep:// will allow you to filter a device by it's unique serial number
Here's a basic list_ports -v output for two devices with the same chipset:
column 1
/dev/ttyUSB9
desc: TTL232R-3V3
hwid: USB VID:PID=0403:6001 SER=FT94O21P LOCATION=1-2.2
column 2
/dev/ttyUSB8
desc: TTL232R-3V3
hwid: USB VID:PID=0403:6001 SER=FT94MKCI LOCATION=1-2.1.4
To assign the devices using serial you would use something like:
"hwgrep://FT94O21P"
"hwgrep://FT94MKCI"
Update
It might help to step by step debug the system and try one port a time.
The idea is to get the bit of code reading the expected serial string tight.
Here's a basic example that should simply accumulate one char at a time into a string and display it:
import processing.serial.*;
Serial port;
String fromSerial = "";
void setup(){
size(300,300);
port = initSerial("/dev/ttyUSB0", 115200);
}
Serial initSerial(String portName, int baudRate){
Serial port = null;
try{
port = new Serial(this, portName, baudRate);
// if sending strings and using println() from Arduino
// you can buffer all chars until the new line ('\n') character is found
port.bufferUntil('\n');
}catch(Exception e){
println("error initialising port: " + portName);
println("double check name, cable connections and close other software using the same port");
e.printStackTrace();
}
return port;
}
void draw(){
if(port != null){
if(port.available() > 0){
char inChar = port.readChar();
fromSerial += inChar;
if(inChar == '\n'){
println("newline encountered");
println(fromSerial.split("\n"));
}
}
}
background(0);
text("from serial:" + fromSerial, 10,15);
}
If the data from dccCentral comes in a expected: great, the code can be simplfied and right conditions applied to filter the device in the future,
otherwise it should help pin point communication issues getting the "hello" in the first place (which would be 6 bytes ("hello"(5) + '\n') if sent with Serial.println() from Arduino)
Regarding Python, no problem at all. Should the idea help in the future you can check out this answer. (AFAIK Processing Serial uses JSSC behind the scenes)
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).
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();
}
}
}
I am trying to read two pins from a c8051f040 controller.
Reading the port directly works, but saving the same port value to a variable does not work even though the debugger shows the correct value.
// This works
if((P1 & 0xF0) == 0xa0)
{
YEL_LED = 1; //Turn on
}
else
{
YEL_LED = 0; //Turn off
}
// This does not work even though the debugger
// shows the correct value 0xa0 for the var
ORange = (P1 & 0xF0);
if(ORange == 0xa0)
{
YEL_LED = 1; //Turn on
}
else
{
YEL_LED = 0; //Turn off
}
Is this a KEIL c51 bug or is something being optimized away.
The variable was declared as char which is signed. It should be unsigned.
I got fooled by the debugger which was showing the the watch variable as unsigned.
I have a problem of getting my Processing app to start when I'm using the Arduino library to work on it. I'm thinking just installing Linux on a partition of my hard drive to get it to work. I see the library text load but then it freezes up. I'm also using an anti virus called kaspersky. Here's my source code for the processing
import processing.serial.*;
import cc.arduino.*;
Arduino arduino= new Arduino(this, Arduino.list()[0], 57600);
int ledPin = 13;
boolean greenFlash = false;
boolean blueFlash = false;
boolean redFlash = false;
void setup()
{
size(600,600);
//println(Arduino.list());
//arduino = new Arduino(this, Arduino.list()[0], 57600);
arduino.pinMode(ledPin, Arduino.OUTPUT);
arduino.digitalWrite(ledPin, Arduino.HIGH);
}
void draw()
{
if(redFlash){
arduino.digitalWrite(12, Arduino.HIGH);
}
delay(mouseY);
arduino.digitalWrite(12, Arduino.LOW);
delay(mouseX);
if(greenFlash){
arduino.digitalWrite(11, Arduino.HIGH);
}
delay(mouseY);
arduino.digitalWrite(11, Arduino.LOW);
delay(mouseX);
if(blueFlash){
arduino.digitalWrite(10, Arduino.HIGH);
}
delay(mouseY);
arduino.digitalWrite(10, Arduino.LOW);
delay(mouseX);
}
void keyPressed(){
//flash = true;
if (key == 'R' || key == 'r'){
redFlash=true;
}
if (key == 'B' || key == 'b'){
blueFlash=true;
}
if (key == 'G' || key == 'g'){
greenFlash=true;
}
}
void keyReleased(){
//flash = false;
if (key == 'R' || key == 'r'){
redFlash=false;
}
if (key == 'B' || key == 'b'){
blueFlash=false;
}
if (key == 'G' || key == 'g'){
greenFlash=false;
}
}
The arduino is loaded up with the standard firmata example to allow this to run. This has worked on mac so I'm sure it's a windows bug. I've looked though some forums and haven't found anything. If anyone can help that would be awesome.
EDIT:
it is the processing app that is freezing up. it starts but then the window dose not pop up. sometimes i have to go into task manager to kill it. also the processing compiler is 1.5.1
Display 0 does not exist, using the default display instead.
WARNING: RXTX Version mismatch
Jar version = RXTX-2.2pre1
native lib Version = RXTX-2.2pre2
after this message it freezes up and dose nothing. iv wait about 5 minutes nothing happens.
Do some diagnostics: simplify
Are you able to run other basic Processing sketches (non-Arduino/non-Serial com)? (Java issue)
Are you able to connect and upload sketches to the Arduinio using the Arduino IDE? (COM issue)
If there answer to either of those is no, then you have a place to start looking.
I have read on the Arduino site that installed drivers for Windows 7 is a bit complicated. If you can't connect to the Arduinio using the IDE, then work that out first.