sending serial commands to arduino - python

I've been trying to find a way to send serial commands from my PC (Windows 7) to an Arduino Uno R3. I've been working on this simple program, where you're supposed to send a simple "1" through the USB cable, in order to turn on the onboard LED. My Arduino code should be working (what I know of, but I'll make sure to upload it).
I've been trying to send this command using Python and pySerial, but I can't seem to get pySerial to work. Also I've tried using CMD, but it seems like CMD freezes when i type in my command (ECHO 1 > COM3 BAUD:9600).
I'm the adminstrator of my PC.
This is my arduino coding
int var = 0;
int LEDPin = 13;
int val = 0;
void setup() {
Serial.begin(9600);
pinMode(LEDPin, OUTPUT);
}
void loop() {
if (Serial.available()>0){
val = Serial.read();
}
if (val == 1){
digitalWrite(LEDPin, HIGH);
}
digitalRead(LEDPin);
if (LEDPin==HIGH){
var ++;
delay (1000);
if(var==10){
digitalWrite(LEDPin,LOW);
var = 0;
val = 0;
}
}
}
And the short Python program I've got :)
import serial
ser = serial.Serial('COM3', 9600, timeout=0)
while 1:
var = 1
ser.write(var)
delay(12000)
With Kind Regards
Michael Vedel.

just to be sure - is Arduino really connected to COM3?
In order to check serial connection manually you can use for example Putty. With help of it you can connect to the needed serial port and send command manually. And in order to check whether Arduino received it, you can add Serial.println(val); just after val = Serial.read();, with this Arduino should sends back to serial whatever characters it receives.

Does the code work when you type a '1' into the Serial Monitor in the Arduino IDE? If so, check the COM port. On my PC (also Windows 7), COM3 is never the Arduino port, as it is used internally for something else.
By the way everything after the digitalRead() statement will do nothing, since you're comparing LEDpin (which is declared as 13) to HIGH (which is defined as 1). I think you mean to see if the digitalRead output is HIGH, but I'm not sure that will work, either, since the pin is declared as an OUTPUT. You'd be much better off putting that logic in the (val == 1) section.

just save this code as .bat and make sure that you are using com 6.
This code lets you enter and sends your commands to serial port at 9600bpm
mode com6:9600,N,8,1
#echo off
:start
cls
Set /p commands="enter command:"
echo|set /p= %commands% >com6
goto start
Now you have to read serial using this in Arduino
Serial.read();

I think the root problem is in the Python code in the call to write. The argument has to be bytes (or something compatible). You're passing an integer value. You need to explicitly convert that value to a bytes object. I'm not a Python expert, but I think one way to do that is to replace:
var = 1
with
var = b'\x01'
Oh, and you might need to call flush as well.
BTW, your experiment with ECHO doesn't do what you intended. It sends the character value for '1', which is 49. Since 49 != 1, your Arduino code won't respond to it.
I find the easiest way to test serial commands is to use the Arduino Serial Monitor, which will have all the right defaults as long as you match the baud rate. This will enable you to ensure the Arduino code is right before debugging the Python code. (Then again, it may be difficult to send control characters with the Serial Monitor, so consider using printable text in your protocol. For example 'A' for on and 'B' for off. Printable text can be easy to work with among all these tools (Python, C, Serial Monitor, ECHO, etc.).)

do this it works better for me, just change the com4 for the port you have connected to
#echo off
:start
cls
set /p commands="enter command:"
mode com4 baud=115200 parity=n data=8 stop=1 to=on xon=off odsr=off octs=off dtr=off rts=off idsr=off && echo %commands% > com4
cls
goto start

I think Arduino is stable and easy enough to handle the data from serial, the cause of that as I used same library with Pyserial in python 3 was that event of reading the serial get fired once which is way faster than Arduino board and to solve that you should use a thread method that runs in the background and make it always try to read the incoming data from serial.
I've made this function that recieved the opened serial :
def read_from_port(ser):
while True:
try:
reading = ser.read().decode()
handle_data(reading)
except EXCEPTION:
print("error while decoding" + str(EXCEPTION))
after I have got the serial from the list and assigned it with the desired baud rate and send it to the Thread :
serial_me = serial.Serial(serial_port1, 115200, timeout=3)
try:
thread_x = threading.Thread(target=read_from_port, args= (serial_me,))
thread_x.daemon = True
thread_x.start()
except EXCEPTION:
print('couldn\'t start thread')
print(Exception)

Related

Unable to send byte from Python serial.write() to Arduino

I wrote a python script that sends and receive data to and from an Arduino. I can receive data without problems, but when I send data it seems like the Arduino is receiving only garbage.
The Arduino is connected to a linux pc via USB and the pc is running Python 3.8.
Since the original code contains a lot of unrelated stuff and may be distracting, I prepared the simplest possible sketch to demontrate the problem:
Python code:
#! /usr/bin/env python
import serial
import time
if __name__ == '__main__':
ser = serial.Serial("/dev/ttyACM0", 9600, timeout=0)
time.sleep(5) # Wait for Arduino to reset and init serial
ser.write(67)
Arduino sketch
const byte LED_PIN = 13;
void setup() {
pinMode(LED_PIN, OUTPUT);
digitalWrite(LED_PIN, LOW);
Serial.begin(9600);
while (!Serial) {
; // wait for serial port to connect. Needed for native USB port only
}
}
void loop() {
if (Serial.available() > 0) {
byte b = Serial.read();
if (b == 67) {
digitalWrite(LED_PIN, HIGH);
delay(500);
digitalWrite(LED_PIN, LOW);
}
}
}
This code flashes the onboard LED when receives a byte with value 67 (uppercase C). This works with the Arduino Serial Monitor, but not when running the Python script.
I feel like my problem may be related to this question, but in that case the focus was on the user not considering the case of an empty serial input buffer, while I believe the problem is actually in the sent data. This is why I decided to leave out the receiving part and simplify the example using only the onboard led.
Update
I made it work changing the last line in the python script to:
ser.write(bytes([67]))
(note the [] added around the integer value).
Anyone can explain why this syntax produces the correct result? It seems like I'm passing a single entry array to the function bytes().
Pardon my poor skills in Pyton, I know the question is probably basic.
It's really simple; the methods you tried that worked all conform to the specification for the pyserial library.
Per the Pyserial documentation:
write(data)
Parameters: data ā€“ Data to send.
Returns: Number of bytes written.
Return type: int
Raises: SerialTimeoutException ā€“ In case a write timeout is configured for the port and the time is exceeded.
Write the bytes data to the port. This should be of type bytes (or compatible such as bytearray or memoryview). Unicode strings must be encoded (e.g. 'hello'.encode('utf-8').
This is why the b'C style worked as well as the bytes call.
Attribution: Pyserial Page

PySerial slowdown on read from Arduino

I'm attempting to write a handshaking procedure to allow my python program to automatically detect which port the Arduino is on. It works, however sometimes it runs extremely slow. Here's the problematic part of my code:
import serial, serial.tools.list_ports, time
portList = list(serial.toools.list_ports.comports())
conn = 0
while conn == 0:
for port in portList:
print(port[0])
try:
arduino = serial.Serial(port[0], 4800, timeout=.1)
time.sleep(.2)
sig = arduino.read()
signum = int.from_bytes(sig, byteorder='little')
if signum == 7:
global comport
comport = port[0]
conn = 1
break
except:
print('Could not read from ' + str(port[0]))
Essentially I have the Arduino constantly sending the arbitrary number '7' to the serial port. The python script scans each port for a 7 until it finds it. What's happening is that when it gets to the port that the Arduino is on, the code seemingly pauses executing for about 10 seconds at the arduino = serial.Serial(...) line right underneath the try statement. Since it's in a try loop, I know it's not throwing an error because it does eventually make it through. Is it just having trouble opening the port? How can this be fixed? I am on Python 3.4.3 and pySerial 2.7.
I think the issue is more with how arduino does serial ... it waits for a serial connection to open then it does a bunch of setup you can see this with a relatively simple arduino sketch
int i;
void setup(){
i=8;
Serial.begin(9600);
}
void loop(){
Serial.print(i);
Serial.print(",");
i+=1;
}
and I think that you will always see 8 as the first number when you connect to the port ... I dont have an arduino on hand but I seem to recall seeing this behaviour
Just to check: Is the baudrate the same for both your Arduino and Python? Are there any other programs trying to access the Arduino?

Random character at the beginning of serial.readline() in python and arduino

I get random characters when I perform a serial.readline(), sometimes it is other umbers and sometimes it is whole messages. The output should be "1,2" or "2,2"
Here are a couple of screenshots of the output of serial.readline().
I have tried to put a delay at before serial.readline() but it did not make a difference.
There is usually a strange character at the beginning:
I have also received strange messages:
There is a problem later on in the program that causes the program to hand because sometimes I just receive a blank line.
Is there a way to get consistent output from serial?
Here is the arduino code:
void setup() {
// initialize the LED pin as an output:
pinMode(ledPin, OUTPUT);
// initialize the pushbutton pin as an input:
pinMode(buttonPin, INPUT);
Serial.begin(9600);
}
void loop(){
// read the state of the pushbutton value:
buttonState = digitalRead(buttonPin);
// check if the pushbutton is pressed.
// if it is, the buttonState is HIGH:
if (buttonState == HIGH) {
// turn LED on:
digitalWrite(ledPin, HIGH);
Serial.println("1,2");
}
else {
// turn LED off:
digitalWrite(ledPin, LOW);
Serial.println("2,2");
}
}
And here is the python code:
ser = serial.Serial('/dev/ttyUSB0', 9600)
line=ser.readline()
coord= line.strip()
print coord
EDIT:
I tried putting ser.flushInput() after the ser.open() and I get the same output.
Have you flushed the serial buffer
ser.flushInput()
I've been having the same issue when interfacing between pyserial and Arduino. This may be an old post, but in case someone else is having the same trouble, I remedied my problem by inserting:
ser.flushInput()
...right before my ser.readline() call.
How to Read serial data from an Arduino in Linux
Nothing fancy here. Iā€™m getting the current port configuration, setting the input/output speed to 9600 baud, setting the data expectations to be 8 bits per word, with no parity bit and no stop bit, setting canonical mode, and then committing those changes back to the serial port.
If I am not mistaken you have to change the mentioned settings when connecting through serial port.
You do not mention it, but I guess you are using the pySerial library. Regardless you can use it with the correct settings to connect through serial. The constructor of the API allows all the parameters which are noted below:
Pyserial Library
I have not tested this approach as I have had a similar problem in C not Python.
What happens if you break it down to something simpler?
On the Arduino:
void setup()
{
Serial.begin(9600);
}
int i = 0;
void loop()
{
delay(1000);
Serial.print("Hello World ");
Serial.println(i);
i++;
}
And in the Python REPL...
import serial
ser = serial.Serial('/dev/ttyUSB0', 9600)
while(1):
ser.readline()
The first behavior you should observe is that when you initiate the serial connection, the Arduino reboots. This takes a few seconds.
The second behavior you should observe is that (if you're typing this in the REPL slowly) when the while(1) loop begins, you get all of the serial data that had accumulated since you initiated the serial connection. It takes me a few seconds to type all that out, so when I hit Enter after ser.readline() I see:
'Hello World 1\r\n'
'Hello World 2\r\n'
'Hello World 3\r\n'
I only mention this to make sure you're familiar with two things that burned me a bit the last time I messed with serial communication to an Arduino: it needs time to reboot after connecting, and the serial data buffers. readline() will only give you one line in the buffer - not everything that's in the buffer.
Is it possible you're trying to sent/receive data before it's done rebooting? What about button bounce - could a dozen high/low state detections be messing something up?

Changing XBee from 57.6k to 115.2k Causing Problems with TTL Camera and PySerial

I've been working on a simple XBee/Arduino/Python transfer system. Here's how it works: A hex command is sent from python over xbee, which is received by the arduino. This triggers it to take a picture using an Adafruit TTL Serial Camera. The image is then held in memory and sent over the xbee to the computer, 32 bytes at a time. The Python script then adds the bytes to a .jpg, to be viewed when it finishes.
As of now, both run fine, albeit a tad slow (~25 sec round-trip) for my needs. The problem is, switching from 57600 baud to 115200 in the xbee firmware and programs causes them to fail. They will sometimes give a .jpg roughly half the normal size, or not transmit at all, in both cases being unreadable from a viewer. I've tried changing the timeout in the python side, and modifying the xbee's interfacing options, all to no avail.
Here is the Arduino sketch (adapted largely from the Snapshot example sketch in the Adafruit VC0706 examples library):
#include <Adafruit_VC0706.h>
#include <SoftwareSerial.h>
#define chipSelect 10
SoftwareSerial cameraConnection = SoftwareSerial(2,3);
Adafruit_VC0706 cam = Adafruit_VC0706(&cameraConnection);
void setup()
{
Serial.begin(57600);
pinMode(8, OUTPUT);
if (cam.begin()){}
else { return; } //Abort the transfer if camera does not initialize
cam.setImageSize(VC0706_640x480);
}
void loop()
{
if (Serial.read() == 0x01) //Wait for send command
{
snapAndSend();
cam.reset();
}
}
void snapAndSend()
{
cam.takePicture();
uint16_t jpgLen = cam.frameLength();
while (jpgLen > 0)
{ //Send off 32 bytes of data at a time
uint8_t *buffer;
uint8_t bytesToRead = min(32, jpgLen);
buffer = cam.readPicture(bytesToRead);
Serial.write(buffer, bytesToRead);
jpgLen -= bytesToRead;
}
}
And the Python script:
import serial
import time
link = serial.Serial('COM12', 57600)
print("Engage!")
while True:
answer = input("Press enter to take a picture (type ' to exit): ")
if answer == "'":
break
file = open('imageTest.jpg', 'wb')
link.write(b"\x01")
time1 = time.time()
while True:
if link.inWaiting() > 0:
file.write(link.read())
time1 = time.time()
else:
time2 = time.time()
if (time2 - time1) > .5:
break
print ("Complete! Closing file now...")
file.close()
I'm still a bit new to serial communication and xbees, so I may be overlooking something here. Anyone more experienced have any thoughts on why a switch in baudrate breaks it?
I'm fairly certain that this is going to be related to flow control.
The XBee module can't keep up with a steady stream of data at 115200, so you need to configure it to use hardware flow control. In your case, you need to watch the CTS (clear to send) line from the XBee module, and have your program hold off on sending more data whenever it's not asserted (held low).
You can also configure the XBee to use one of its inputs for an RTS (request to send) signal -- the line the host uses to tell the XBee module when it's ready to receive data.
You may need to modify your Arduino code to receive the entire image from the camera into a buffer, and then slowly send it back out to the XBee module. If you were to check the CTS line before sending each byte, you could hold off whenever the XBee module's buffers were full. You'd need to call a function in your main loop to check the status of your buffered data, and the status of the pin to see if it was possible to send another byte.

Problem with Arduino and pySerial

I got a problem. I recently bought an Arduino Uno board. I tried to make something funny like controlling an input from my computer. I used Python with pySerial and the program is the following:
arduino = serial.Serial(portaCOM, 9600, timeout = 1)
... in loop ->
arduino.write(value)
def sliderUpdate(self, event):
pos = self.slider.GetValue()
arduino.write(pos)
time.sleep(.1)
print arduino.readline()
try:
arduino = serial.Serial(portaCOM, 9600, timeout = 1)
except:
print "Errore di connessione alla porta seriale"
The write value should send the value to my board though USB.
The program loaded on board is:
const int ledPin = 11;
byte brightness;
void setup(){
Serial.begin(9600);
pinMode(ledPin, OUTPUT);
}
void loop(){
while(Serial.available()){
brightness = Serial.read();
Serial.print(brightness);
analogWrite(ledPin, brightness); //LED doesn't refresh the brightness
delay(10);
}
}
My LED is working properly. I tried with the Fade example provided by Arduino and it's working..
I checked if the program is sending properly the data. Yes, it is. It returns the same thing I sent before.
It should retrieve the value sent and set analaogWriter(pin, VALUE), but something is wrong or not working.
How can I fix this problem?
Solution
The Arduino code
const int ledPin = 11;
byte valoreLed;
void setup(){
Serial.begin(9600);
pinMode(ledPin, OUTPUT);
}
void loop(){
while(Serial.available()){
valoreLed = Serial.read();
analogWrite(ledPin, valoreLed);
delay(20);
}
}
Python script code:
pos = self.slider.GetValue()
arduino.write(chr(pos))
Thank you to everybody!! :)
First of all, make sure your LED is properly connected. Anode (longer pin) to PWM 11 port and cathode (shorter pin) to ground, also you may need to add a resistor between cathode and ground depending on LED.
Make sure you're writing to the right port from python (that FTDI cable is associated with in your OS).
If you're not using FTDI cable with USB connector, make sure that all of the pins are connected to the right inputs.
What is the value of value in your example? Try arduino.write(chr(0xFF)), does LED stay lit?
I suspect that arduino.readline() waits for a newline, and you Arduino code never sends a newline. Hence the Python code blocks indefinitely after sending the first value.
I see in your comments that the LED works with the first character, but you don't see a change with the different characters. Definitely make sure you're sending ASCII characters that are significantly different from the previous characters, e.g. send an ASCII 0 followed by an ASCII 255.
Edit:
Since you say the FadeLED example works, can you just take that example and add serial port functionality to it? For example, only fade after a serial character is received. This will at least get you confident that the serial port and leds can coexist in code you write. Also, I assume you're using the FadeLED example from here. If so, make sure you've set the correct pin number, as the reference code uses pin 9, but your sample code uses pin 11.
Another Edit:
You say you receive the characters back properly from the Arduino, but you're using the pySerial ReadLine function, which should block until it sees a newline, and I don't see anything in the Arduino code that would generate a newline that wasn't sent to it first. To eliminate the number of variables in the question, try using HyperTerminal or a similar COM port program to send bytes to the Arduino, rather than your Python program. For example, you can send space characters (ASCII 32) and '}' characters (ASCII 125), which should be different enough to create a visible difference in the LED.
I would begin by establishing which side of the serial port harbours the problem.
First of all, can you drive the LED using a hard-coded loop on the Arduino. Does the LED change its brightness as expected?
Once that's out of the way, can you make the Arduino do something visibly correct when sending stuff manually from a terminal app (e.g. the one built into the Arduino IDE). This may require changes to the Arduino code.
Once that's working, I would then focus on the Python code, making sure you're talking to the right COM port etc.
"the write value should send the value to my board through USB"
If this is not a typo, then you can not use PySerial to access USB ports. There is pyUSB instead, and probably others.

Categories