UniteLabs
Reference

Brooks PreciseFlex 400

Get a Brooks PreciseFlex 400 robot arm connected through GroundControl, with the connector installing its own controller software, and confirm the connection from Python.

This page gets a PF400 connected and confirms the connection without moving the arm. Mounting, wiring and safety are covered by the Brooks manuals; the PF400 guides take it from here to teaching positions and moving plates.

The connector targets unitelabs-brooks-preciseflex-400 0.4.0. The connection test below ran against a simulated arm and a real PF400.

What you need

ItemDetail
InstrumentA PF400 with its Guidance Controller, bolted down, powered, with the emergency stop within reach
ControllerIts IP address and basic settings done through the Brooks web interface. See below
NetworkAn Ethernet link from the GroundControl machine to the controller. The factory address is 192.168.0.1
ConnectorBrooks PreciseFlex 400 from the UniteLabs registry
Vendor softwareNone at runtime. The connector installs and runs its own program on the controller
MachineWindows, Linux or macOS running GroundControl
AccessA tenant and the SDK installed. See Setup

The GroundControl machine has to reach these ports on the controller:

PortUsed for
10100Commands to the arm
10000Status reads, and stopping the arm while another command runs
21FTP, to upload the connector's program: on the first start, after a connector update, and when another program answers
80The web console, to write the startup settings and to start or restart the program

Before you connect

A factory-fresh controller is not ready for the connector. Give it its IP address and initial settings through the Brooks web interface first, as the Guidance Controller documentation describes. The connector takes over from there.

The connector runs its own GPL program on the controller, in its own folder, /flash/projects/unitelabs_tcp_server/. It never deletes another project. If the controller runs another program, from Brooks, an integrator or another scheduler, the connector stops and unloads it and points the startup settings at its own program. It changes these startup settings:

  • GPL operating mode on;
  • autostart, and auto compile and run, of its own project, at its own project path;
  • home the arm on power-up;
  • switch motor power on at power-up: off.

Note the current values in the web console before you connect, along with the name of the startup project. To switch back later, disable motor power, set the old project and values again, and save them to flash.

Drive the arm from one place at a time. Stop the connector in GroundControl before you use the Brooks web console to move the arm, and close the console before you start the connector again.

Install and configure the connector

  1. In GroundControl, add a connector and pick Brooks PreciseFlex 400 from the registry (how to add a connector).
  2. Fill in the device block of the configuration. The fields that matter:
    FieldValue
    hostThe controller's IP address, 192.168.0.1 unless it was changed
    portThe command port, 10100. Change it only if the controller serves commands elsewhere
    simulationfalse for the real arm. It defaults to true, so a fresh install never moves anything
    extended_reachAlways set it: true for an XR arm, false for standard reach. A wrong value makes the reach check use the wrong link lengths, up to about 113 mm off
    rail_axisy, or x if the rail carriage is turned a quarter. Ignored without a rail
    ftp_userLeave empty, unless someone added FTP credentials on the controller. Same for ftp_password
    boot_timeoutSeconds to wait for the controller after installing the program, 120 by default
    profilesMotion profiles to write into slots 1 to 20 at startup. Empty leaves the controller's values

    The rail is detected from the controller; there is no setting to turn it on.
  3. Start the connector. On the first real-mode start it installs its program, which takes up to two minutes:
    • uploads the program over FTP and sets it to start, compile and run on every power-up;
    • starts it from the web console and checks that the code answering is the code it uploaded;
    • switches motor power on and homes the arm. The arm moves.

    On later starts nothing is uploaded. A connector update with a newer program re-uploads it. If the program is installed but stopped, after a crash or an operator stopping it, the connector only restarts it: no settings rewritten, no homing. The arm comes up powered but not homed, and moves fail with -1021 until you home it.
    After a power cycle of the controller, the program starts on its own but motor power stays off. The controller ships with power coming on at startup, and the connector turns that off. Switch power on and home the arm before the first move.
  4. GroundControl lists the modules, among them MovementController, JointMovementController, PathController, GripperController, TransportController, SafetyController, LightingController and SimulationController. TransportController only appears when the controller reports plate handling.

To go from simulation to the real arm, set simulation to false and restart the connector. Switching with the SimulationController module does not install the program, and fails if the controller runs another program until the connector restarts.

To install the program by hand instead, for example on a site that blocks FTP, set auto_deploy to false and ask UniteLabs support for the project files.

Try it without an arm

With simulation left at true, the connector answers like a PF400 without one: moves take time and finish, the gripper grasps, and plate handling is reported. simulate_rail adds a rail. It checks targets against the arm extended_reach describes, so set that as you would for the real arm. Every script on this page and in the PF400 guides runs against it.

First connection test

The script reads what the controller reports about itself, then its state and joint positions. Nothing in it moves the arm. Run it with the SDK authenticated (Connect to Platform), using the connector's name from GroundControl.

first_connection.py
import asyncio

from unitelabs.sdk import AsyncApiClient


async def first(subscription, key):
    # Sensor streams open with an event that carries no value,
    # so read until one that does
    async with subscription:
        async for value in subscription:
            if key in value:
                return value
    raise RuntimeError("The stream closed without a value")


async def main():
    client = AsyncApiClient()
    arm = await client.get_service_by_name(name="Brooks PreciseFlex 400")
    info = arm.information_provider

    # What the controller reports about itself
    print("Model:", await info.get_model())
    print("Firmware:", await info.get_firmware_version())
    rail = await info.get_rail_installed()
    print("Rail:", rail)
    print("Plate handling:", await info.get_plate_handling_supported())

    # Live state and position. Nothing here moves the arm
    print("State:", await first(await info.subscribe_state(), "Homed"))
    suffix = "_with_rail" if rail else ""
    stream = arm.joint_movement_controller.actions[
        "subscribe_joint_positions" + suffix
    ]
    print("Joints:", await first(await stream(), "Column"))


asyncio.run(main())

Run it with uv run first_connection.py. On a real arm it prints something like:

Model: PreciseFlex 400
Firmware: TCP Command Server 3.0D2 06-28-2024, ..., PARobot Module 3.0C2 07-11-2023, ...
Rail: False
Plate handling: True
State: {'Status': 'IDLE', 'Enabled': True, 'Homed': True}
Joints: {'Column': 502.27, 'Shoulder': 26.389, 'Elbow': 181.844, 'Wrist': -207.677, 'Gripper': 126.12}

With a rail, Joints also carries Rail. If Plate handling is False, the pick-up and put-down commands are not available; contact UniteLabs support.

Known quirks and errors

You seeIt meansDo this
-1021 Robot not homed on every moveThe program restarted, the controller was power-cycled, or the arm was stoppedClear the gripper. Switch power on if it is off (update_power(active=True)), then await arm.movement_controller.home()
-1009 latched faultA collision or an emergency stop left a fault the controller holdsCheck the cell and the gripper, then await arm.safety_controller.recover(). It clears the fault and re-homes, so the arm moves
The connector does not start with simulation set to falseNo arm answered at hostCheck the cable, the address and the ports above. The connector does not fall back to simulation
An error naming two digestsA different program answers on port 10100, found on a reconnectRestart the connector. A fresh start installs its own program next to the other one and switches the startup settings; see Before you connect first
-2805 Unknown commandThe controller runs another vendor's programAs above
A move is refused with a profile out of rangeProfiles 0 to -5 only exist from connector 0.4.0Update the connector, or use a slot from 1 to 20 that you have set to a known speed
The arm does not respond to the connectorSomeone is driving it from the Brooks web consoleClose the console; one driver at a time

Homed in the state can lag behind the arm for a few seconds after a move, a stop or a recovery.

Next steps

Vendor documentation

Mounting, power, the controller's own settings and safety are covered by the Brooks PreciseFlex 400 manual and the Guidance Controller documentation shipped with the arm.

Last updated