首页 > 解决方案 > 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>directionnormal0left90

原始代码中使用的“翻译”在我的情况下不起作用(在调整它以匹配我的 arduino 的输出之后),但这里有一个示例供参考:

translation = {"Y_POS":"90",
                 "X_POS":"180",
                 "X_NEG":"0",
                "Y_NEG":"270"}

我更改了每个输入值(例如更改Y_POSleft),因为这不起作用,目前我正在为每个可能的值使用 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: ----

标签: python-3.xwindowsarduino

解决方案


您应该能够将每个 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")

推荐阅读