Reputation: 143
I am working on a python script that monitors serial input from an Arduino 101's onboard accelerometer. It has been adapted from scripts written for different Arduino hardware (these can be found here).
When a change is detected, the python script runs display.exe
(or XRandR
on linux) to rotate the display when a change is detected. This needs to work with both Linux and Windows.
The arduino writes a string to serial as <right>
, <left>
, <normal>
and <inverted>
. These values work fine with XRandR on Linux, however display.exe requires degree values (0, 90, 180, 270). So when direction
== normal
it should be converted to 0
... left
to 90
, etc.
The "translation" used in the original code did not work in my case (after adjusting it to match the output from my arduino), but here's an example of that for reference:
translation = {"Y_POS":"90",
"X_POS":"180",
"X_NEG":"0",
"Y_NEG":"270"}
I changed each input value (ex. Y_POS
to left
) Since this didn't work, Currently I'm using an if, elif, else statement for each possible value of direction
. There must be a less verbose way to achieve this. How can I achieve this without repeating things unnecessarily?
# 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")
When using translation = {"normal":"0, ...}
Error output was:
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: ----
Upvotes: 0
Views: 77
Reputation: 1702
You should just be able to replace each if/elif with:
command = "C:\Rotaytor\display.exe /device 2 /rotate:" + translation[direction]
print("running: " + command)
call(command, shell=True)
Based on a dictionary:
translation = {"normal": 0, ...}
So line 96 onwards would be:
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")
Upvotes: 1