python-3.x - Python:根据原始值更改字符串
问题描述
我正在研究一个 python 脚本,它监视来自 Arduino 101 的板载加速度计的串行输入。它改编自为不同 Arduino 硬件编写的脚本(可在此处找到)。
当检测到更改时,python 脚本会运行display.exe
(或XRandR
在 linux 上)以在检测到更改时旋转显示。这需要同时适用于 Linux 和 Windows。
arduino 将一个字符串作为<right>
、<left>
和. 这些值适用于 Linux 上的 XRandR,但 display.exe 需要度数值(0、90、180、270)。所以当==它应该被转换为...到等。<normal>
<inverted>
direction
normal
0
left
90
原始代码中使用的“翻译”在我的情况下不起作用(在调整它以匹配我的 arduino 的输出之后),但这里有一个示例供参考:
translation = {"Y_POS":"90",
"X_POS":"180",
"X_NEG":"0",
"Y_NEG":"270"}
我更改了每个输入值(例如更改Y_POS
为left
),因为这不起作用,目前我正在为每个可能的值使用 if、elif、else 语句direction
。必须有一种不那么冗长的方法来实现这一点。我怎样才能在不重复不必要的事情的情况下做到这一点?
# 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")
推荐阅读
- flutter - 无法在颤动中进行映射
- javascript - 无法将未定义转换为对象
- pentaho - 如何在 linux 中使用数据参数执行 .ktr 文件(另一种转换)?
- laravel - 如何更正下图中的错误?
- java - 尝试获取与设定时区相比的本地时区
- xslt - 如何在不丢失兄弟数据的情况下基于子组复制 XML
- java - 如何为 Overide 方法编写 Junit 测试
- android - 用 Kotlin 协程实现 Observale.amb?
- google-apps-script - 如何从另一个工作表的另一行中删除具有与单元格相关内容的行?
- javascript - 如何使用 puppeteer 从 json 文件中获取数据到 js