Behavior of While(!Serial)

Hello,

Uno noobie here!
I'm having a strange issue with my UNO running my current project.
I'm using a Python Program from my computer to send a raw series of Infrared codes to the Arduino serial port.
On receiving the code, Arduino uses the IR Library to transmit this code to the target appliance.

The program works as intended, but only when the Serial Monitor is open on my computer.

I read elsewhere on these forums that this particular line needs to be removed

while (!Serial) {
    ; // wait for serial port to connect. Needed for native USB port only

I have removed this line in my sketch and re-flashed it into my UNO. But the problem persists.

What could be wrong?
Besides, I picked up the above code from an Arduino Serial tutorial. What does the comment about native USB port under the code mean?

thanks,
AM

1 Like

The "Serial" is always valid for an Arduino Uno, therefor that piece of code does not wait.
In the Leonardo, the "Serial" could be zero, if the serial monitor has not been opened yet.

The problem is probably in your sketch or Python script, but we don't know your sketch or your script. Have your read this : http://forum.arduino.cc/index.php/topic,148850.0.html

Do you open the serial port in Python ?
I don't know Python very well, but this might be useful : Arduino Playground - Python

It is possible to test the Serial communication from Windows with PowerShell or with linux using Bash.

You may find some useful ideas in this Python - Arduino demo

...R

Thanks all! Here's my Arduino code for the time being.
I will post the Python code after logging into my Raspberry Pi, but I have tested the sketch and this is what it does:

  • The IR Code is parsed as a pipe-delimited string
    Example: 1234 5678 |2345 6789|E90909 1111 273
  • Arduino parses the segments between the pipes and loads each value into an IRBuffer
  • The last segment of the code contains a leading "E"
  • When Arduino encounters a segment with a leading "E", it knows that it has received all of the segments, and exits reading the Serial port
  • It then proceeds to package this IRBuffer into an IRTransmit call and transmits the signal
  • My monitor turns off or ON based on the signal sent.
#include <IRLib.h>
#include <Wire.h>

//IRdecode My_Decoder;
IRsend IRTransmitter;

unsigned int IRCodeBuffer[67];   // Raw codes will be stored in an array
String cs;
unsigned int c;
boolean debug;
void setup() {
  cs = String(""); c = 0;
  Serial.setTimeout(2000);
  Serial.begin(9600);
  delay(2000); //delay for Leonardo
  //Enable this line when debugging only!
  //Having this enabled will mean that the sketch
  //will work only when the Serial window is OPEN!
  debug = false;
  if (debug)
  {
    while (!Serial);
  }

}

void loop() {
  // put your main code here, to run repeatedly:
  receiveIRCode();
  delay(500);Serial.read();
  transmitIRCode();

}

//function to receive IRCode from Raspberry Pi
void receiveIRCode()
{
  while (Serial.available() > 0)
  {
    cs = Serial.readStringUntil('|');
    if (cs.length() > 0 && cs.substring(0, 1) == "E")
    {
      //Only the last byte segment comes with a leading "E"
      cs = cs.substring(1, cs.length());

    }
    if(debug) Serial.println(cs);

    while (cs.indexOf(" ") != -1) {
      IRCodeBuffer[c] = cs.substring(0, cs.indexOf(" ")).toInt();
      cs = cs.substring(cs.indexOf(" ") + 1, cs.length());
      c++;
    }
    if(debug) Serial.print("cs > "); Serial.println(cs);
    if (cs.length() > 0)
    {
      IRCodeBuffer[c] = cs.substring(0, cs.length()).toInt();
    }
    c++;
    Serial.print("c = "); Serial.println(c);
  }

  if (c >= 67 && debug)
  {
    // All codes have been processed - Playback codes
    for (int i = 1; i <= 67; i++) {
      Serial.print("Playback ["); Serial.print(i - 1); Serial.print("] >> "); Serial.println(IRCodeBuffer[i - 1]);
    }
    c = 0;
    Serial.read();
  }
}

void transmitIRCode()
{
  IRTransmitter.IRsendRaw::send(IRCodeBuffer, 67, 38);
}

About other questions on Python asked by members on this thread:

Yes, I use the Python Serial library
I confirm that the Serial port is open
The Python program successfully transmits the code from the Pi over to the Uno
Uno responds as shown in my sketch above and controls the Monitor
Python program closes Serial port

All of this works only if:
I keep the Serial Window open in the Arduino dev environment in the Raspberry Pi

If it's of any help, the Pi runs on Ubuntu Mate.

thanks!

andymenon:
Python program closes Serial port

Aaarghhh!

Don't close the Serial Port until you are completely finished with the Arduino because it resets whenever you open the Serial port.

Look at the code in the link I gave you.

...R

:roll_eyes:

Hmmm... I will go through the link you gave me, but does this mean that I modify the python program to keep the serial port open for ever and close it only when the arduino-pi system is shut down?

Thanks

andymenon:
does this mean that I modify the python program to keep the serial port open for ever and close it only when the arduino-pi system is shut down?

Yes.

...R

Thanks! Can't wait to get back to my desk to try this out!

Hello,

Finally, I grabbed some time today to make changes to my Python program and try this once more. But no success.
I have posted my Python Program below. But I've also eliminated the following factors as causes:

  • The baud rate on both the Uno Sketch and the Python program is set identically to 9600
  • The Uno does not write to the Serial port - it only reads from it
  • Conversley, the Python client does not read anything from the Serial Port - simply writes to it

Python client program observations (Output of the Python Shell is also published below):

  • When I run the Python client, and hit the button on my Web page, the Python client receives the correct IR code
  • It parses the code correctly into segments
  • As shown by the output, the Serial Port is always open during the life time of the Python client

Arduino Serial Window observations:

  • That said, when I open the Serial Window of the Arduino, I don't see the codes completely written out to the window
  • In between each code, a random number is being written
  • And now, Serial Window or no Serial Window, the set up has stopped working!

Python Code:

Andy Menon - 04.03.2016

The Signalr Python Client with the Pi-Arduino Serial Bridge

progam constants | variables

TEST_CODE_NAME: The test code requested as soon as this client establishes connection with the hub

SEGMENT_DELIMITER: The delimiting character that this client has to look for, and parse code segments

TERMINAL_PREFIX: (future) - Client may use this to communicate back to the server that it has received all segments

debug: 1 = output messages (test mode) | 0 = no output messages except failures (operational or production mode)

mode: 1 = production | 0 = local (or test) hub

hubUrl: The URL to the Signalr hub that changes based on the value of mode

hubName: Name of the Signal hub - the server hub name is HomeAutomationHub,

but the signalr client must refer to this hub as homeAutomationHub (camel-case)

port: The Serial Port that opens to the Arduino Uno

from requests import Session
from signalr import Connection
import serial

debug = 1
mode = 1
hubUrl =""
hubName = "homeAutomationHub"
TEST_CODE_NAME = "galaxy"
SEGMENT_DELIMITER = "|"
TERMINAL_PREFIX = "E"
port = "/dev/ttyACM1"

with Session() as session:
    #create a connection - URL pattern is: http://<your_server_name>:<your_port_num>/signalr
    if(mode==1):
        hubUrl="http://myActualWebSite.com/signalr"
    else:
        hubUrl="http://localhost:54521/signalr"
    
    # Open connection to the SignalR Hub
    connection = Connection(hubUrl, session)

    # Open Serial Port with the same rate as Arduino would read - 9600 baud
    ser = serial.Serial(port,9600)
    
    #MAKE SURE THAT signlar v0.0.6 is installed for register_hub() availability    
    homeAutoHub = connection.register_hub(hubName)


    #create new haHub message handler - This handler will be triggered when this 
    #client receives a notification from the Hubs sendCommandToClient() method
    def process_command_from_hub(buttonId, cmdSrc):
        if(mode==1):
            if(debug==1):
                print('Received Signal from Hub - Signal Id {0} : Source {1}'.format(buttonId,cmdSrc))
            if(len(cmdSrc)>0 and buttonId <> TEST_CODE_NAME ):
                transmitToArduino(cmdSrc,SEGMENT_DELIMITER,TERMINAL_PREFIX)              
        else:
            if(debug==1):
                print('TEST: Received Signal from Hub - Signal Id {0} : Source {1}'.format(buttonId,cmdSrc))
            

    
    #receive new messages from the hub - pass it on to the handler for processing
    #'sendCommandToClient' is the server side method that pushes notificationS to the clients
    homeAutoHub.client.on('sendCommandToClient', process_command_from_hub)


    def transmitToArduino(IRSignalCode,delim,endPrefix):
        while(len(IRSignalCode)>0):
            pos = IRSignalCode.index(delim)
            segment=IRSignalCode[:pos+1]
            if(debug==1):
                print("Found {0} at position {1} - segment parsed is {2}".format(delim,pos,segment))
            if(debug==1):
                print("Serial port {0} is open ".format(ser.name))        
            # CAUTION! segment value is UNICODE,convert to string before writing!
            ser.write(str(segment))
            segment=""
            # Remove segment already processed.
            IRSignalCode = IRSignalCode[(pos+1):]
          
   
    #start connection - for always connected clients, use 'with (connection):'
    #call the 'automationCommand' SERVER-side method to send a message to the Automation Hub

    print("starting connection to haHub...")    
    with (connection):
        print("connection to haHub active...requesting test code '{0}' ... ".format(TEST_CODE_NAME))
        homeAutoHub.server.invoke('automationCommand', 'galaxy','galaxy')
        print("awaiting commands from automation hub ...")
        while(1==1):
            connection.wait(5)
            print("...")

    # CLOSE SERIAL PORT ONLY ON EXIT!
    ser.close()
    print("haHub exited....")

Python Shell Output:

The parsing of the code is shown in detail - The sections between the pipe-delimiter are read
correctly , and as expected per my previous tests.

Found | at position 44 - segment parsed is 4400 4550 450 1800 400 1800 400 1800 450 700|
Serial port /dev/ttyACM1 is open 
Found | at position 40 - segment parsed is 400 700 400 700 400 700 450 650 500 1750|
Serial port /dev/ttyACM1 is open 
Found | at position 41 - segment parsed is 400 1800 450 1800 400 700 400 700 400 700|
Serial port /dev/ttyACM1 is open 
Found | at position 40 - segment parsed is 400 700 450 700 400 700 400 1800 400 700|
Serial port /dev/ttyACM1 is open 
Found | at position 39 - segment parsed is 450 700 400 700 400 700 400 700 400 700|
Serial port /dev/ttyACM1 is open 
Found | at position 43 - segment parsed is 450 1800 400 700 400 1800 450 1800 400 1800|
Serial port /dev/ttyACM1 is open 
Found | at position 31 - segment parsed is E400 1850 400 1800 400 1800 450|
Serial port /dev/ttyACM1 is open

Thanks for your help!
AM

Screenshot-5.png

andymenon:
Hello,

Finally, I grabbed some time today to make changes to my Python program and try this once more. But no success.
I have posted my Python Program below. But I've also eliminated the following factors as causes:

Just write a short Python program that says "Hello World" over and over at 1 second intervals and get that working with your Arduino.

When that works you can add to the code to send other messages and experiment with the time interval

...R

Well,

I did write the two basic programs. They work fine with or without the Serial Window open.

But if I include something in the Sketch such as flashing an LED, it seems to have trouble, or the Sketch will need some tweaking with the sleep function on both the Uno and Python ends.

The Uno is supposed to pause the while loop for 500ms
Instead, I see the LED continuously lit up when the Python program sends 5 messages in succession
every 1500ms

My next step is to try the SerialEvent pattern and see if it makes any difference:

Simple Python Program:

import serial
import time
port = "/dev/ttyACM0"
segment = "This is Python! Message {0} to Uno via Serial Port |"
def main():
    ser = serial.Serial(port,9600)
    print("Serial port {0} is open ".format(ser.name))
    ser.write(str(segment.format("1")))
    time.sleep(1.5)
    ser.write(str(segment.format("2")))
    time.sleep(1.5)
    ser.write(str(segment.format("3")))
    time.sleep(1.5)
    ser.write(str(segment.format("4")))
    time.sleep(1.5)
    ser.write(str(segment.format("5")))
    time.sleep(1.5)

    ser.close()
    print("Serial port {0} is closed ".format(ser.name))
    
# execute main program
main()

Simple Uno Sketch:

String cs;
const int ledPIN = 13;
void setup() {
  cs = String(""); 
  pinMode(ledPIN, OUTPUT);
  Serial.begin(9600);
  while (!Serial); 
}


void loop(){

  while (Serial.available() > 0)
  {
    cs = Serial.readStringUntil('|');    
    Serial.println(cs);
    //***Adding anything other than simply printing out messages, causes 
    // the message processing to falter. Here, I try to flash the on board LED
    // so that I can test without having to open the Serial Window on the Uno
    // Flash LED to indicate that a message has 
    // been received and processed
    if(cs.length() > 0)
    {
      digitalWrite(ledPIN,HIGH);
      delay(500);
      digitalWrite(ledPIN,LOW);
      cs="";
    }


  }
}

Basic sketch and Python code working!
Changed over to the Serial Event model as mentioned earlier.
Basically, the time interval between which the Pi must send messages over must be slightly higher than the rate at which the UNO takes time to respond.

From my earlier posts, this line in the Python code changes to :

time.sleep(0.65)

I will start building on this and see adjust the delays accordingly.

Thanks for your inputs!
AM

serialEvent() in the Arduino system is a crock of sh*t. It behaves identically to

if (Serial.available > 0) {
    mySerialFunction();
}

So is readStringUntil() because it blocks the Arduino from doing other things.

Your Python code closes the Serial port - and I told you earlier not to do that. And it does not wait for any evidence that the Arduino has completed resetting before it starts sending.

Use either the 2nd or 3rd example (perferrably the 3rd) in Serial Input Basics to receive the data in the Arduino.

All of these things are in the example in the link I posted in Reply #2

...R

Yep,
I went back to the first version of my test program, and figured that the SerialEvent has no effect. The time delays were the one that made the difference.

Yes, the Serial window is closed in this test program. It's just a test.

But if you look at the actual Python client program from my post a couple of days ago, the Serial port is opened at the very beginning and never closed unless the endless while loop in Python is broken at the very end.

Also was presented, the output from Python shell that shows the Serial port to be always open when 4 segments of codes are transmitted over the serial port.

I have to now do the following:

Measure the real time duration the Uno will require to:

Process each long segment of code and build them into an IR Buffer.

With this, I hope that when I set the delay on the Python side to be greater than the processing time measured in the previous step, it should make the message processing a lot more reliable.

Thanks

It seems to me you are making things hard for yourself. I use the system in my link in Reply #2 in several programs and with different Arduinos that have different reset arrangments. I don't have to set any delay values.

Serial communication is asynchronous - it should not rely on timing (other than the baud rate).

Have you tried the example I gave you?

...R

I will revisit the link you speak of and keep you posted

Robin2,

Looked through the links and I made some minor changes to the original sketch that reads the long IRCodes into an IR buffer.

When the Serial Window is not open, I added a minor function to flash an LED if the IR Buffer has been built successfully.
Works well.
The Python client that pushes these codes to the UNO has no changes made to it.

Next step would be to add the IR Transmission part and see how that's going to shape up.

fyi,
AM

Awesome!

I included the IR Transmission and the system works great for 4 functions on my Samsung LCD Monitor - Power On/Off and Volume Up/Down

Purely in the spirit of sharing, I want you all to know what I'm trying to do is here nothing new, but in the way I'm going about it is . I'm trying to make multiple technologies work together so that my learning experience is a lot more fulfilling.

Here's is a visual of the system that has all its components operational as briefly described below:

  • I have a remote website that runs a real-time ASP.NET SignalR Hub
  • The Hub is wired to receive commands from a SignalR HTML client (that I run from my phone, tablet anywhere in the house)
  • The Hub receives the command, reaches out to a SQL Server database and grabs the IR Code corresponding to that button on the HTML page that sent the command
  • The Hub then relays this command to a Python SignalR Service client running on my Raspberry Pi - The Pi is my central place to do all my IoT stuff that I remotely administer
  • Python client receives the command and passes it down to the Uno via the Serial port
  • The Uno controls the target LCD monitor

Basically, this is an exercise for me to bridge what I already know , with what I'm learning anew.
Besides this, I have an IR code capture Sketch that I use to capture all codes. The idea is to expand this out
to control our entertainment center and the lights in the house.

Thanks for all your inputs.

AM

Members,

Thanks once again for your help with this topic in discussion.
I wanted to share the latest update with you folks.
A few days ago I completed an instructable on a basic version of a Home Automation system and posted it to my instructables page here:

Please give this a read and I hope you like it.

AM