When I run this script in terminal I can receive data serially, but eventually my entire computer freezes up. Could someone explain why this is happening?
#!/usr/bin/env python
from sys import argv
from msppg import Parser
import serial
if len(argv) < 2:
print('Usage: python %s PORT' % argv[0])
print('Example: python %s /dev/ttyUSB0' % argv[0])
exit(1)
def handler(pitch, roll, yaw):
print(pitch, roll, yaw)
port.write(request)
pitch, roll, yaw = 5, 15, 20
port = serial.Serial(argv[1])
parser = Parser()
request = parser.serialize_ATTITUDE_Request()
parser.set_ATTITUDE_Handler(handler)
def cycle(value):
return (value + 1) %360
while True:
print port.read(1)
if port.read(1) != None:
port.write(parser.serialize_ATTITUDE(pitch, roll, yaw))
pitch = cycle(pitch)
roll = cycle(roll)
yaw = cycle(yaw)
Could someone explain why this is happening?
while True: without a break.
It looks like the app is trying to read from a physical port and your while loop is constantly reading. This behavior will look up your computer as there are no waits or callbacks for reading the data.
Your issue is with the port.read(1) line. According to PySerial's Documentation you're specifying that you only want one byte to be read from the USART hardware buffer. However, if there isn't a byte to be read PySerial by default will wait for some data, causing your program to "freeze".
My suggestion is to add a timeout arg to the port init line (where 12 means 12 seconds, it can be anything you want)
port = serial.Serial(argv[1], timeout=12)
Related
I'm working with Python on my PC, sending serial commands to an arduino which controls a certain number of stepper motors.
However, in this function:
# takes array of commands to send to motors (in order) and sends commmand arcodinlgy
# each element of commands is an absolute angle (rad) to give to one motor
def send_command(commands):
if not len(commands) > 0:
return
# make command string to send serial
# (with command separator and line termination)
command_string = "";
for i in range(len(commands) - 1):
command_string += f"{commands[i]:.4f}{COMMAND_SEPARATOR}"
command_string += f"{commands[-1]:.4f}{LINE_TERMINATOR}"
# make command string into bytes UTF-8
# print(command_string)
command_string = bytes(command_string, "utf-8")
# send command string serial
print(f"Sending command: " + str(command_string))
port.write(command_string)
# wait for arduino's return_code on serial
while True:
if port.inWaiting() > 0:
return_code = int(port.readline())
return return_code
# driving code
while True:
commands = [0, 0]
commands[0] = float(input("command 1: "))
commands[1] = float(input("command 2: "))
return_code = send_command(commands)
print(f"return code: {return_code}")
This code works correctly, but if I don't want user input for the commands :
while True:
commands = [float(random.random()*pi), float(random.random()*pi)]
# or even the following doesn't work for exemple:
# commands = [3.1415, 0.5555]
return_code = send_command(commands)
print(f"return code: {return_code}")
sleep(1)
This code doesn't.
I don't get why because in the first case, the line print(f"Sending command: " + str(command_string)) prints exactly the same as in the second case :
Sending command: b'3.1415:0.5555\n'
(when input those angles)
But in the second case, no return code is received, and the function doesn't work.
I tried totally hardcoding the values given.
I implemented that the commands are always formated the same way, and always converted with float() (before the print("Serial command... line.
So I expected the same behavior for the two codes, and I don't see what changes between the two (since the print("Serial command ... line gives the same and is the last line before the command is sent over serial
Thanks !
Try to add logging to receiving part.
Replace this:
while True:
if port.inWaiting() > 0:
return_code = int(port.readline())
return return_code
With this:
import time
while True:
if port.inWaiting() > 0:
print(f"Received {port.inWaiting()} bytes.")
return_code = int(port.readline())
return return_code
print("Nothing received yet.")
time.sleep(0.1)
Maybe your Arduino does not response for request, and you just waiting for the response in infinite loop.
You can also add timeout for response, so after some time if there was no response method send_command(commands) will just return None.
Found the problem :
After every new serial connection, the Arduino resets.
When it resets, it need a little time to start the loop() function !
So when I was entering my commands manually, I gave it a little time without noticing, but when the commands were generated inside my Python code, the first command was sent so quickly that it wasn't interpreted by the Arduino, and the function didn't get a return code from the Arduino !
2 ways to solve the problem:
1. Adding a timeout
TIMEOUT = 2
TIMEOUT_ACTIVE = True
def send_command(commands):
### same code as above ###
port.write(command_string)
# wait for arduino's return_code on serial WITH TIMEOUT
init_time = time()
while (not TIMEOUT_ACTIVE) or (time() - init_time) <= TIMEOUT:
if port.inWaiting() > 0:
return_code = int(port.readline())
return return_code
2. Waiting before sending the first command
waiting 2 seconds (tested 1 seconds, was not enough) before begining to send commands
sleep(2)
while True:
commands = [float(random.random()*pi), float(random.random()*pi)]
return_code = send_command(commands)
print(f"return code: {return_code}")
# don't need the sleep(0.1) anymore
I am writing a program in python to scan the ports of the host and tell how many of them are open, show the time taken & have also added error handling...
This code is working fine but the problem is it is taking too long to scan all the ports (im talking about the time its taking to generate the full output) like it did not even complete in 1hr, is this normal? or what's wrong here.
secondly, I want the output of this program in a text file... I have tried several methods but none of them did work, one of the methods I tried is written at the end of the code in comment. Any help would be greatly appreciated. Thanks, in advance!
Here's the source code:
#!/usr/bin/env python
import socket
import subprocess
import sys
from datetime import datetime
# Clear the screen
subprocess.call('clear', shell=True)
# Ask for input
remoteServer = input("Enter a remote host to scan: ")
# Using the range function to specify ports (here it will scans all ports between 1 and 1024)
# We also put in some error handling for catching errors
try:
remoteServerIP = socket.gethostbyname(remoteServer)
# Prints a banner with info on which host we are about to scan
print ("-" * 60)
print ("Please wait, scanning remote host", remoteServerIP)
print ("-" * 60)
# Check what time the scan started
t1 = datetime.now()
for port in range(1,1025):
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
result = sock.connect_ex((remoteServerIP, port))
if result == 0:
print ("Port {}: Open".format(port))
sock.close()
except KeyboardInterrupt:
print ("You pressed Ctrl+C")
sys.exit()
except socket.gaierror:
print ('Hostname could not be resolved. Exiting')
sys.exit()
except socket.error:
print ("Host is not available")
sys.exit()
# Checking the time again
t2 = datetime.now()
# Calculates the difference of time, to see how long it took to run the script
total = t2 - t1
# Printing the information to screen
print ('Scanning Completed in: ', total)
'''#Text file
f = open('Hostreport.txt', 'a')
print(port,file=f)
f.close()'''
Two common ways to write simple text to a file in python:
with open('/tmp/foo.txt', 'w') as f:
f.write('first line\n')
f.write('second line\n')
Using open as a context manager means it's only valid within the block and python automatically takes care of ensuring it's properly closed at the end.
Or the classic way:
f = open('/tmp/bar.txt', 'w')
f.write('first line\n')
f.write('second line\n')
f.close()
I'm working on a script to send a list of commands to a device and return the output.
When the device first boots up, it has a few prompts. I am able to get through the prompts.
However, after completing the prompts, when I try to send a command the command isn't sent.
Commands
The commands.txt is set up like this:
200,
2,no
2,
The first line (200) is to let the device boot up.
The 2nd and 3rd lines answer 2 different prompts.
Issues
The issues come after these 3 inputs. The code runs and completes. Python prints out each of the commands. So the list is processed by Python. However, I don't think the device is receiving the commands.
In the log, the \n and no are written out, but none of the commands after it are. The commands do show when I use ser.inWaiting()
When I access the device through putty and run the commands through the console, everything works as expected.
Why aren't the commands going through?
Small update:
I read somewhere that python may be sending the commands to quickly, so I tried sending the commands 1 char at a time with a .01 delay.
It still didn't work:
for i in lines[1]:
cmd = i
encoded_cmd = cmd.encode("utf-8")
ser.write(encoded_cmd)
sleep(0.1)
print(cmd)
Code
import serial
import time
from time import sleep
from datetime import datetime
# create list of commands
with open('commands.txt') as commands:
list_of_commands = [tuple(map(str, i.split(','))) for i in commands]
# open and name log file
date = datetime.now().strftime("%Y-%m-%d")
log = open(f'{date}.txt', 'w+')
# serial configuration
info = open('info.txt', 'r')
lines = info.readlines()
port = lines[0].strip('\n')
baud = int(lines[1].strip('\n'))
try:
# open port
ser = serial.Serial(port=port, baudrate=baud, timeout=5, parity=serial.PARITY_NONE, stopbits=serial.STOPBITS_ONE, write_timeout=0)
except ConnectionError:
log.write(''.join('There was a connection error'))
else:
# run commands
x = 0
for lines in list_of_commands:
ser.close()
ser.open()
sleep(2)
cmd = lines[1]
encoded_cmd = cmd.encode("utf-8")
sleep_time = int(lines[0])
ser.write(encoded_cmd)
time.perf_counter()
# log output
while 1:
test = ser.readline()
text = test.decode('utf-8')
print(text)
log.write(''.join(text))
print(time.perf_counter())
print(time.perf_counter() - x)
if time.perf_counter() - x > sleep_time:
x = time.perf_counter()
ser.flushInput()
ser.flushOutput()
break
print(cmd)
# close port
ser.close()
# close files
log.close()
From the question it's obvious that multiple issues are intermingled. The same observation comes when reading the code. So I tried to list some of those I struggled with.
Issues
Try-except-else
What is the intention behind try .. except .. else ?
Not sure, its used correctly on purpose here. See try-except-else explained:
The else clause is executed if and only if no exception is raised. This is different from the finally clause that’s always executed.
The serial connection
Why opening and closing inside the loop:
ser.close()
ser.open()
Why the misleading comment:
# close server
ser.close()
Usage of sleep_time
What is the purpose of using the first column sleep_time of your CSV commands.txt inside a conditional break inside you read-loop?
sleep_time = int(lines[0])
Instead the sleep is fix 2 seconds before sending the command:
sleep(2)
How to debug
I would recommend adding some print (or log) statements to
verify the list_of_commands has been read correctly
verify which commands (cmd or even encoded_cmd) have been sent to the serial output
I am a bit of a newbie on Python, but was was testing some things I learned on Ubuntu.
Basically, this script is supposed to set your TCP/IP config, then restart the networking daemon and display the changes.
This is the whole script:
#!/usr/bin/env python
import commands
import os
import sys
euid = os.geteuid()
if euid != 0:
print "Script not started as root. Running sudo.."
args = ['sudo', sys.executable] + sys.argv + [os.environ]
# the next line replaces the currently-running process with the sudo
os.execlpe('sudo', *args)
print 'Running. Your euid is', euid
print "IP"
IP = raw_input(">>")
print "Gateway"
PE = raw_input(">>")
ifconfig = commands.getoutput("ifconfig")
interfaz = ifconfig[0:5]
ArchivoInterfaces = open("/etc/network/interfaces", "w")
ArchivoInterfaces.write("#auto lo\n#iface lo inet loopback\nauto %s\niface %sinet static\naddress %s\ngateway %s\nnetmask 255.255.255.0"%(interfaz, interfaz, IP, PE))
ArchivoInterfaces.close()
ArchivoResolv = open("/etc/resolv.conf", "w")
ArchivoResolv.write("# Generated by NetworkManager\ndomain localdomain\nsearch localdomain\nnameserver 8.8.8.8\nnameserver 8.8.4.4")
ArchivoResolv.close()
os.execlpe('/etc/init.d/networking', "test","restart", os.environ)
print "Todo esta correcto, su IP ahora es %s" %(IP)
fin = raw_input("write d and press enter to show the changes, or press enter to exit.")
if fin == "d":
ArchivoResolv = open("/etc/resolv.conf")
ArchivoInterfaces = open("/etc/network/interfaces")
ifconfig2 = commands.getoutput("ifconfig")
print "ARCHIVO resolv.conf\n"+ArchivoResolv.read()+"\n\n"+"ARCHIVO interfaces\n"+ArchivoInterfaces.read()+"\n\n"+"RESULTADO DE \"ifconfig\"\n"+ifconfig2
fin = raw_input("Presiona ENTER para salir.")
Unfortunately, it keeps stopping on this line - and I'm not sure why:
os.execlpe('/etc/init.d/networking', "test","restart", os.environ)
After reaching this spot, the script runs the restart, and then just exits.
I would love to get it to run the last part of the script so I can see what changed, but I'm unable. Any ideas?
Because all of the exec family of functions work by replacing the current process with the one you execute.
If you just want to run an external command, use the spawn functions instead. (In this case, os.spawnlpe is very nearly a drop-in replacement.)
os.execlpe (and the similar os.exec* functions) replace the current process:
These functions all execute a new program, replacing the current process; they do not return.
I used win7 before to read the GPS data from the com port. From now on I would like to read the data under Ubuntu but the same code is not working. Here is my code:
import serial, sys, time, threading
from datetime import datetime, timedelta
class MeasureModule():
def __init__(self, port, baudrate, sync_time=0, sync_nr=0):
self.port = port;
self.baudrate = baudrate;
def start(self):
try:
self.serial = serial.serial_for_url(self.port, self.baudrate, timeout=1)
except AttributeError:
self.serial = serial.Serial(self.port, self.baudrate, timeout=1)
start = time.clock()
while(time.clock()-start<11):
data = self.readline()
print(data)
self.stop();
def stop(self):
self.serial.close()
def readline(self, timeout=1, endline='\n'):
buff='';
try:
tic = time.clock()
ch = self.character(self.serial.read(1))
# you can use if not ('\n' in buff) too if you don't like re
while ((time.clock() - tic) < timeout) and (not ch in endline):
buff += ch
ch = self.character(self.serial.read(1))
except serial.SerialException, e:
return buff
return buff
def character(self,b):
if sys.version_info >= (3, 0):
return b.decode('latin1')
else:
return b
I called the function in the following way:
for i in range (0,4):
try:
print "Starting measurement /dev/ttyACM%d" % i
gs = GPSModule('/dev/ttyACM%d' % i, 4800, 1, 1)
gs.start()
except:
print "Unable to connect"
run#FXR:/dev$ dmesg | grep tty
[ 0.000000] console [tty0] enabled
[ 4.764464] cdc_acm 2-1.6:1.1: ttyACM0: USB ACM device
[ 4.767620] cdc_acm 2-1.6:1.3: ttyACM1: USB ACM device
[ 4.771525] cdc_acm 2-1.6:1.9: ttyACM2: USB ACM device
[ 4.808622] usb 2-1.4.4: pl2303 converter now attached to ttyUSB0
But I'm not receiving anything.
How can I do the same things under Ubuntu? How can I read the GPS data from com port?
Ok!
This code is VEEERY Ugly and Old I did that in 2006 I was a beginner and naive.
Now baby steps!
Use the command dmesg or check your console messages to know WHICH USB device is attached your GPS. In MY CASE was USB0
After that play with this code
import serial
import socket
ser = serial.Serial('/dev/ttyUSB0', 4800, timeout=1)
latitude = ''
longitude = ''
def readgps(latitude,longitude):
"""Read the GPG LINE using the NMEA standard"""
while True:
line = ser.readline()
if "GPGGA" in line:
latitude = line[18:26] #Yes it is positional info for lattitude
longitude = line[31:39] #do it again
return(latitude,longitude)
print "Finished"
Sure you have to call the function ;) please do not forget.
Remeber the gps is always sending data and communicating.
For educational purposes do a :
print line after ser.readline()
so you can see the whole data not only lat and long coordinates.
Remeber the USB GPS is just a fancy serial device ;)
This code is very simple and I am sure you will understand and make WAY better code/programs.
You don't open /dev/ttyUSB0 with your program. How is your GPS module plugged ?
What happens if you do :
stty -F /dev/ttyACM0 4800
cat /dev/ttyACM0
in a console ?
You probably have to add yourself to the group that the gps is under. This is posted really late, but I recently tried to configure a usb gps puck on linux, and I had to do sudo adduser -aG USERMAME dialout in the terminal. This just adds the user to the group (dialout) which the gps is under. If you don't know the group, cd to /dev (in terminal) and type ll (or ls -Flh if that doesn't work) This will diplay all of the permissions and groups. There is one column that is of particular interest; this is one of the last columns (I think third to last -- sorry, I'm on Windows right now), and you might see about six or seven items in the list called "dialout". If your file -- your usb -- shows up there, then that is the group. Otherwise, just look for the group and sudo adduser... yourself.
Be sure you log out first, and then -- after logging back in -- go to the terminal again and type cat /dev/ttyACM0. If you still see nothing, then you need to configure and tell it the correct rate at which to dump its info (the baud rate); so, type (as someone else mentioned) stty -F /dev/ttyACM0 4800 which configures the baud rate to 4800. You should google the correct baud rate, but the last command essentially says, take this file (-F) and speak to me at this rate (4800).
I hope this helps someone because I certainly had some trouble getting my usb gps puck to work on linux-mint. Good luck to all linux users (I'm a recent convert). :D