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.

class linkbot3.async.peripherals.Buzzer
frequency()

Get the current buzzer frequency.

Returns:Frequency in Hz
Return type:float
set_frequency(hz)

Set the buzzer frequency.

Parameters:hz (float) – A frequency in Hz.

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()

class linkbot3.async.peripherals.Led
color()

Get the current LED color.

Return type:(int, int, int) indicating the intensity of the red, green, and blue channels. Each intensity is a value between [0,255].
set_color(r, g, b)

Set the current LED color.

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.Motor for 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.
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

See linkbot3.async.peripherals.Motor.accel()

set_controller(value)

Set the controller type of a motor.

See alse: linkbot3.async.peripherals.Motor.controller()

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.
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_timeout parameter.
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()