blob: 9332ca1eb957a9b0b68cae07226f948682476f6d [file] [log] [blame]
#
# Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
#
# A graphical point picker that gives visual feedback on the screen for the
# current robot finger location and displays coordinates, allowing fine
# positioning under manual control. Useful for registration of new device
# touch regions for use in other scripts. See the README for details on
# how it works, but most controls are visible at the top of the screen.
#
# Note: This program uses curses, and generally perfers a taller, 80 column
# terminal window in which to to run.
#
import sys
import time
import curses
import curses.textpad
import roibot
import run_program
# Open the robot interface.
robot_port = run_program.scan_serial_ports()
robot = roibot.ROIbot(port=robot_port,
baudrate=9600,
bytesize=8,
parity='E',
stopbits=1,
rtscts=0)
# If the robot doesn't respond in 2 seconds to a command, then something
# is wrong.
robot.timeout = 2
#
# Perform an operation on the robot
#
try:
# Clear outstanding error conditions (if any).
#
# This will clean up any bad outstanding state that exists from:
#
# o line noise from a previous connection
# o resulting from the robot responding to flow control events
# occuring during initialization of the serial port:
# o DTR off->on
# o CTS/RTS
# o etc.
#
print "COMMAND: Clear error status"
robot.assertCancelError()
print "COMMAND: Current status..."
for statusElement in roibot.error.statusReport(robot):
print " ", statusElement
print "COMMAND: Reset"
robot.assertReset()
print "COMMAND: Enable host mode"
if robot.modeHostON():
print "Host mode enabled"
else:
print "Failed to set host mode"
print "COMMAND: Servo ON"
if not robot.execServoON():
print "Servo failed"
for statusElement in roibot.error.statusReport(robot):
print " ", statusElement
# print "COMMAND: Return to origin"
# if not robot.execReturnToOrigin():
# print "origin reset failed"
#
# # Wait for completion
# roibot.motion.waitForExecution(robot)
# Show inaccuracy in settle at origin... :(
print "This is not precise unless we wait for it to settle..."
print robot.sendCommand("STAS", "SNO=0")
print robot.monRequestPresentPosition()
print robot.sendCommand("STAS", "SNO=0")
print robot.monRequestPresentPosition()
print robot.sendCommand("STAS", "SNO=0")
print robot.monRequestPresentPosition()
print robot.sendCommand("STAS", "SNO=0")
print robot.monRequestPresentPosition()
print robot.sendCommand("STAS", "SNO=0")
print robot.monRequestPresentPosition()
print robot.sendCommand("STAS", "SNO=0")
print robot.monRequestPresentPosition()
print "Starting..."
def showSpeed(stdscr, speed):
stdscr.move(0, 0)
stdscr.addstr("Speed: " + str(speed))
stdscr.move(0, 20)
stdscr.addstr("[1] = 10.00, [2] = 01.00, [3] = 00.10, [4] = 00.01")
def showAxis(stdscr, axis):
stdscr.move(1, 0)
stdscr.addstr("Axis: " + axis)
stdscr.move(1, 20)
stdscr.addstr("[<=] change axis down, [=>] change axis up")
def showKey(stdscr, key):
stdscr.move(2, 0)
if curses.ascii.isprint(key):
key = "'" + chr(key) + "'"
stdscr.addstr("Key : " + str(key) + " ")
stdscr.move(2, 20)
stdscr.addstr("[^] move toward origin, [v] move away from origin")
def showPosition(stdscr, position):
stdscr.move(3, 0)
stdscr.addstr("Loc: " + str(position))
#
# Display the current probe (finger) location as an x,y location with a
# pin altitude representing the z height as a negative offzet from max_z.
#
# A typical plot will look like:
#
# ,---------------,
# | |
# | |
# | |
# | o | --.
# | | | | z
# | | |x -'
# | |
# `---------------'
# y
#
def showSampleArea(stdscr, x, y, z):
# These numbers are based on screen coordinates
base_x = 10
base_y = 6
dim_x = 20
dim_y = 40
dim_z = 5
# These numbers reflect hardware limits of the robot itself
max_x = 400.00
max_y = 250.00
max_z = 100.00
inc_z = max_z / dim_z
# Sample area rectangle - not entirely within the motion rectangle!
#
# These numbers are selected relative to the area in which the
# cursor will move in order to describe the actual sample area;
# the negative and positive offsets are used to move the box
# outside.
#
# Moving the cursor outside the bounding rectange means that the
# robot is no longer over the sample area, and therefor no longer
# over the sample.
curses.textpad.rectangle(stdscr,
base_x - 1 - 2,
base_y - 1,
base_x + dim_x + 1 - 5,
base_y + dim_y + 1 + 20)
stdscr.move(base_x - 1 - 2, base_y + 10)
stdscr.addstr("Sample Area Rectangle")
# Motion rectangle; this is wehere the robot can reach. Unfortunately
# it does not precisely match the sample area rectangle, so there are
# portions of the sample area not reachable by the robot, and there
# are portions outside of the sample area that are reachable.
#
# Asserrtion: this is a hardware design bug.
#
# Like the above, there numbers are selected so that the cursor will
# not leave the motion area.
curses.textpad.rectangle(stdscr,
base_x - 1, base_y - 1,
base_x + dim_x + 1, base_y + dim_y + 1)
stdscr.move(base_x - 1, base_y + 10)
stdscr.addstr("Motion Rectangle")
point_x = int(base_x + ((x * dim_x) / max_x))
point_y = int(base_y + ((y * dim_y) / max_y))
lim_z = base_y + int(y)
stdscr.move(point_x, point_y)
if (z < max_z):
adj_z = int(max_z - z);
while (adj_z > 0):
stdscr.addstr("|")
point_x = point_x - 1
adj_z = adj_z - inc_z
stdscr.move(point_x, point_y)
stdscr.addstr("o")
def main(stdscr):
speed = "10.00"
axis = "X"
xjog = "+C"
yjog = "SP"
zjog = "SP"
wjog = "SP"
position = robot.monRequestPresentPosition()[1]
x = float(position[0].split("=")[1])
y = float(position[1].split("=")[1])
z = float(position[2].split("=")[1])
stdscr.clear()
showPosition(stdscr, position)
showSampleArea(stdscr, x, y, z)
showSpeed(stdscr, speed)
showAxis(stdscr, axis)
showKey(stdscr, 0)
stdscr.move(0, 0)
stdscr.refresh()
while True:
c = stdscr.getch()
if c != -1:
if c == ord('q'): # quit
break;
if c == ord('o'): # origin
robot.execReturnToOrigin()
roibot.motion.waitForExecution(robot)
elif c == ord('1'): # inching distance large
speed = "10.00"
stdscr.move(0, 0)
stdscr.addstr("Speed: " + str(speed))
robot.sendCommand("WPAR", "P12", "AX1=" + speed,
"AX2=" + speed,
"AX3=" + speed,
"AX4=" + speed)
elif c == ord('2'): # inching distance medium
speed = "01.00"
stdscr.move(0, 0)
stdscr.addstr("Speed: " + str(speed))
robot.sendCommand("WPAR", "P12", "AX1=" + speed,
"AX2=" + speed,
"AX3=" + speed,
"AX4=" + speed)
elif c == ord('3'): # inching distance small
speed = "00.10"
stdscr.move(0, 0)
stdscr.addstr("Speed: " + str(speed))
robot.sendCommand("WPAR", "P12", "AX1=" + speed,
"AX2=" + speed,
"AX3=" + speed,
"AX4=" + speed)
elif c == ord('4'): # inching distance tiny
speed = "00.01"
stdscr.move(0, 0)
stdscr.addstr("Speed: " + str(speed))
robot.sendCommand("WPAR", "P12", "AX1=" + speed,
"AX2=" + speed,
"AX3=" + speed,
"AX4=" + speed)
elif c == curses.KEY_UP: # Move probe negative on axis
robot.execJog(**{axis:"-C"})
roibot.motion.waitForExecution(robot)
elif c == curses.KEY_DOWN: # Move probe positive on axis
robot.execJog(**{axis:"+C"})
roibot.motion.waitForExecution(robot)
elif c == curses.KEY_LEFT:
if axis == 'X':
axis = 'Z'
elif axis == 'Z':
axis = 'Y'
elif axis == 'Y':
axis = 'X'
elif c == curses.KEY_RIGHT:
if axis == 'X':
axis = 'Y'
elif axis == 'Y':
axis = 'Z'
elif axis == 'Z':
axis = 'X'
position = robot.monRequestPresentPosition()[1]
x = float(position[0].split("=")[1])
y = float(position[1].split("=")[1])
z = float(position[2].split("=")[1])
stdscr.clear()
showPosition(stdscr, position)
showSampleArea(stdscr, x, y, z)
showSpeed(stdscr, speed)
showAxis(stdscr, axis)
showKey(stdscr, c)
stdscr.move(0,0)
stdscr.refresh()
if __name__ == '__main__':
curses.wrapper(main)
print "done"
except roibot.roibot.ROIbotTimeoutException:
# timeouts - usually communications or stuck servo related
print "timed out!"
#except:
# all other errors
print "Exception!"
for statusElement in roibot.error.statusReport(robot):
print " ", statusElement
robot.timeout = None
robot.close()