Я работаю над скриптом Python, который отслеживает последовательный ввод со встроенного акселерометра Arduino 101. Он был адаптирован из скриптов, написанных для другого оборудования Arduino (их можно найти здесь).
При обнаружении изменения запускается скрипт Python display.exe (или XRandR в Linux), чтобы повернуть дисплей при обнаружении изменения. Это должно работать как с Linux, так и с Windows.
Arduino записывает строку в последовательный порт как <right>, <left>, <normal> и <inverted>. Эти значения прекрасно работают с XRandR в Linux, однако для 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). Поскольку это не сработало, в настоящее время я использую оператор 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")
Что значит "не получилось"? Что он выдал такого, чего вы не ожидали?
Перемещение translation после print("direction: " + direction) решило проблему! Также необходимо было вернуть «перевод [направление] обратно в команду». Версия этого скрипта для Linux, которую я использую, является обязательной + direction Я добавил вывод ошибки в свой вопрос. Спасибо!
Любая идея, почему это не запустилось, когда перевод был помещен в сценарий ранее?
где в сценарии это было изначально?
После инициализации последовательного устройства (строки с 42 по 50) ниже несколько строк комментариев, затем два разных перевода для Linux, затем для Windows (один будет закомментирован). прямо перед line_start = "Rotate Monitor <"
Я не понимаю, почему это повлияло на это, извините
Единственное, о чем я могу думать, это если вы переназначили перевод на что-то другое (и перезаписали свой словарь)
Ага, так и было сделано изначально. У меня это почему-то не сработало. Я не додумался его переместить, так что я попробую это завтра.