This question already has an answer here:
-
Python to automatically select serial ports (for Arduino)
4 answers
I have a problem automagically detecting my Arduino's serial port in Python, using Mac/Linux.
I know a working shell command to find the port; because Arduino serial ports almost always begin with tty.usbmodem
, you can find the serial port with ls /dev | grep tty.usbmodem
which should return something like tty.usbmodem262141
.
However, I'm confused on how to call this shell command from my Python code. I've tried this:
p = "/dev/" + str(subprocess.Popen('ls /dev | grep tty.usbmodem', shell=True).stdout)
Which should make p
become /dev/tty.usbmodem262141
.
However, at the moment I get /dev/None
.
How can I modify my shell script call to return the right string? I've tried to use several commands to call shell scripts, but none have worked.
First of all, if you're using a shell, you can use a glob (*
), so your command would become ls /dev/tty.usbmodem*
.
Next, you don't even have to call a shell command to use a glob in Python!
Consider the following code:
import glob
print(glob.glob("/dev/tty.usbmodem*"))
I wrote this to find out what dev the arduino was plugged into on osx 10.7.x : enjoy.
#!/usr/bin/env bash
# script name: findtty.sh
# author: Jerry Davis
#
# this little script determines what usb tty was just plugged in
# on osx especially, there is no utility that just displays what the usb
# ports are connected to each device.
#
# I named this script findtty.sh
# if run interactively, then it prompts you to connect the cable and either press enter or it will timeout after 10 secs.
# if you set up an alias to have it run non-interactively, then it will just sleep for 10 secs.
# either way, this script gives you 10 seconds to plug in your device
# if run non interactively, a variable named MCPUTTY will be exported, this would be an advantage.
# it WAS an advantage to me, otherwise this would have been a 4 line script. :)
#
# to set up an alias to run non-interactively, do this:
# osx: $ alias findtty='source findtty.sh',
# or linux: $ alias findtty='. findtty.sh' (although source might still work)
\ls -1 /dev/tty* > before.tty.list
if [ -z "$PS1" ]; then
read -s -n1 -t 10 -p "Connect cable, press Enter: " keypress
echo
else
sleep 10
fi
\ls -1 /dev/tty* > after.tty.list
ftty=$(diff before.tty.list after.tty.list 2> /dev/null | grep '>' | sed 's/> //')
echo $ftty
rm -f before.tty.list after.tty.list
export MCPUTTY=$ftty # this will have no effect if running interactively
I've used this code to auto detect serial ports on linux. Its based on some code I found in the MAVLINK project.
import fnmatch
import serial
def auto_detect_serial_unix(preferred_list=['*']):
'''try to auto-detect serial ports on win32'''
import glob
glist = glob.glob('/dev/ttyUSB*') + glob.glob('/dev/ttyACM*')
ret = []
# try preferred ones first
for d in glist:
for preferred in preferred_list:
if fnmatch.fnmatch(d, preferred):
ret.append(d)
if len(ret) > 0:
return ret
# now the rest
for d in glist:
ret.append(d)
return ret
def main():
available_ports = auto_detect_serial_unix()
port = serial.Serial(available_ports[0], 115200,timeout=1)
return 0
if __name__ == '__main__':
main()
Another way of solving this if you want a purely shell solution is to use a combination of 'ls' and awk which I have found handy for all kinds of niche applications.
First plug in your Arduino and make sure it shows up when you do
ls /dev/tty*
crw-rw---- 1 root dialout 166, 0 2012-10-16 18:37 /dev/ttyACM0
My Arduino Uno shows up as a ttyACM* so I modified the command to be more selective and then piped the output to awk which can then print space delimited fields very easily.
ls /dev/ttyACM* | awk {'print $9'}
/dev/ttyACM0
You will still have to do something with the final output such as export it to use in the shell or send to a file for later reading.