BB.Ufactory (bb_ufactory v0.2.0)

Copy Markdown View Source

Beam Bots integration for UFactory xArm robotic arms.

BB.Ufactory provides controller, actuator, and sensor modules that plug into the BB robotics framework for UFactory xArm arms: xArm5, xArm6, xArm7, Lite6, and xArm850.

Architecture

The arm communicates over two independent TCP connections:

SocketPortDirectionPurpose
Command502Client → ArmSend register commands; receive responses
Report30003Arm → ClientArm pushes joint state at ~100 Hz

BB.Ufactory.Controller owns both connections. An ETS table acts as a shared blackboard — joint actuators write target positions into it, and the controller's 100 Hz loop batches all pending positions into a single MOVE_JOINT frame each tick. Cartesian and accessory commands (gripper, linear track) bypass the ETS loop and are sent immediately via BB.Process.call/3.

Actuator.Joint  writes set_position  ETS table
                                              
Controller loop (100 Hz) reads ETS  cmd_move_joints frame  arm:502
arm:30003 pushes report Controller updates ETS current_position
                                       publishes JointState, CartesianPose

Quick Start

The fastest path to a working xArm6 is to use BB.Ufactory.Robots.XArm6, which provides the complete six-joint topology and only requires a host address:

defmodule MyRobot do
  use BB.Ufactory.Robots.XArm6, host: "192.168.1.111"
end

Accessories and controller configuration are options of the same macro (gripper:, linear_track:, controller:) — see BB.Ufactory.Robots.XArm6 for the full list.

Full Robot Definition Example

For a topology use BB.Ufactory.Robots.XArm6 cannot express (renamed joints, the arm composed into a larger robot), define it with use BB directly. Accessory actuators (Cartesian, gripper, linear track) hang off fixed mount joints — bb's DSL only allows actuators under joints:

defmodule MyRobot do
  use BB
  import BB.Unit

  controllers do
    controller :xarm, {BB.Ufactory.Controller,
      host: "192.168.1.111",
      model: :xarm6,
      loop_hz: 100
    }
  end

  topology do
    link :base do
      joint :j1 do
        type :revolute

        limit do
          lower ~u(-360 degree)
          upper ~u(360 degree)
          effort ~u(50 newton_meter)
          velocity ~u(180 degree_per_second)
        end

        actuator :j1_motor, {BB.Ufactory.Actuator.Joint, joint: 1, controller: :xarm}

        link :link1 do
          # ... joints j2–j6 nest here exactly like j1, ending in :link6.
          # Copy the full chain (with per-joint limits) from the source
          # of BB.Ufactory.Robots.XArm6.

          joint :cartesian_mount do
            type :fixed

            # Optional: Cartesian actuator — commands end-effector pose
            actuator :cartesian, {BB.Ufactory.Actuator.Cartesian,
              controller: :xarm,
              speed: 100.0,
              acceleration: 2000.0
            }

            link :cartesian_body do
            end
          end

          joint :gripper_mount do
            type :fixed

            # Optional: Gripper G2 — position in pulse units (0–850)
            actuator :gripper, {BB.Ufactory.Actuator.Gripper,
              controller: :xarm,
              speed: 1500
            }

            link :gripper_body do
            end
          end
        end
      end

      joint :track_mount do
        type :fixed

        # Optional: Linear track — position in millimetres
        actuator :track, {BB.Ufactory.Actuator.LinearTrack,
          controller: :xarm,
          speed: 200
        }

        link :track_body do
        end
      end
    end
  end

  sensors do
    # Optional: UFactory Force/Torque sensor — publishes BB.Ufactory.Message.Wrench
    sensor :wrench, {BB.Ufactory.Sensor.ForceTorque, controller: :xarm}
  end
end

Module Inventory

ModuleRole
BB.Ufactory.ControllerBB.Controller — TCP sockets, ETS table, 100 Hz loop, heartbeat, pubsub
BB.Ufactory.ProtocolFrame builder and parser for port 502 commands
BB.Ufactory.ReportReport frame parser for port 30003 push data
BB.Ufactory.RegistersModule-attribute constants for all register addresses
BB.Ufactory.ModelPer-model joint counts and limits (xArm5/6/7, Lite6, xArm850)
BB.Ufactory.Actuator.JointBB.Actuator — joint-space position via ETS + 100 Hz loop
BB.Ufactory.Actuator.CartesianBB.Actuator — Cartesian end-effector pose via MOVE_LINE
BB.Ufactory.Actuator.GripperBB.Actuator — Gripper G2 position (pulse units 0–850)
BB.Ufactory.Actuator.LinearTrackBB.Actuator — linear track position in mm (RS485 proxy)
BB.Ufactory.Sensor.ForceTorqueBB.Sensor — forwards report-stream F/T data, publishes Wrench
BB.Ufactory.Message.ArmStatusState, mode, error/warning codes from the report socket
BB.Ufactory.Message.CartesianPoseTCP pose (x/y/z/roll/pitch/yaw) from report socket
BB.Ufactory.Message.WrenchFx/Fy/Fz/Tx/Ty/Tz from the F/T sensor
BB.Ufactory.Robots.XArm6Pre-built BB robot definition for the xArm6
BB.Error.Protocol.Ufactory.HardwareFaultStructured error for xArm hardware fault codes
BB.Error.Protocol.Ufactory.ConnectionErrorTCP connection failure
BB.Error.Protocol.Ufactory.CommandRejectedNon-zero status byte in a command response

Protocol Notes

  • Angles on the wire are always radians. BB also uses radians, so no conversion is needed.
  • Mixed endianness: u16 header fields are big-endian; fp32 payload fields are little-endian. The only exception is the linear track position, which is int32 big-endian.
  • Heartbeat: The controller sends a bare GET_STATE request (<<0, 0, 0, 2, 0, 1, 0x0D>>) every second on the command socket to keep the connection alive.
  • Modbus-TCP variant: The protocol identifier in the header is 0x0002 (not the standard Modbus 0x0000). The developer manual is the authoritative spec.