Input controller API
The input controller API allows you to give commands to your input controller components for configuring callbacks for events, allowing you to configure input devices to control your machines.
The input controller component supports the following methods:
Method Name | Description |
---|---|
GetControls | Get a list of the Controls that your controller provides. |
GetEvents | This method returns the current state of the controller as a map of Event Objects, representing the most recent event that has occurred on each available Control. |
TriggerEvent | Directly send an Event Object from external code. |
GetGeometries | Get all the geometries associated with the input controller in its current configuration, in the frame of the input controller. |
RegisterControlCallback | Defines a callback function to execute whenever one of the EventTypes selected occurs on the given Control. |
Reconfigure | Reconfigure this resource. |
DoCommand | Execute model-specific commands that are not otherwise defined by the component API. |
GetResourceName | Get the ResourceName for this input controller with the given name. |
Close | Safely shut down the resource and prevent further use. |
Establish a connection
Once you’ve configured your input controller according to model type, you can write code to define how your machine processes the input from the controller.
To get started using Viam’s SDKs to connect to and control your machine, go to your machine’s page on the Viam app, navigate to the CONNECT tab’s Code sample page, select your preferred programming language, and copy the sample code.
API key and API key ID
By default, the sample code does not include your machine API key and API key ID. We strongly recommend that you add your API key and API key ID as an environment variable and import this variable into your development environment as needed.
To show your machine’s API key and API key ID in the sample code, toggle Include API key on the CONNECT tab’s Code sample page.
Caution
Do not share your API key or machine address publicly. Sharing this information could compromise your system security by allowing unauthorized access to your machine, or to the computer running your machine.
When executed, this sample code creates a connection to your machine as a client.
The following examples assume you have an input controller called "my_controller"
configured as a component of your machine.
If your input controller has a different name, change the name
in the code.
Be sure to import the input controller package for the SDK you are using:
from viam.components.input import Control, Controller, EventType
import (
"go.viam.com/rdk/components/input"
)
API
GetControls
Get a list of the Controls that your controller provides.
Parameters:
extra
(Mapping[str, Any]) (optional): Extra options to pass to the underlying RPC call.timeout
(float) (optional): An option to set how long to wait (in seconds) before calling a time-out and closing the underlying RPC call.
Returns:
- (List[viam.components.input.input.Control]): List of controls provided by the Controller.
Example:
# Get the controller from the machine.
my_controller = Controller.from_robot(
robot=myRobotWithController, name="my_controller")
# Get the list of Controls provided by the controller.
controls = await my_controller.get_controls()
# Print the list of Controls provided by the controller.
print(f"Controls: {controls}")
For more information, see the Python SDK Docs.
Parameters:
ctx
(Context): A Context carries a deadline, a cancellation signal, and other values across API boundaries.extra
(map[string]interface{}): Extra options to pass to the underlying RPC call.
Returns:
- ([]Control): List of Controls provided by the controller.
- (error): An error, if one occurred.
Example:
// Get the list of Controls provided by the controller.
controls, err := myController.Controls(context.Background(), nil)
For more information, see the Go SDK Docs.
GetEvents
This method returns the current state of the controller as a map of Event Objects, representing the most recent event that has occurred on each available Control.
Parameters:
extra
(Mapping[str, Any]) (optional): Extra options to pass to the underlying RPC call.timeout
(float) (optional): An option to set how long to wait (in seconds) before calling a time-out and closing the underlying RPC call.
Returns:
- (Dict[viam.components.input.input.Control, viam.components.input.input.Event]): The most recent event for each input.
Example:
# Get the controller from the machine.
my_controller = Controller.from_robot(
robot=myRobotWithController, name="my_controller")
# Get the most recent Event for each Control.
recent_events = await my_controller.get_events()
# Print out the most recent Event for each Control.
print(f"Recent Events: {recent_events}")
For more information, see the Python SDK Docs.
Parameters:
ctx
(Context): A Context carries a deadline, a cancellation signal, and other values across API boundaries.extra
(map[string]interface{}): Extra options to pass to the underlying RPC call.
Returns:
- (map[Control]Event): A map mapping the most recent Event for each Control.
- (error): An error, if one occurred.
Example:
// Get the most recent Event for each Control.
recent_events, err := myController.Events(context.Background(), nil)
For more information, see the Go SDK Docs.
TriggerEvent
Directly send an Event Object from external code.
Support Notice
This method is currently only supported for input controllers of model webgamepad
.
Parameters:
event
(viam.components.input.input.Event) (required): The event to trigger.extra
(Mapping[str, Any]) (optional): Extra options to pass to the underlying RPC call.timeout
(float) (optional): An option to set how long to wait (in seconds) before calling a time-out and closing the underlying RPC call.
Returns:
- None.
Example:
# Define a "Button is Pressed" event for the control BUTTON_START.
button_is_pressed_event = Event(
time(), EventType.BUTTON_PRESS, Control.BUTTON_START, 1.0)
# Trigger the event on your controller. Set this trigger to timeout if it has
# not completed in 7 seconds.
await myController.trigger_event(event=my_event, timeout=7.0)
For more information, see the Python SDK Docs.
Parameters:
ctx
(Context): A Context carries a deadline, a cancellation signal, and other values across API boundaries.event
(Event): TheEvent
to trigger on the controller.extra
(map[string]interface{}): Extra options to pass to the underlying RPC call.
Returns:
- (error): An error, if one occurred.
For more information, see the Go SDK Docs.
GetGeometries
Get all the geometries associated with the input controller in its current configuration, in the frame of the input controller. The motion and navigation services use the relative position of inherent geometries to configured geometries representing obstacles for collision detection and obstacle avoidance while motion planning.
Parameters:
extra
(Mapping[str, Any]) (optional): Extra options to pass to the underlying RPC call.timeout
(float) (optional): An option to set how long to wait (in seconds) before calling a time-out and closing the underlying RPC call.
Returns:
- (List[viam.proto.common.Geometry]): The geometries associated with the Component.
Example:
geometries = await my_input_controller.get_geometries()
if geometries:
# Get the center of the first geometry
print(f"Pose of the first geometry's centerpoint: {geometries[0].center}")
For more information, see the Python SDK Docs.
RegisterControlCallback
Defines a callback function to execute whenever one of the EventTypes selected occurs on the given Control.
You can only register one callback function per Event for each Control. A second call to register a callback function for a EventType on a Control replaces any function that was already registered.
You can pass a nil
function here to “deregister” a callback.
Tip
Registering a callback for the ButtonChange
EventType is merely a convenience for filtering.
Doing so registers the same callback to both ButtonPress
and ButtonRelease
, but ButtonChange
is not reported in an actual Event Object.
Parameters:
control
(viam.components.input.input.Control) (required): The control to register the function for.triggers
(List[viam.components.input.input.EventType]) (required): The events that will trigger the function.function
(viam.components.input.input.ControlFunction) (optional): The function to run on specific triggers.extra
(Mapping[str, Any]) (optional): Extra options to pass to the underlying RPC call.
Returns:
- None.
Example:
# Define a function to handle pressing the Start Menu Button "BUTTON_START" on
# your controller, printing out the start time.
def print_start_time(event):
print(f"Start Menu Button was pressed at this time: {event.time}")
# Define a function that handles the controller.
async def handle_controller(controller):
# Get the list of Controls on the controller.
controls = await controller.get_controls()
# If the "BUTTON_START" Control is found, register the function
# print_start_time to fire when "BUTTON_START" has the event "ButtonPress"
# occur.
if Control.BUTTON_START in controls:
controller.register_control_callback(
Control.BUTTON_START, [EventType.BUTTON_PRESS], print_start_time)
else:
print("Oops! Couldn't find the start button control! Is your "
"controller connected?")
exit()
while True:
await asyncio.sleep(1.0)
async def main():
# ... < INSERT CONNECTION CODE FROM MACHINE'S CODE SAMPLE TAB >
# Get your controller from the machine.
my_controller = Controller.from_robot(
robot=myRobotWithController, name="my_controller")
# Run the handleController function.
await handleController(my_controller)
# ... < INSERT ANY OTHER CODE FOR MAIN FUNCTION >
For more information, see the Python SDK Docs.
Parameters:
ctx
(Context): A Context carries a deadline, a cancellation signal, and other values across API boundaries.control
(Control): The Control to register the function for.triggers
([]EventType): The EventTypes that trigger the function.ctrlFunc
(ControlFunction): The function to run when the specified triggers are invoked.extra
(map[string]interface{}): Extra options to pass to the underlying RPC call.
Returns:
- (error): An error, if one occurred.
Example:
// Define a function to handle pressing the Start Menu button, "ButtonStart", on your controller and logging the start time
printStartTime := func(ctx context.Context, event input.Event) {
logger.Info("Start Menu Button was pressed at this time: %v", event.Time)
}
// Define the EventType "ButtonPress" to serve as the trigger for printStartTime.
triggers := []input.EventType{input.ButtonPress}
// Get the controller's Controls.
controls, err := controller.Controls(ctx, nil)
// If the "ButtonStart" Control is found, trigger printStartTime when "ButtonStart" the event "ButtonPress" occurs.
if !slices.Contains(controls, input.ButtonStart) {
return errors.New("button `ButtonStart` not found; controller may be disconnected")
}
Mycontroller.RegisterControlCallback(context.Background(), input.ButtonStart, triggers, printStartTime, nil)
For more information, see the Go SDK Docs.
Reconfigure
Reconfigure this resource. Reconfigure must reconfigure the resource atomically and in place.
Parameters:
ctx
(Context): A Context carries a deadline, a cancellation signal, and other values across API boundaries.deps
(Dependencies): The resource dependencies.conf
(Config): The resource configuration.
Returns:
- (error): An error, if one occurred.
For more information, see the Go SDK Docs.
DoCommand
Execute model-specific commands that are not otherwise defined by the component API.
For built-in models, model-specific commands are covered with each model’s documentation.
If you are implementing your own input controller and add features that have no built-in API method, you can access them with DoCommand
.
Parameters:
command
(Mapping[str, ValueTypes]) (required): The command to execute.timeout
(float) (optional): An option to set how long to wait (in seconds) before calling a time-out and closing the underlying RPC call.
Returns:
- (Mapping[str, viam.utils.ValueTypes]): Result of the executed command.
Raises:
- (NotImplementedError): Raised if the Resource does not support arbitrary commands.
Example:
command = {"cmd": "test", "data1": 500}
result = await my_input_controller.do_command(command)
For more information, see the Python SDK Docs.
Parameters:
ctx
(Context): A Context carries a deadline, a cancellation signal, and other values across API boundaries.cmd
(map[string]interface{}): The command to execute.
Returns:
- (map[string]interface{}): The command response.
- (error): An error, if one occurred.
Example:
myInputController, err := input_controller.FromRobot(machine, "my_input_controller")
command := map[string]interface{}{"cmd": "test", "data1": 500}
result, err := myInputController.DoCommand(context.Background(), command)
For more information, see the Go SDK Docs.
GetResourceName
Get the ResourceName
for this input controller with the given name.
Parameters:
name
(str) (required): The name of the Resource.
Returns:
- (viam.proto.common.ResourceName): The ResourceName of this Resource.
Example:
my_input_controller_name = Controller.get_resource_name("my_input_controller")
For more information, see the Python SDK Docs.
Close
Safely shut down the resource and prevent further use.
Parameters:
- None.
Returns:
- None.
Example:
await my_input_controller.close()
For more information, see the Python SDK Docs.
Parameters:
ctx
(Context): A Context carries a deadline, a cancellation signal, and other values across API boundaries.
Returns:
- (error): An error, if one occurred.
Example:
myInputController, err := input.FromRobot(machine, "my_input_controller")
err = myInputController.Close(context.Background())
For more information, see the Go SDK Docs.
API types
The input
API defines the following types:
Event object
Each Event
object represents a singular event from the input device, and has four fields:
Time
:time.Time
the event occurred.Event
:EventType
indicating the type of event (for example, a specific button press or axis movement).Control
:Control
indicating which Axis, Button, or Pedal on the controller has been changed.Value
:float64
indicating the position of an Axis or the state of a Button on the specified control.
EventType field
A string-like type indicating the specific type of input event, such as a button press or axis movement.
- To select for events of all type when registering callback function with RegisterControlCallback, you can use
AllEvents
as yourEventType
. - The registered function is then called in addition to any other callback functions you’ve registered, every time an
Event
happens on your controller. This is useful for debugging without interrupting normal controls, or for capturing extra or unknown events.
Registered EventTypes
definitions:
ALL_EVENTS = "AllEvents"
"""
Callbacks registered for this event will be called in ADDITION to other
registered event callbacks.
"""
CONNECT = "Connect"
"""
Sent at controller initialization, and on reconnects.
"""
DISCONNECT = "Disconnect"
"""
If unplugged, or wireless/network times out.
"""
BUTTON_PRESS = "ButtonPress"
"""
Typical key press.
"""
BUTTON_RELEASE = "ButtonRelease"
"""
Key release.
"""
BUTTON_HOLD = "ButtonHold"
"""
Key is held down. This will likely be a repeated event.
"""
BUTTON_CHANGE = "ButtonChange"
"""
Both up and down for convenience during registration, not typically emitted.
"""
POSITION_CHANGE_ABSOLUTE = "PositionChangeAbs"
"""
Absolute position is reported via Value, a la joysticks.
"""
POSITION_CHANGE_RELATIVE = "PositionChangeRel"
"""
Relative position is reported via Value, a la mice, or simulating axes with
up/down buttons.
"""
See the Python SDK Docs for the most current version of supported EventTypes
.
// Callbacks registered for this event will be called in ADDITION to other registered event callbacks.
AllEvents EventType = "AllEvents"
// Sent at controller initialization, and on reconnects.
Connect EventType = "Connect"
// If unplugged, or wireless/network times out.
Disconnect EventType = "Disconnect"
// Typical key press.
ButtonPress EventType = "ButtonPress"
// Key release.
ButtonRelease EventType = "ButtonRelease"
// Key is held down. This will likely be a repeated event.
ButtonHold EventType = "ButtonHold"
// Both up and down for convenience during registration, not typically emitted.
ButtonChange EventType = "ButtonChange"
// Absolute position is reported via Value, a la joysticks.
PositionChangeAbs EventType = "PositionChangeAbs"
// Relative position is reported via Value, a la mice, or simulating axes with up/down buttons.
PositionChangeRel EventType = "PositionChangeRel"
See the Viam RDK for the most current version of supported EventTypes
.
Control field
A string representing the physical input location, like a specific axis or button, of your Controller
that the Event Object is coming from.
Registered Control
types are defined as follows:
# Axes
ABSOLUTE_X = "AbsoluteX"
ABSOLUTE_Y = "AbsoluteY"
ABSOLUTE_Z = "AbsoluteZ"
ABSOLUTE_RX = "AbsoluteRX"
ABSOLUTE_RY = "AbsoluteRY"
ABSOLUTE_RZ = "AbsoluteRZ"
ABSOLUTE_HAT0_X = "AbsoluteHat0X"
ABSOLUTE_HAT0_Y = "AbsoluteHat0Y"
# Buttons
BUTTON_SOUTH = "ButtonSouth"
BUTTON_EAST = "ButtonEast"
BUTTON_WEST = "ButtonWest"
BUTTON_NORTH = "ButtonNorth"
BUTTON_LT = "ButtonLT"
BUTTON_RT = "ButtonRT"
BUTTON_LT2 = "ButtonLT2"
BUTTON_RT2 = "ButtonRT2"
BUTTON_L_THUMB = "ButtonLThumb"
BUTTON_R_THUMB = "ButtonRThumb"
BUTTON_SELECT = "ButtonSelect"
BUTTON_START = "ButtonStart"
BUTTON_MENU = "ButtonMenu"
BUTTON_RECORD = "ButtonRecord"
BUTTON_E_STOP = "ButtonEStop"
# Pedals
ABSOLUTE_PEDAL_ACCELERATOR = "AbsolutePedalAccelerator"
ABSOLUTE_PEDAL_BRAKE = "AbsolutePedalBrake"
ABSOLUTE_PEDAL_CLUTCH = "AbsolutePedalClutch"
See the Python SDK Docs for the most current version of supported Control
types.
// Axes.
AbsoluteX Control = "AbsoluteX"
AbsoluteY Control = "AbsoluteY"
AbsoluteZ Control = "AbsoluteZ"
AbsoluteRX Control = "AbsoluteRX"
AbsoluteRY Control = "AbsoluteRY"
AbsoluteRZ Control = "AbsoluteRZ"
AbsoluteHat0X Control = "AbsoluteHat0X"
AbsoluteHat0Y Control = "AbsoluteHat0Y"
// Buttons.
ButtonSouth Control = "ButtonSouth"
ButtonEast Control = "ButtonEast"
ButtonWest Control = "ButtonWest"
ButtonNorth Control = "ButtonNorth"
ButtonLT Control = "ButtonLT"
ButtonRT Control = "ButtonRT"
ButtonLT2 Control = "ButtonLT2"
ButtonRT2 Control = "ButtonRT2"
ButtonLThumb Control = "ButtonLThumb"
ButtonRThumb Control = "ButtonRThumb"
ButtonSelect Control = "ButtonSelect"
ButtonStart Control = "ButtonStart"
ButtonMenu Control = "ButtonMenu"
ButtonRecord Control = "ButtonRecord"
ButtonEStop Control = "ButtonEStop"
// Pedals.
AbsolutePedalAccelerator Control = "AbsolutePedalAccelerator"
AbsolutePedalBrake Control = "AbsolutePedalBrake"
AbsolutePedalClutch Control = "AbsolutePedalClutch"
See GitHub for the most current version of supported Control
types.
Axis controls
Support Notice
Currently, only Absolute
axes are supported.
Relative
axes, reporting a relative change in distance, used by devices like mice and trackpads, will be supported in the future.
Analog devices like joysticks and thumbsticks which return to center/neutral on their own use Absolute
axis control types.
These controls report a PositionChangeAbs
EventType.
Value: A float64
between -1.0
and +1.0
.
1.0
: Maximum position in the positive direction.0.0
: Center, neutral position.-1.0
: Maximum position in the negative direction.
AbsoluteXY axes
If your input controller has an analog stick, this is what the stick’s controls report as.
Alternatively, if your input controller has two analog sticks, this is what the left joystick’s controls report as.
Name | -1.0 | 0.0 | 1.0 |
---|---|---|---|
AbsoluteX | Stick Left | Neutral | Stick Right |
AbsoluteY | Stick Forward | Neutral | Stick Backwards |
AbsoluteR-XY axes
If your input controller has two analog sticks, this is what the right joystick’s controls report as.
Name | -1.0 | 0.0 | 1.0 |
---|---|---|---|
AbsoluteRX | Stick Left | Neutral | Stick Right |
AbsoluteRY | Stick Forward | Neutral | Stick Backwards |
- For
Y
axes, the positive direction is “nose up,” and indicates pulling back on the joystick.
Hat/D-Pad axes
If your input controller has a directional pad with analog buttons on the pad, this is what those controls report as.
Name | -1.0 | 0.0 | 1.0 |
---|---|---|---|
AbsoluteHat0X | Left DPAD Button Press | Neutral | Right DPAD Button Press |
AbsoluteHat0Y | Up DPAD Button Press | Neutral | Down DPAD Button Press |
Z axes (analog trigger sticks)
Info
Devices like analog triggers and gas or brake pedals use Absolute
axes, but they only report position change in the positive direction.
The neutral point of the axes is still 0.0
.
Name | -1.0 | 0.0 | 1.0 |
---|---|---|---|
AbsoluteZ | Neutral | Stick Pulled | |
AbsoluteRZ | Neutral | Stick Pulled |
Z
axes are usually not present on most controller joysticks.
If present, they are typically analog trigger sticks, and unidirectional, scaling only from 0
to 1.0
as they are pulled, as shown above.
AbsoluteZ
is reported if there is one trigger stick, and AbsoluteZ
(left) and AbsoluteRZ
(right) is reported if there are two trigger sticks.
Z axes can be present on flight-style joysticks, reporting yaw, or left/right rotation, as shown below. This is not common.
Name | -1.0 | 0.0 | 1.0 |
---|---|---|---|
AbsoluteZ | Stick Left Yaw | Neutral | Stick Right Yaw |
AbsoluteRZ | Stick Left Yaw | Neutral | Stick Right Yaw |
Button controls
Button Controls report either ButtonPress
or ButtonRelease
as their EventType.
Value:
0
: released1
: pressed
Action buttons (ABXY)
If your input controller is a gamepad with digital action buttons, this is what the controls for these buttons report as.
Tip
As different systems label the actual buttons differently, we use compass directions for consistency.
ButtonSouth
corresponds to “B” on Nintendo, “A” on XBox, and “X” on Playstation.ButtonNorth
corresponds to “X” on Nintendo, “Y” on XBox, and “Triangle” on Playstation.
Diamond 4-Action Button Pad | Rectangle 4-Action Button Pad | ||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
Horizontal 3-Action Button Pad | Vertical 3-Action Button Pad | ||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
Horizontal 2-Action Button Pad | Vertical 2-Action Button Pad | ||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
Trigger buttons (bumpers)
If your input controller is a gamepad with digital trigger buttons, this is what the controls for those buttons report as.
2-Trigger Button Pad | 4-Trigger Button Pad | ||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
Digital buttons for sticks
If your input controller is a gamepad with “clickable” thumbsticks, this is what thumbstick presses report as.
Name | Description |
---|---|
ButtonLThumb | Left or upper button for stick |
ButtonRThumb | Right or lower button for stick |
Miscellaneous buttons
Many devices have additional buttons. If your input controller is a gamepad with these common buttons, this is what the controls for those buttons report as.
Name | Description |
---|---|
ButtonSelect | Select or - |
ButtonStart | Start or + |
ButtonMenu | Usually the central “Home” or Xbox/PS “Logo” button |
ButtonRecord | Recording |
ButtonEStop | Emergency Stop (on some industrial controllers) |
Usage examples
Control a wheeled base with a Logitech G920 steering wheel controller
The following Python code is an example of controlling a wheeled base with a Logitech G920 steering wheel controller, configured as a gamepad
input controller.
import asyncio
from viam.components.base import Base
from viam.components.input import Control, Controller, EventType
from viam.proto.common import Vector3
from viam.robot.client import RobotClient
from viam.rpc.dial import Credentials, DialOptions
turn_amt = 0
modal = 0
cmd = {}
async def connect_robot(host, api_key, api_key_id):
opts = RobotClient.Options.with_api_key(
api_key=api_key,
api_key_id=api_key_id
)
return await RobotClient.at_address(host, opts)
def handle_turning(event):
global turn_amt
turn_amt = -event.value
print("turning:", turn_amt)
def handle_brake(event):
if event.value != 0:
print("braking!:", event.value)
global cmd
cmd = {"y": 0}
print("broke")
def handle_accelerator(event):
print("moving!:", event.value)
global cmd
accel = (event.value - 0.1) / 0.9
if event.value < 0.1:
accel = 0
cmd = {"y": accel}
def handle_clutch(event):
print("moving!:", event.value)
global cmd
accel = (event.value - 0.1) / 0.9
if event.value < 0.1:
accel = 0
cmd = {"y": -accel}
async def handleController(controller):
resp = await controller.get_events()
# Show the input controller's buttons/axes
print(f'Controls:\n{resp}')
if Control.ABSOLUTE_PEDAL_ACCELERATOR in resp:
controller.register_control_callback(
Control.ABSOLUTE_PEDAL_ACCELERATOR,
[EventType.POSITION_CHANGE_ABSOLUTE],
handle_accelerator)
else:
print("Accelerator Pedal not found! Exiting! Are your steering wheel" +
" and pedals hooked up?")
exit()
if Control.ABSOLUTE_PEDAL_BRAKE in resp:
controller.register_control_callback(
Control.ABSOLUTE_PEDAL_BRAKE,
[EventType.POSITION_CHANGE_ABSOLUTE],
handle_brake)
else:
print("Brake Pedal not found! Exiting!")
exit()
if Control.ABSOLUTE_PEDAL_CLUTCH in resp:
controller.register_control_callback(
Control.ABSOLUTE_PEDAL_CLUTCH,
[EventType.POSITION_CHANGE_ABSOLUTE],
handle_clutch)
else:
print("Accelerator Pedal not found! Exiting! Are your steering wheel" +
" and pedals hooked up?")
exit()
if Control.ABSOLUTE_X in resp:
controller.register_control_callback(
Control.ABSOLUTE_X,
[EventType.POSITION_CHANGE_ABSOLUTE],
handle_turning)
else:
print("Wheel not found! Exiting!")
exit()
while True:
await asyncio.sleep(0.01)
global cmd
if "y" in cmd:
res = await modal.set_power(
linear=Vector3(x=0, y=cmd["y"], z=0),
angular=Vector3(x=0, y=0, z=turn_amt))
cmd = {}
print(res)
async def main():
# ADD YOUR MACHINE REMOTE ADDRESS and API KEY VALUES.
# These can be found in app.viam.com's CONNECT tab's Code sample page.
# Toggle 'Include API key' to show the API key values.
g920_robot = await connect_robot(
"robot123example.locationxyzexample.viam.com", "API_KEY", "API_KEY_ID")
modal_robot = await connect_robot(
"robot123example.locationxyzexample.viam.com", "API_KEY", "API_KEY_ID")
g920 = Controller.from_robot(g920_robot, 'wheel')
global modal
modal = Base.from_robot(modal_robot, 'modal-base-server:base')
await handleController(g920)
await g920_robot.close()
await modal_robot.close()
if __name__ == '__main__':
asyncio.run(main())
Drive a robot with four wheels and a skid steer platform
The following Go code is part of an example of using an input controller to drive a robot with four wheels & a skid steer platform.
The motorCtl
callback function controls 5 motors: left front & back FL
BL
, right front & back FL
BL
, and a winder
motor that raises and lowers a front-end like a bulldozer.
The event.Control
logic is registered as a callback function to determine the case for setting the power of each motor from which button is pressed on the input controller.
// Define a single callback function
motorCtl := func(ctx context.Context, event input.Event) {
if event.Event != input.PositionChangeAbs {
return
}
speed := float32(math.Abs(event.Value))
// Handle input events, commands to set the power of motor components (SetPower method)
switch event.Control {
case input.AbsoluteY:
motorFL.SetPower(ctx, speed, nil)
motorBL.SetPower(ctx, speed, nil)
case input.AbsoluteRY:
motorFR.SetPower(ctx, speed * -1, nil)
motorBR.SetPower(ctx, speed * -1, nil)
case input.AbsoluteZ:
motorWinder.SetPower(ctx, speed, nil)
case input.AbsoluteRZ:
motorWinder.SetPower(ctx, speed * -1, nil)
}
}
// Registers callback from motorCtl for a selected set of axes
for _, control := range []input.Control{input.AbsoluteY, input.AbsoluteRY, input.AbsoluteZ, input.AbsoluteRZ} {
err = g.RegisterControlCallback(ctx, control, []input.EventType{input.PositionChangeAbs}, motorCtl)
}
Have questions, or want to meet other people working on robots? Join our Community Discord.
If you notice any issues with the documentation, feel free to file an issue or edit this file.
Was this page helpful?
Glad to hear it! If you have any other feedback please let us know:
We're sorry about that. To help us improve, please tell us what we can do better:
Thank you!