BB.Ufactory (bb_ufactory v0.1.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

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

Full Robot Definition Example

For custom topologies or to add accessories, define the robot with use BB directly. The example below combines all available components:

defmodule MyRobot do
  use BB
  import BB.Unit

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

  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
          joint :j2 do
            type :revolute
            limit do
              lower ~u(-118 degree)
              upper ~u(120 degree)
              effort ~u(50 newton_meter)
              velocity ~u(180 degree_per_second)
            end
            actuator :j2_motor, {BB.Ufactory.Actuator.Joint, joint: 2, controller: :xarm}

            link :link2 do
              joint :j3 do
                type :revolute
                limit do
                  lower ~u(-225 degree)
                  upper ~u(11 degree)
                  effort ~u(32 newton_meter)
                  velocity ~u(180 degree_per_second)
                end
                actuator :j3_motor, {BB.Ufactory.Actuator.Joint, joint: 3, controller: :xarm}

                link :link3 do
                  joint :j4 do
                    type :revolute
                    limit do
                      lower ~u(-360 degree)
                      upper ~u(360 degree)
                      effort ~u(32 newton_meter)
                      velocity ~u(180 degree_per_second)
                    end
                    actuator :j4_motor, {BB.Ufactory.Actuator.Joint, joint: 4, controller: :xarm}

                    link :link4 do
                      joint :j5 do
                        type :revolute
                        limit do
                          lower ~u(-97 degree)
                          upper ~u(180 degree)
                          effort ~u(32 newton_meter)
                          velocity ~u(180 degree_per_second)
                        end
                        actuator :j5_motor, {BB.Ufactory.Actuator.Joint, joint: 5, controller: :xarm}

                        link :link5 do
                          joint :j6 do
                            type :revolute
                            limit do
                              lower ~u(-360 degree)
                              upper ~u(360 degree)
                              effort ~u(20 newton_meter)
                              velocity ~u(180 degree_per_second)
                            end
                            actuator :j6_motor, {BB.Ufactory.Actuator.Joint, joint: 6, controller: :xarm}

                            link :link6 do
                            end
                          end
                        end
                      end
                    end
                  end
                end
              end
            end
          end
        end
      end

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

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

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

  sensors do
    # Optional: UFactory Force/Torque sensor — publishes BB.Ufactory.Message.Wrench
    sensor :wrench, {BB.Ufactory.Sensor.ForceTorque,
      controller: :xarm,
      poll_interval_ms: 20
    }
  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–840)
BB.Ufactory.Actuator.LinearTrackBB.Actuator — linear track position in mm (RS485 proxy)
BB.Ufactory.Sensor.ForceTorqueBB.Sensor — polls register 0xC8, 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 <<0, 0, 0, 1, 0, 2, 0, 0>> 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.