我正在研究一个python脚本,它监视来自Arduino 101的板载加速度计的串行输入。它已经改编自为不同的Arduino硬件编写的脚本(这些可以找到here)。
当检测到更改时,python脚本运行display.exe
(或Linux上的XRandR
)以在检测到更改时旋转显示。这需要适用于Linux和Windows。
arduino将字符串写成<right>
,<left>
,<normal>
和<inverted>
。这些值适用于Linux上的XRandR,但display.exe需要度数值(0,90,180,270)。因此,当direction
== normal
时,它应该转换为0
... left
到90
等。
原始代码中使用的“翻译”在我的情况下不起作用(在调整它以匹配我的arduino的输出之后),但是这里有一个例子供参考:
translation = {"Y_POS":"90",
"X_POS":"180",
"X_NEG":"0",
"Y_NEG":"270"}
我改变了每个输入值(例如Y_POS
到left
)因为这不起作用,目前我正在为direction
的每个可能值使用if,elif,else语句。必须有一种不那么冗长的方式来实现这一目标。如何在不重复不必要的情况下实现这一目标?
# This python3.4 script is the computer-side component of my
# auto-rotating display project, which rotates a computer display
# automatically when the physical monitor is rotated
# Terminate this script before trying to program the Arduino.
# Similarly, do not have the Arduino serial viewer open whilst this script is
# running
import serial
import string
import time
from subprocess import call # for sending the command to rotate
import traceback # for debugging
# This function tries to initialise a serial connection on dev
# If no device is connected, it will fail
# If a non-Arduino device is connected there, it may connect
def initSerial(dev):
ser = serial.Serial(dev, 9600, timeout=1,
xonxoff=False, rtscts=False, dsrdtr=False)
ser.flushInput()
ser.flushOutput()
return ser
# This function tries to initialise a serial connection
# It blindly tries to connect to anything on possibleDevices
# If if fails, it waits then tries again.
# This function does not return until it succeeds
def waitForSerialInit():
# The Arduino can appear on any of these ports on my computer
# It may appear on different ports for you.
# To figure out which ones to use,
# 1) open the Arduino IDE
# 2) Click on Tools > Serial Port
# The devices listed there are what you should type here
possibleDevices = ["COM6", "COM3"] # Windows
# possibleDevices = ["/dev/ttyACM0","/dev/ttyACM1","/dev/ttyACM2"] # Linux
while True:
for dev in possibleDevices:
try:
ser = initSerial(dev)
print("device found on " + dev)
return ser
except Exception:
print("Failed to initialise device on " + dev)
time.sleep(5)
# depending on what orientation your accelerometer is relative to your monitor,
# you may have to adjust these.
# This is for when the Y axis points to the top of the monitor,
# And the bottom of the Arduino is against the monitor back
#
# The second string on each of these lines are the arguments sent in the
# terminal command to rotate. So if you want to try this on Mac or Windows,
# this is one of the things you'll need to change
#
# Only some of the stuff the Arduino sends will be a command
# Other stuff is just diagnostics
# We only want to rotate the display when the line starts and ends with
# these substrings. These must match what's in monitor.ino
line_start = "Rotate Monitor <"
line_end = ">"
# Ok, let's go.
# Start by initialising a serial connection to the Arduino
ser = waitForSerialInit()
while True:
try:
line = ser.readline().decode("utf-8")
except Exception:
# It's probably been unplugged
#
# But this also catches other types of errors,
# Which is not ideal.
print("error: ")
traceback.print_exc()
print("probably not plugged in")
time.sleep(5)
print("trying to init serial again")
ser = waitForSerialInit()
continue
if line == "":
continue # ignore empty lines
# print line for debugging purposes
print("line: " + line)
# check if the line starts with the special command start
if line.find(line_start) == 0:
#yes this is a command
direction = line.replace(line_start,"")
direction = direction[0:direction.find(line_end)]
print("direction: " + direction)
# check the direction is valid (so not NOT_SURE)
if direction == "normal":
command = "C:\Rotaytor\display.exe /device 2 /rotate:0"
print("running: " + command)
call(command, shell=True)
elif direction == "left":
command = "C:\Rotaytor\display.exe /device 2 /rotate:90"
print("running: " + command)
call(command, shell=True)
elif direction == "inverted":
command = "C:\Rotaytor\display.exe /device 2 /rotate:180"
print("running: " + command)
call(command, shell=True)
elif direction == "right":
command = "C:\Rotaytor\display.exe /device 2 /rotate:270"
print("running: " + command)
call(command, shell=True)
else:
print("invalid direction: " + direction)
print("ignoring")
当使用translation = {"normal":"0, ...}
错误输出时:
device found on COM6
line: change detected: 4
line: Rotate Monitor <right>
direction: right
translation: 270
running: C:\Rotaytor\display.exe /device 2 /rotate:right
Display - Version 1.2 (build 15), 32-bit.
Controls display brightness, contrast, orientation and power management.
© 2005-2014, Noël Danjou. All rights reserved.
Invalid parameter value(s):
/rotate (expected: 0,90,180,270,cw,ccw,default)
line: ----
你应该能够用以下内容替换每个if / elif:
command = "C:\Rotaytor\display.exe /device 2 /rotate:" + translation[direction]
print("running: " + command)
call(command, shell=True)
基于字典:
translation = {"normal": 0, ...}
所以第96行将是:
if line.find(line_start) == 0:
#yes this is a command
direction = line.replace(line_start,"")
direction = direction[0:direction.find(line_end)]
print("direction: " + direction)
translation = {"normal": 0, ...}
# check the direction is valid (so not NOT_SURE)
if direction in translation:
command = "C:\Rotaytor\display.exe /device 2 /rotate:" + translation[direction]
print("running: " + command)
call(command, shell=True)
else:
print("invalid direction: " + direction)
print("ignoring")