Unable to receive correct data from serial

Hello everyone,

I am working on a project of mine. I am trying to send via serial some data from a raspberry pi script to my arduino UNO. Notice that I have tried the following at my linux computer and it is working. However when I run the python script to the raspberry it is not working. As a result i am sure that the problem is related to the Raspberry PI board.

The basic Idea is to use the RPI and send a number or a string or some bytes (eg. 0 for lights off and 1 for lights on). After receiving those bytes in the arduino, it controls a relay to open or close the circuit. Quite simple. But it is not working. All I have done is to randomly open or close or blink the lights. I have no Idea what arduino is receiving. Any ideas? How should I continue? Do I need hardware interrupts? What exactly is going on my arduino?

ADD: When I serial write to activate relay it is working, I am deactivating and it is working. Then If I try to activate again it activates for 1 sec and deactivates... I mean that it is working for only once and then it just activate the relay for 1 sec only. (in case it helps)

I have connected my arduino and my rpi with a simple USB cable. I am not using TX/Rx. Also, The pins I use ar 2, 3.

Arduino code:

#define relayPin1 2
#define relayPin2 3

void setup() {
    Serial.begin (9600);
    pinMode(relayPin2, OUTPUT);
    pinMode(relayPin1, OUTPUT);
}


void loop() {
  if (Serial.available()) {
    String x = Serial.readString();
    
    if(x == "7") {
      Serial.println('0');
      delay(10);
      digitalWrite(relayPin1, LOW);
      digitalWrite(relayPin2, LOW);
    }else if(x == "8") {
      Serial.println('0');
      delay(10);
      digitalWrite(relayPin1, HIGH);
      digitalWrite(relayPin2, HIGH);
    }
    delay(10);
  }
}

thank you for your time,
Vasilis

Please check what is x when you entered 7 .
String x = Serial.readString();
Serial.println(x);

try to look what shows when you entered "7". if it shows 7 ,

try;
if(x == '7') {

Have a look at the examples in Serial Input Basics - simple reliable ways to receive data.

It is not a good idea to use the String (capital S) class on an Arduino as it can cause memory corruption in the small memory on an Arduino. Just use cstrings - char arrays terminated with 0.

...R

Ok I have checked them out. My arduino code is:

#include <stdio.h>

#define deskLightsPin 3
#define monitorLightsPin 2

const unsigned long MESSAGE_TIMEOUT = 10UL * 1000;  // 10 seconds

boolean PARSE = false;
boolean EXEC = false;    

char myStr[64];
int bufPos = 0;

void setup () {
  Serial.begin (9600);
  while (!Serial) ;  // wait for Serial to become active
  Serial.println ("Starting");
  pinMode (deskLightsPin, OUTPUT);
  pinMode (monitorLightsPin, OUTPUT);
  
  digitalWrite(monitorLightsPin, HIGH);
  digitalWrite(deskLightsPin, HIGH);

}  // end of setup

unsigned long lastMessage;
unsigned int countOfA;

void clearBuffer() {
  for(int j=0; j<64; j++) {
    myStr[j] = '\0';
  }
  bufPos = 0;
}
void processInput () {
  while (Serial.available ()) {
    char c = Serial.read ();
    
    if( c == '<') {
      PARSE = true;
    }else if( c == '>') {
      PARSE = false;
      EXEC = true;
    }else {
      PARSE = false;
      EXEC = false;
    }
    
    if( ( PARSE == true ) && ( c != '<' ) ) {
      myStr[bufPos] = c;
      bufPos++;
    }
  }  // end of while loop
}  // end of processInput

void executeCommand() {
  if( "desk-lights-on" == myStr ) {
    //Serial.println("Activating desk lights...");
    digitalWrite(monitorLightsPin, LOW);
  }else if( "desk-lights-off" == myStr ) {
    //Serial.println("Deactivating desk lights...");
    digitalWrite(monitorLightsPin, HIGH);
  }else if( strstr("monitor-lights-on", myStr) != NULL ) {
    //Serial.println("Activating monitor lights...");
    digitalWrite(deskLightsPin, LOW);
  }else if( strstr("monitor-lights-off", myStr) != NULL ) {
    //Serial.println("Deactivating monitor lights...");
    digitalWrite(deskLightsPin, HIGH);
  }
  
  /*if( strstr("lights-on", myStr) != NULL ) {
    Serial.println("Activating desk lights...");
    digitalWrite(monitorLightsPin, LOW);
    digitalWrite(deskLightsPin, LOW);

  }else if( strstr("lights-off", myStr) != NULL ) {
    Serial.println("Deactivating desk lights...");
    digitalWrite(monitorLightsPin, HIGH);
    digitalWrite(deskLightsPin, HIGH);
  }*/
  
}

void loop () {
  if (Serial.available ()) {
    lastMessage = millis ();  // remember when we last got input
    processInput ();  // now handle the input
    //Serial.print("Message was:");
    //Serial.println(myStr);
  }

  // warn if no keepalive received
  if (EXEC == true) {
    EXEC = false;
    //Serial.print("Command found:");
    //Serial.println(myStr);
    
    //Serial.print    
    executeCommand();
    clearBuffer();
  }else {
    EXEC = false;
    //Serial.println("Waiting...");
  }
  
} // END of main loop

It seems to be working but still sometimes it digitalWrite() and It shouldn' t. How can I keep a logfile of what arduino does? I tried to write to file using C but i got an error:

fopen() was not declared

even if i added stdlib at the top.

Any ideas?

The Arduino has no hard drive to store files. If you add an SD card then you can save files.

  while (!Serial) ;  // wait for Serial to become active
  }else {
    EXEC = false;
    }else {
      PARSE = false;
      EXEC = false;
    }

Can you see how that last else{} will stop parsing when it receives a valid char that comes after a "<" start-of-parse? I'm surprised you get any output at all.

xmarkx:
Ok I have checked them out.

I don't know what you meant by "them" but it does not seem to mean the examples in Serial Input Basics

...R

Is there any problem if I use Serial.print()? I mean ok i am receiving data from my raspberry (serial) but maybe there is some conflict with the Serial.print() lines that i use for debugging my code.

Any ideas?

xmarkx:
Is there any problem if I use Serial.print()? I mean ok i am receiving data from my raspberry (serial) but maybe there is some conflict with the Serial.print() lines that i use for debugging my code.

As you have not responded to the earlier Replies you have received I have no idea where you have got to in your thought process.

...R

I dont know what shall i answer to those. I have already looked at Serial Input Basics - updated - Introductory Tutorials - Arduino Forum. I have also made all the changes that @MorganS said. He was correct.

Let me update you. I have successfully turned on and off my lights using an android app. However this is working great only when I open the arduino Serial Monitor. If I just use the arduino hardware without any Serial Monitor open this is not working properly.

How does the serial monitor affect my project? Any ideas?

xmarkx:
I dont know what shall i answer to those. I have already looked at Serial Input Basics - updated - Introductory Tutorials - Arduino Forum. I have also made all the changes that @MorganS said. He was correct.

Let me update you. I have successfully turned on and off my lights using an android app. However this is working great only when I open the arduino Serial Monitor. If I just use the arduino hardware without any Serial Monitor open this is not working properly.

How does the serial monitor affect my project? Any ideas?

If the code in your first post is the same code today, you are waiting forever until something arrives from Serial, and then you perform your light on and off. A little studying of your code's logic will solve a lot of problems.

Paul

Paul_KD7HB:
If the code in your first post is the same code today, you are waiting forever until something arrives from Serial, and then you perform your light on and off. A little studying of your code's logic will solve a lot of problems.

Paul

Hello.

No I have changed many things. As i said it it is working. It seems that Serial Monitor affect the whole project somehow but I have no idea how and why. :confused: This is my actual problem Paul.

xmarkx:
Hello.

No I have changed many things. As i said it it is working. It seems that Serial Monitor affect the whole project somehow but I have no idea how and why. :confused: This is my actual problem Paul.

Well, ok, if you are not willing to show us the new code, then good luck.

Paul

Paul_KD7HB:
Well, ok, if you are not willing to show us the new code, then good luck.

Paul

I have no problem sharing the code :slight_smile: Here it is:

#include <stdio.h>

#define deskLightsPin 3
#define monitorLightsPin 2

boolean PARSE = false;
boolean EXEC = false;    

char myStr[64];
int bufPos = 0;

void setup () {
  Serial.begin (9600);
  pinMode (deskLightsPin, OUTPUT);
  pinMode (monitorLightsPin, OUTPUT);
  
  digitalWrite(monitorLightsPin, HIGH);
  digitalWrite(deskLightsPin, HIGH);
  Serial.println ("Arduino server is ready!\n\n");
}

void clearBuffer() {
  for(int j=0; j<64; j++) {
    myStr[j] = '\0';
  }
  bufPos = 0;
}

void procInput () {
  while (Serial.available ()) {
    char c = Serial.read ();
    
    if( c == '<') {
      PARSE = true;
    }else if( c == '>') {
      PARSE = false;
      EXEC = true;
    }
    
    if( ( PARSE == true ) && ( c != '<' ) ) {
      myStr[bufPos] = c;
      bufPos++;
    }
  }  // end of while loop
}  // end of processInput

void executeCommand() {
  if( strstr("desk-lights-on", myStr) != NULL ) {
    Serial.println("Activating desk lights...");
    digitalWrite(monitorLightsPin, LOW);
  }else if( strstr("desk-lights-off", myStr) != NULL ) {
    Serial.println("Deactivating desk lights...");
    digitalWrite(monitorLightsPin, HIGH);
  }else if( strstr("monitor-lights-on", myStr) != NULL ) {
    Serial.println("Activating monitor lights...");
    digitalWrite(deskLightsPin, LOW);
  }else if( strstr("monitor-lights-off", myStr) != NULL ) {
    Serial.println("Deactivating monitor lights...");
    digitalWrite(deskLightsPin, HIGH);
  }
  
  /*if( strstr("lights-on", myStr) != NULL ) {
    Serial.println("Activating desk lights...");
    digitalWrite(monitorLightsPin, LOW);
    digitalWrite(deskLightsPin, LOW);

  }else if( strstr("lights-off", myStr) != NULL ) {
    Serial.println("Deactivating desk lights...");
    digitalWrite(monitorLightsPin, HIGH);
    digitalWrite(deskLightsPin, HIGH);
  }*/
}

void loop () {
  if (Serial.available ()) {
    procInput ();
    
    if (EXEC == true) {
      executeCommand();
      clearBuffer();
      EXEC = false;
    }
  }
} // END of main loop

Well, I can see where you get and send data using the Serial monitor, but I can't find where you get any data from another device. What am I missing?

Ah, I used Linux back in the 1990's and wonder if somehow you are merging the serial data from the third device into using the same serial port on the PC?

Paul

xmarkx:
I have no problem sharing the code :slight_smile: Here it is:

Now tell us what it actually does and what you want it to do that is different.

...R

@Paul let me explain the code

@Robin2 what it does is what i want to do but as i said above it is working only when my serial monitor (the debug window) is open.

in digital pins 2 and 3 I have two relay with led strips.

#include <stdio.h>

#define deskLightsPin 3
#define monitorLightsPin 2

PARSE indicates that the arduino is reading a message, when PARSE is false i am just consuming chars or executing the command found.
EXEC indicates that the message has completed (i received all the chars) so the arduino is ready to EXECUTE the command (message)

boolean PARSE = false;
boolean EXEC = false;    

char myStr[64];
int bufPos = 0;

void setup () {
  Serial.begin (9600);
  pinMode (deskLightsPin, OUTPUT);
  pinMode (monitorLightsPin, OUTPUT);
  
  digitalWrite(monitorLightsPin, HIGH);
  digitalWrite(deskLightsPin, HIGH);
  Serial.println ("Arduino server is ready!\n\n");
}

When the message is executed i clear the buffers (i need this caz without it the 2nd or 3rd messages append my string - myStr)

void clearBuffer() {
  for(int j=0; j<64; j++) {
    myStr[j] = '\0';
  }
  bufPos = 0;
}

ALL the messages start with < and end with >

void procInput () {
  while (Serial.available ()) {
    char c = Serial.read ();
    
    if( c == '<') {
      PARSE = true;
    }else if( c == '>') {
      PARSE = false;
      EXEC = true;
    }
    
    if( ( PARSE == true ) && ( c != '<' ) ) {
      myStr[bufPos] = c;
      bufPos++;
    }
  }  // end of while loop
}  // end of processInput

Depending on the message do something

void executeCommand() {
  if( strstr("desk-lights-on", myStr) != NULL ) {
    Serial.println("Activating desk lights...");
    digitalWrite(monitorLightsPin, LOW);
  }else if( strstr("desk-lights-off", myStr) != NULL ) {
    Serial.println("Deactivating desk lights...");
    digitalWrite(monitorLightsPin, HIGH);
  }else if( strstr("monitor-lights-on", myStr) != NULL ) {
    Serial.println("Activating monitor lights...");
    digitalWrite(deskLightsPin, LOW);
  }else if( strstr("monitor-lights-off", myStr) != NULL ) {
    Serial.println("Deactivating monitor lights...");
    digitalWrite(deskLightsPin, HIGH);
  }
  
  /*if( strstr("lights-on", myStr) != NULL ) {
    Serial.println("Activating desk lights...");
    digitalWrite(monitorLightsPin, LOW);
    digitalWrite(deskLightsPin, LOW);

  }else if( strstr("lights-off", myStr) != NULL ) {
    Serial.println("Deactivating desk lights...");
    digitalWrite(monitorLightsPin, HIGH);
    digitalWrite(deskLightsPin, HIGH);
  }*/
}

void loop () {
  if (Serial.available ()) {
    procInput ();
    
    if (EXEC == true) {
      executeCommand();
      clearBuffer();
      EXEC = false;
    }
  }
} // END of main loop

To sum up, It receives from serial connection some characters. It consumes characters till < appears, then it goes into a phase of PARSE=TRUE till the > appears. Then PARSE = FALSE and EXEC = TRUE. So the next step is to check wither EXEC = TRUE or FALSE. Obviously is TRUE so it procInput and it executed digitalWrite() in the appropriate pin.

Do you need any more explanation? If you have any other approach I would be glad to read it and discuss it with you guys.

xmarkx:
@Robin2 what it does is what i want to do but as i said above it is working only when my serial monitor (the debug window) is open.

Maybe we have been focusing on the wrong end.

It may be that your Python program needs to set DTR or RTS for the serial port (I can never remember which) and at the moment it is only being set when you open the Serial Monitor.

I am assuming, of course, that your Python program is not running while you have the Serial Monitor open - because two PC programs cannot use the same serial connection at the same time.

Another "gotcha" with PC programs is when they continually close and open the serial port. Your Python program needs to open the serial port and keep it open until it is completely finished with the Arduino. Have a look at this Python - Arduino demo

Post your Python program.

...R

Well it may be crazy but yes i am running serial monitor and on a terminal i am running my python script too and it is working. I think if i stop the serial monitor it will also be working. But when I start my arduino (power it up) and then power my raspberry without opening any serial monitors it does some crazy things like blinking one of the two lights.

My python code is:

import socket
import time
import sys
import select
import serial
from time import gmtime, strftime
from datetime import date
import datetime
import warnings
import sys
import serial.tools.list_ports
import subprocess
import os

def handleRequests(newdata):
	arduPort = ""
	baudRate = 9600
    
	for p in serial.tools.list_ports.comports():
		if "ACM" in p[1]:
			arduPort = p[0]
			print "Arduino was found at port: " + arduPort + "\n"
	
	ser = serial.Serial(arduPort, baudRate)
	newdata = newdata.replace("&", "") // message to send to arduino
	
	print "Handler received: " + newdata
	
	if newdata == "deskLights_on": # Desk lights ON
		msg = "Activating desk lights..."
		print msg
		ser.write("<desk-lights-on>")
		time.sleep(1)
	elif newdata == "deskLights_off": # Desk lights OFF
		msg = "Deactivating desk lights"
		print msg
		ser.write("<desk-lights-off>")
		time.sleep(1)
	else:
		msg = "Command not found\n"
	return msg
    
def main(argv):
	if( len(sys.argv) < 2 ):
		print "No argument passed to the handler. I did nothing!"
		exit(1)

	# Get the input via argv array
	newdata = sys.argv[1]	
	handleRequests(newdata)

if __name__ == "__main__":
    main(sys.argv)

I am by no means an expert on Python but I don't think that style of script is suitable - because it just communicates briefly with the Arduino rather than keeping the serial port open permanently. And I don't see any code that allows time for the Arduino reset process when the Python program opens the serial port.

Have a look at the Python example that I gave you the link to.

As separate matter, rather than send to the Arduino just send as it will convey just as much useful information and will be much easier to respond to in Arduino code. And send for OFF.

...R

I have to ask. When I open a serial from my python script arduino reset? I mean it will run again setup() function etc...?