Multi-robot Programmatic Access

Scripts to iterate through robots and iteratively activate or control them

Using the Freedom REST API, it is exceedingly simple for you to programmatically control large numbers of robots remotely.

Set up your Credentials

You will want to save API credentials to ~/.config/freedomrobotics/credentials with a payload of:

{
    "token":"T000000000000", 
    "secret":"S00000000000
}

You can create a new token in the freedom App by going to
TEAM SETTINGS -> TOKENS -> CUSTOM then CREATE API TOKEN.

🚧

Create API Token: API Secret

You can only ever get your secret the first time, so please save it.

List all your Devices

Below, in a few lines, you can easily list all devices in your account. The examples below it show how to filter these devices by fleet, physical type, activity and other dimensions and then how to send commands back to them.

Each device has a JSON representation. A few of the keys you should know are:

  • account - the account the device is in
  • device - the freedom ID of the device
  • name - the human readable name of the device you have given it
  • fleet - the logical grouping the device belongs to
  • type - the physical type of device, such as "spot-mini 1.0"
  • utc_last_received.data - the utc time in seconds when data was last received from the robot
import json
import requests

headers = {
    'content-type': 'application/json',
    'mc_token': credentials['token'],
    'mc_secret': credentials['secret']
    }
    
url = "https://api.freedomrobotics.ai/accounts/" + account + "/devices"

response = requests.get(url, headers=headers)
devices = json.loads(response)

for device in devices:
    print(device)

By Activity

# Time is stored in UTC seconds since 1970
# NOTE: JS uses msecs, so divide by 1000
current_time = time.time()

LAST_ACTIVE_TIME_ATT = "utc_last_received.data"

active_devices = []
inactive_devices = []


for device in devices:
    # Define active as a device which has uploaded data in the last minute
    if LAST_ACTIVE_TIME_ATT not in device or current_time - device[LAST_ACTIVE_TIME_ATT] > 60:
        inactive_devices.append(device)
    else:
        active_devices.append(device)
        
print("You have " + str(len(active_devices)) + " active devices and " +
      str(len(inactive_devices)) + " inactive devices.")

By Alerts

You can search for devices with alerts and filter based on a specific type or level of alert.

for device in devices:
    # If there are any triggered alerts
    if len(device['mc.alerts.triggered']) > 0:
		    for alert in device['mc.alerts.triggered']:
				    if alert['level'] in ['error', 'fatal']:
						    print(device['name'] + " has an issue you should look at...")

By Fleet

You can easily segment so you are only interacting with devices from a specific fleet to update just the ones you want.

fleets = {}

for device in devices:
		if device['fleet'] not in fleets:
				fleets[device['fleet']] = []

		fleets[device['fleet']].append(device)

By Type

Each robot has a physical type which represents the underlying hardware and version, such as "Spot-Mini 1.0".

types = {}

for device in devices:
		if device['type'] not in types:
				types[device['type']] = []

		types[device['type']].append(device)

Send a Command to all Devices

Below shows you how to easily send a command in to all your devices. You can easily augment this to only send it to devices which are online, in a specific fleet or of a specific type.

import json
import requests

def send_data( headers, account, device, topic, topic_type, data):

    payload = [{
            'message': data,
            'platform': 'ros',
            'topic': topic,
            'type': topic_type,
            'expiration_secs': 5
        }]

    url = "https://api.freedomrobotics.ai/accounts/" + 
          account + "/devices/" + device +"/commands"
      
    r = requests.put(url, headers=headers, data=json.dumps(payload))
    
for device in devices:
    # Only update a specific fleet
    if device["fleet"] is "california_04:
        send_data(headers,
              device["account"],device["device"], 
              "/commands", 
              "std_msgs/String", 
              {"data":"return_to_dock"}
             )

Trigger a Script on all Devices

You can also trigger scripts locally on a subset of your robots for deploy, update and validation of data - or just to reset your usb bus if there is an issue.

import json
import requests

def trigger_script( headers, account, device, package, script_path, args):
    payload = [{
            'data': {
                'package': package, 
                'script_path': script_path,
                'args': args
              },
            'platform': 'mission_control_controller',
            'command': 'local_script',
            'expiration_secs':100
        }]

    url = "https://api.freedomrobotics.ai/proto/accounts/" + 
          account + "/devices/" + device +"/commands"
      
    r = requests.put(url, headers=headers, data=json.dumps(payload))
    
for device in devices:
    # Only update a specific fleet
    if device["fleet"] is "california_04:
        # remote trigger the script
        trigger_script(headers,
              device["account"], device["device"], 
              "acme_robotics", 
              "scripts/update_firmware_stack.sh", 
              " --now"
             )