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?
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.
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
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?
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?
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
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
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.
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
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.
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).
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.
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 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: