Asynchronous Peripherals¶
This section describes how to access some miscellaneous peripherals on the Linkbot, such as the buttons, accelerometer, multicolor LED, and buzzer. The functions described here are asynchronous in nature, designed to be used with Python 3.5’s new asyncio module.
Accelerometer¶
A Linkbot’s accelerometer object can be accessed via the “accelerometer” member of the AsyncLinkbot class. For instance,
import linkbot3 as linkbot
import asyncio
async def cb(*args):
print(args)
async def task(serial_id):
l = await linkbot.AsyncLinkbot.create(serial_id)
r_fut = await l.accelerometer.values()
print('Current accel values: ', await r_fut)
r_fut = await l.accelerometer.x()
print('Current X axis value: ', await r_fut)
r_fut = await l.accelerometer.y()
print('Current y axis value: ', await r_fut)
r_fut = await l.accelerometer.z()
print('Current z axis value: ', await r_fut)
print('Enabling accelerometer events for 5 seconds...')
await l.accelerometer.set_event_handler(cb)
await asyncio.sleep(5)
print('Done. Disabling accelerometer events...')
await l.accelerometer.set_event_handler()
loop = asyncio.get_event_loop()
loop.run_until_complete(task('7944'))
loop.close()
-
class
linkbot3.async.peripherals.Accelerometer¶ -
set_event_handler(callback=None, granularity=0.05)¶ Set a callback function to be executed when the accelerometer values on the robot change.
Parameters: - callback – async func(x, y, z, timestamp) -> None
- granularity – float . The callback will only be called when any axis of the accelerometer changes by this many G’s of acceleration.
-
values()¶ Get the current accelerometer values.
Return type: asyncio.Future . The future’s result type is (float, float, float) representing the x, y, and z axes, respectively. The units of each value are in Earth gravitational units (a.k.a. G’s).
-
x()¶ Get the current x axis value.
Return type: asyncio.Future. The future’s result type is “float”, in units of Earth gravitational units (a.k.a. G’s)
-
y()¶ Get the current y axis value.
Return type: asyncio.Future. The future’s result type is “float”, in units of Earth gravitational units (a.k.a. G’s)
-
z()¶ Get the current z axis value.
Return type: asyncio.Future. The future’s result type is “float”, in units of Earth gravitational units (a.k.a. G’s)
-
Battery¶
Get a Linkbot’s current battery voltage or percentage level.
-
class
linkbot3.async.peripherals.Battery¶ -
percentage()¶ Return an estimated battery percentage.
This function estimates the battery charge level based on the current voltage of the battery. The battery voltage discharge curve is highly non-linear, and this function uses three cubic curve-fit equations to generate a “best guess” of the battery level as a percentage.
See https://docs.google.com/spreadsheets/d/1nZYGi2s-gs6waFfvLNPQ9SBCAgTuzwL0sdIo_FG3BQA/edit?usp=sharing for the formula, charts, and graphs.
Also note that both the battery voltage and percentage values returned by the robot will be inaccurate while the robot is being charged.
Returns: A value from 0 to 100 representing the charge of the battery. Return type: asyncio.Future
-
voltage()¶ Get the current battery voltage.
Returns: An asyncio.Future. The result of the future is the current battery voltage. Return type: asyncio.Future
-
Buttons¶
A Linkbot’s button functions can be overridden from their default functions. The power button can also be overridden, but the robot will still turn off if the button is held for more than 2 seconds. The power-off button functionality cannot be overridden. For example,
import linkbot3 as linkbot
import asyncio
async def cb(*args):
print(args)
async def task(serial_id):
l = await linkbot.AsyncLinkbot.create(serial_id)
r_fut = await l.button.values()
print('Current button values: ', await r_fut)
r_fut = await l.button.pwr()
print('Current power button value: ', await r_fut)
r_fut = await l.button.a()
print('Current "a" button value: ', await r_fut)
r_fut = await l.button.b()
print('Current "b" button value: ', await r_fut)
print('Enabling button events for 5 seconds... This will override default '
'button functionality')
await l.button.set_event_handler(cb)
await asyncio.sleep(5)
print('Done. Removing button handler to restore button functionality...')
await l.button.set_event_handler()
loop = asyncio.get_event_loop()
loop.run_until_complete(task('7944'))
loop.close()
-
class
linkbot3.async.peripherals.Button¶ -
a()¶ Get the current state of the ‘A’ button.
Return type: either Button.UP or Button.DOWN
-
b()¶ Get the current state of the ‘B’ button.
Return type: either Button.UP or Button.DOWN
-
pwr()¶ Get the current state of the power button.
Return type: either Button.UP or Button.DOWN
-
set_event_handler(callback=None)¶ Set a callback function to be executed when there is a button press or release.
Parameters: callback – func(buttonNo(int), buttonDown(bool), timestamp) -> None
-
values()¶ Get the current button values
Return type: asyncio.Future . Result type is (int, int, int), indicating the button state for the power, A, and B buttons, respectively. The button state is one of either Button.UP or Button.DOWN.
-
Buzzer¶
The Linkbot’s buzzer can play tones ranging from low buzzes to frequencies higher than most humans can perceive.
Multi-Color LED¶
Control a Linkbot’s LED color through this interface.
import linkbot3 as linkbot
import asyncio
import time
import math
async def task(serial_id):
l = await linkbot.AsyncLinkbot.create(serial_id)
fut = await l.led.color()
print('Current led color: ', await fut)
print('Morphing LED colors for 10 seconds...')
start_time = time.time()
while time.time()-start_time < 10:
red = 128+128*math.sin(time.time())
green = 128+128*math.sin(time.time() + 2*math.pi/3)
blue = 128+128*math.sin(time.time() + 4*math.pi/3)
print('Setting color to: ', red, green, blue)
fut = await l.led.set_color(int(red), int(green), int(blue))
await fut
loop = asyncio.get_event_loop()
loop.run_until_complete(task('7944'))
loop.close()
Motor¶
Move and sense from individual motors.
import linkbot3 as linkbot
import asyncio
async def task(serial_id):
l = await linkbot.AsyncLinkbot.create(serial_id)
accel = await l.motors[0].accel()
decel = await l.motors[0].decel()
print('Current accel, decel values: ', await accel, await decel)
print('Setting to a slow value of 30 deg/s/s')
fut = await l.motors[0].set_accel(30)
await fut
fut = await l.motors[0].set_decel(30)
await fut
fut = await l.motors[0].set_omega(180)
await fut
print('Testing a series of smooth movements...')
fut = await l.motors[0].set_controller(linkbot.Motor.Controller.SMOOTH)
await fut
angle = 360
for i in range(5):
fut = await l.motors[0].move(angle)
await fut
fut = await l.motors[0].move_wait()
await fut
fut = await l.motors[0].move(-angle)
await fut
fut = await l.motors[0].move_wait()
await fut
angle /= 2
print('Testing again with faster accel/decel of 120 deg/s/s')
fut = await l.motors[0].set_accel(120)
await fut
fut = await l.motors[0].set_decel(120)
await fut
angle = 360
for i in range(5):
fut = await l.motors[0].move(angle)
await fut
fut = await l.motors[0].move_wait()
await fut
fut = await l.motors[0].move(-angle)
await fut
fut = await l.motors[0].move_wait()
await fut
angle /= 2
loop = asyncio.get_event_loop()
loop.run_until_complete(task('7944'))
loop.close()
-
class
linkbot3.async.peripherals.Motor¶ The asynchronous representation of a Linkbot’s motor.
See also
linkbot3.peripherals.Motorfor the synchronous counterpart.-
accel()¶ Get the acceleration setting of a motor
Return type: float Returns: The acceleration setting in units of deg/s/s
-
angle()¶ Get the current motor angle of a motor
Return type: float Returns: The current angle in degrees.
-
begin_accel(timeout, v0=0.0, state_on_timeout=0)¶ Cause a motor to begin accelerating indefinitely.
The joint will begin accelerating at the acceleration specified previously by
linkbot3.async.peripherals.Motor.accel(). If a timeout is specified, the motor will transition states after the timeout expires. The state the motor transitions to is specified by the parameter`state_on_timeout`.If the robot reaches its maximum speed, specified by the function
linkbot3.async.peripherals.Motor.set_omega(), it will stop accelerating and continue at that speed until the timeout, if any, expires.Parameters: - timeout (float) – Seconds to wait before robot transitions states.
- v0 (float) – Initial velocity in deg/s
- state_on_timeout (
linkbot3.peripherals.Motor.State) – End state after timeout
-
begin_move(timeout=0, forward=True, state_on_timeout=0)¶ Begin moving motor at constant velocity
The joint will begin moving at a constant velocity previously set by
linkbot3.async.peripherals.Motor.set_omega().Parameters: - timeout (float) – After
`timeout`seconds, the motor will transition states to the state specified by the parameter`state_on_timeout`. - forward (bool) – Whether to move the joint in the positive direction (True) or negative direction (False).
- state_on_timeout (
linkbot3.peripherals.Motor.State) – State to transition to after the motion times out.
- timeout (float) – After
-
controller()¶ The movement controller.
This property controls the strategy with which the motors are moved. Legal values are:
linkbot3.peripherals.Motor.Controller.PID: Move the motors directly with the internal PID controller. This is typically the fastest way to get a motor from one position to another. The motor may experience some overshoot and underdamped response when moving larger distances.linkbot3.peripherals.Motor.Controller.CONST_VEL: Move the motor at a constant velocity. This motor controller attemts to accelerate and decelerate a motor infinitely fast to and from a constant velocity to move the motor from one position to the next. The velocity can be controlled by setting the property omega.linkbot3.peripherals.Motor.Controller.SMOOTH: Move the motor with specified acceleration, maximum velocity, and deceleration. For this type of movement, access maximum velocity with property omega, acceleration with property acceleration, and deceleration with property deceleration.
-
decel()¶ Get the deceleration setting of a motor
Return type: float Returns: The deceleration setting in units of deg/s/s
-
move(angle, relative=True)¶ Move the motor.
Parameters: - angle (float) – The angle to move the motor.
- relative (bool) – Determines if the motor should move to an absolute position or perform a relative motion. For instance, if the motor is currently at a position of 45 degrees, performing a relative move of 90 degrees will move the motor to 135 degrees, while doing an absolute move of 90 degrees will move the motor forward by 45 degrees until it reaches the absolute position of 90 degrees.
-
move_wait()¶ Wait for a motor to stop moving.
Returns an asyncio.Future(). The result of the future is set when the motor has stopped moving, either by transitioning into a “COAST” state or “HOLD” state.
-
omega()¶ Get the rotational velocity setting of a motor
Return type: float Returns: The speed setting of the motor in deg/s
-
set_accel(value)¶ Set the acceleration of a motor.
Parameters: value (float) – The acceleration in deg/s/s
-
set_controller(value)¶ Set the controller type of a motor.
-
set_decel(value)¶ Set the deceleration of a motor.
Parameters: value (float) – Deceleration in deg/s/s See also:
linkbot3.async.peripherals.Motor.decel()
-
set_event_handler(callback=None, granularity=2.0)¶ Set a callback function to be executed when the motor angle values on the robot change.
Parameters: - callback – async func(angle, timestamp) -> None
- granularity – float . The callback will only be called when a motor moves away from its current position by more than ‘granularity’ degrees.
-
set_omega(value)¶ Set the speed of the motor.
Parameters: value (float) – The new speed in deg/s See also:
linkbot3.async.peripherals.Motor.omega()
-
set_power(power)¶ Set the motor’s power.
This function directly controls the duty cycle of the PWM driving the motors.
-
Motors¶
-
class
linkbot3.async.peripherals.Motors¶ The Motors class.
This class represents all of the motors on-board a Linkbot. To access an individual motor, this class may be indexed. For instance, the line:
linkbot.motors[0]
accesses the first motor on a Linkbot, which is of type
linkbot3.async.peripherals.Motor-
angles()¶ Get the current joint angles.
Returns: (angle1, angle2, angle3, timestamp) . These are the three robot joint angles and a timestamp from the robot which is the number of milliseconds the robot has been on. Return type: (float, float, float, int)
-
begin_move(mask=7, timeouts=(0, 0, 0), forward=(True, True, True), states_on_timeout=(0, 0, 0))¶ Begin moving motors at constant velocity
The joint will begin moving at a constant velocity previously set by
linkbot3.async.peripherals.Motor.set_omega().Parameters: - timeout ((float, float, float)) – After
`timeout`seconds, the motor will transition states to the state specified by the parameter`state_on_timeout`. - forward ((bool, bool, bool)) – Whether to move the joint in the positive direction (True) or negative direction (False).
- state_on_timeout ((
linkbot3.peripherals.Motor.State,)*3) – State to transition to after the motion times out.
- timeout ((float, float, float)) – After
-
move(angles, mask=7, relative=True, timeouts=None, states_on_timeout=None)¶ Move a Linkbot’s joints
Parameters: - angles ([float, float, float]) – A list of angles in degrees
- mask –
Which joints to actually move. Valid values are:
- 1: joint 1
- 2: joint 2
- 3: joints 1 and 2
- 4: joint 3
- 5: joints 1 and 3
- 6: joints 2 and 3
- 7: all 3 joints
- relative (bool) – This flag controls whether to move a relative distance from the motor’s current position or to an absolute position.
- timeouts ([float, float, float]) – Sets timeouts for each motor’s movement, in seconds. If
the timeout expires while the motor is in motion, the motor will
transition to the motor state specified by the
states_on_timeoutparameter.
-
reset()¶ Reset the revolution-counter on the Linkbot.
When a Linkbot’s motor turns more than 360 degrees, the motor’s reported angle does not wrap back around to zero. For instance, if a motor is rotated ten times, retrieving the motor angle would yield a value of something like 3600 degrees. Similarly, if a motor is currently at 3600 degrees and it receives an instruction to move to an absolute position of 0 degrees, the motor will “wind down” backwards ten full rotations.
This function resets the internal counter on the Linkbot that stores multiple revolutions on the robot. For instance, if the robot angle is currently 3610, after a
`reset()`, the motor will report to be at an angle of 10 degrees.
-
set_event_handler(callback=None, granularity=2.0)¶ Set an event handler for all motors. The event handler will be invoked when a motor angle value changes by more than the amount specified by “granularity”.
Parameters: - callback – async func(encoder_number, angle, timestamp) -> None
- granularity – float . The callback will only be called when a motor moves away from its current position by more than ‘granularity’ degrees.
-
set_powers(powers, mask=7)¶ Set the PWM duty cycle on the Linkbot’s motors
Parameters: - powers – A list of powers ranging in value from -255 to 255
- mask –
Which joints to actually move. Valid values are:
- 1: joint 1
- 2: joint 2
- 3: joints 1 and 2
- 4: joint 3
- 5: joints 1 and 3
- 6: joints 2 and 3
- 7: all 3 joints
-
stop(mask=7)¶ Immediately stop all motors.
Parameters: mask – See linkbot3.async_peripherals.Motors.move()
-