Your First Robot
View SourceThis tutorial guides you through defining your first robot with Beam Bots. By the end, you'll understand the core DSL concepts and have a working robot definition.
Prerequisites
- Elixir 1.19 or later
- Beam Bots installed in your project
Quick Start with Igniter
The fastest way to get started is with Igniter:
mix igniter.install bb
This creates a {YourApp}.Robot module with arm/disarm commands and a base link, adds it to your supervision tree, and configures the formatter. You can skip to Step 2 and modify the generated module.
Manual Installation
If you prefer to create the module manually, add Beam Bots to your dependencies:
# mix.exs
def deps do
[
{:bb, "~> 0.1"}
]
endWhat We're Building
We'll create a simple two-link robot arm: a base that can rotate (pan), with an arm that can tilt up and down. This is similar to a pan-tilt camera mount.
[camera] <- tilt joint rotates this
|
[pan_link] <- pan joint rotates this
|
[base] <- fixed to the worldStep 1: Create the Module
Create a new file lib/my_robot.ex:
defmodule MyRobot do
use BB
topology do
link :base do
end
end
endLet's break this down:
use BBbrings in the Beam Bots DSL and the~usigil for physical unitstopology do ... enddefines the robot's physical structurelink :base do ... endcreates our first link (rigid body)
Compile and test:
iex> MyRobot.robot()
%BB.Robot{name: MyRobot, links: %{base: %BB.Robot.Link{...}}, ...}The robot/0 function returns a compiled struct optimised for runtime use.
Step 2: Add a Joint and Child Link
Joints connect links. Let's add a pan joint that allows rotation around the Z-axis:
defmodule MyRobot do
use BB
topology do
link :base do
joint :pan_joint do
type(:revolute)
axis do
end
link :pan_link do
end
end
end
end
endKey concepts:
- Joints are nested inside links - the parent link contains the joint definition
- type(:revolute) - a revolute joint rotates around an axis (like a hinge)
- axis - defines which axis the joint rotates around. An empty axis block defaults to the Z-axis. You can specify different orientations using
roll,pitch, andyaw. - Child link is nested inside the joint - this creates the kinematic chain
For Roboticists: The DSL compiles to an Elixir struct at compile-time. There's no runtime parsing - the robot definition is baked into your module.
For Elixirists: Links are rigid bodies (solid pieces). Joints are the connections between them that allow movement. A revolute joint is like a door hinge - it rotates around one axis.
Step 3: Add Joint Limits
Real joints have physical constraints. Let's limit the pan joint's range of motion:
joint :pan_joint do
type(:revolute)
axis do
end
limit do
lower(~u(-90 degree))
upper(~u(90 degree))
effort(~u(5 newton_meter))
velocity(~u(60 degree_per_second))
end
link :pan_link do
end
endThe ~u() sigil creates unit-aware values:
~u(-90 degree)- negative 90 degrees~u(5 newton_meter)- maximum torque the joint can apply~u(60 degree_per_second)- maximum rotation speed
These units are automatically converted to SI base units (radians, newton-metres) in the compiled robot struct.
Step 4: Position the Joint
By default, joints are at the origin of their parent link. Use origin to offset them:
joint :pan_joint do
type(:revolute)
origin do
z(~u(0.05 meter))
end
axis do
end
limit do
lower(~u(-90 degree))
upper(~u(90 degree))
effort(~u(5 newton_meter))
velocity(~u(60 degree_per_second))
end
link :pan_link do
end
endThe joint is now 5cm above the base link's origin.
Step 5: Add a Second Joint
Let's add a tilt joint to create a full pan-tilt mechanism:
defmodule MyRobot do
use BB
topology do
link :base do
joint :pan_joint do
type(:revolute)
origin do
z(~u(0.05 meter))
end
axis do
end
limit do
lower(~u(-90 degree))
upper(~u(90 degree))
effort(~u(5 newton_meter))
velocity(~u(60 degree_per_second))
end
link :pan_link do
joint :tilt_joint do
type(:revolute)
origin do
z(~u(0.03 meter))
end
axis do
roll(~u(-90 degree))
end
limit do
lower(~u(-45 degree))
upper(~u(90 degree))
effort(~u(2 newton_meter))
velocity(~u(45 degree_per_second))
end
link :camera_link do
end
end
end
end
end
end
endThe tilt joint rotates around the Y-axis (specified by roll(~u(-90 degree)) which rotates the default Z-axis to point along Y), allowing the camera to look up and down.
Step 6: Add Visual Geometry
To visualise the robot, add visual geometry to each link:
link :base do
visual do
cylinder do
radius(~u(0.04 meter))
height(~u(0.05 meter))
end
material do
color do
red(0.2)
green(0.2)
blue(0.2)
alpha(1.0)
end
end
end
joint :pan_joint do
# ... joint definition
end
endAvailable geometry types:
box- withx,y,zdimensionscylinder- withradiusandheightsphere- withradiusmesh- withfilenamefor custom 3D models
Complete Example
Here's the full robot definition:
defmodule MyRobot do
use BB
topology do
link :base do
visual do
cylinder do
radius(~u(0.04 meter))
height(~u(0.05 meter))
end
material do
color do
red(0.2)
green(0.2)
blue(0.2)
alpha(1.0)
end
end
end
joint :pan_joint do
type(:revolute)
origin do
z(~u(0.05 meter))
end
axis do
end
limit do
lower(~u(-90 degree))
upper(~u(90 degree))
effort(~u(5 newton_meter))
velocity(~u(60 degree_per_second))
end
link :pan_link do
visual do
origin do
z(~u(0.015 meter))
end
box do
x(~u(0.03 meter))
y(~u(0.03 meter))
z(~u(0.03 meter))
end
material do
color do
red(0.3)
green(0.3)
blue(0.3)
alpha(1.0)
end
end
end
joint :tilt_joint do
type(:revolute)
origin do
z(~u(0.03 meter))
end
axis do
roll(~u(-90 degree))
end
limit do
lower(~u(-45 degree))
upper(~u(90 degree))
effort(~u(2 newton_meter))
velocity(~u(45 degree_per_second))
end
link :camera_link do
visual do
box do
x(~u(0.05 meter))
y(~u(0.03 meter))
z(~u(0.03 meter))
end
material do
color do
red(0.1)
green(0.1)
blue(0.1)
alpha(1.0)
end
end
end
end
end
end
end
end
end
endExploring the Compiled Robot
The robot/0 function returns a BB.Robot struct:
iex> robot = MyRobot.robot()
iex> Map.keys(robot.links)
[:base, :pan_link, :camera_link]
iex> Map.keys(robot.joints)
[:pan_joint, :tilt_joint]
iex> robot.joints.pan_joint.type
:revolute
iex> robot.joints.pan_joint.limit.upper
1.5707963267948966 # 90 degrees in radiansNotice that angles are stored in radians (SI units) even though we defined them in degrees.
Joint Types
BB supports six joint types:
| Type | Description | Use Case |
|---|---|---|
:revolute | Rotation with limits | Arm joints, pan-tilt |
:continuous | Unlimited rotation | Wheels |
:prismatic | Linear sliding | Linear actuators |
:fixed | No movement | Welded connections |
:floating | 6 degrees of freedom | Free-floating objects |
:planar | Movement in a plane | Some mobile bases |
What's Next?
You've defined a robot structure, but it's not running yet. In the next tutorial, we'll:
- Start the robot's supervision tree
- Understand how the process structure mirrors the physical structure
- Learn about Beam Bots' fault isolation model
Continue to Starting and Stopping.