BB.Parameter.Store.CubDB
CubDB-backed parameter persistence for the Beam Bots robotics framework.
Tune a gain with BB.Parameter.set/3, and it's still there after a reboot.
Why CubDB
bb ships BB.Parameter.Store.Dets, which is fine when the machine shuts down
politely. Robots don't always. CubDB stores its data in an append-only, immutable
B-tree, so an unexpected shutdown can't corrupt the database or leave it needing
a repair pass — which matters when the off switch is "it fell over". Keys and
values are arbitrary terms, so parameter paths and BB.Unit values are stored
as-is, and writes are flushed to disk as they happen.
Installation
mix igniter.install bb_parameter_store_cubdb
That adds the extension to your robot and declares a parameter_store_cubdb
section, pointing at /root on a Nerves project and the build directory
otherwise.
Or add it to mix.exs by hand:
def deps do
[
{:bb_parameter_store_cubdb, "~> 0.1.0"}
]
end
Usage
Add the extension to your robot and say where the database lives:
defmodule MyRobot.Robot do
use BB, extensions: [BB.Parameter.Store.CubDB.Dsl]
parameter_store_cubdb do
data_dir "/root/my_robot_params"
end
parameters do
group :balance do
param :kp, type: :float, default: 180.0, min: 0.0, max: 500.0
param :kd, type: :float, default: 4.0, min: 0.0, max: 50.0
end
end
topology do
link :base_link
end
end
Then tune away, and the values will be there next boot:
iex> BB.Parameter.set(MyRobot.Robot, [:balance, :kp], 200.0)
:ok
Declaring the section is all that's needed — it sets the robot's
parameter_store setting for you. If you'd rather configure the store directly
and skip the extension, that works too:
settings do
parameter_store {BB.Parameter.Store.CubDB, data_dir: "/root/my_robot_params"}
end
Options
| Option | Default | Description |
|---|---|---|
data_dir |
required | Directory to store the database in, created if it doesn't exist |
auto_compact |
true |
Compact automatically. true, false, or {min_write_operations, min_dirt_factor} |
auto_file_sync |
true |
Flush the disk buffer on every write. Turning this off trades durability for write throughput |
Where to put the data directory
On Nerves, use a path under /root — the application data partition. The
firmware's root filesystem is read-only, and bb only logs a warning when a
store fails to open, so a robot pointed at an unwritable path will boot with
persistence quietly disabled.
Which is a problem if the same robot module has to run on your laptop and on
the device, because /root isn't writable on the one and _build doesn't exist
on the other. Take the directory from the application environment instead:
parameter_store_cubdb do
data_dir Application.compile_env(:my_app, :params_dir)
end
Then give each environment and target its own value. In a Nerves project,
config/config.exs ends with import_config "#{Mix.target()}.exs", so the
per-target files are where the paths go:
# config/host.exs
config :my_app, params_dir: Path.expand("_build/params")
# config/rpi0_2.exs
config :my_app, params_dir: "/root/params"
For a plain (non-Nerves) project the same trick works per Mix.env(), with
config/dev.exs and config/test.exs setting their own directories — handy for
keeping a test run from inheriting the gains you tuned in dev.
Two things to know about this:
- Use
Application.compile_env/2, notget_env/2orruntime.exs. The DSL is compiled, so the value has to be available at compile time — a key set inconfig/runtime.exsis read far too late to end up in the section. The payoff is thatcompile_envalso tracks the key, so changing it triggers a recompile rather than leaving a stale path baked into the BEAM file. - An unset key is a compile error, not a
nilpath, because the section's schema requires a string. You'll hear about a missing target config while you're building the firmware rather than after it's on the robot.
Bounds aren't rechecked on load
bb applies persisted values without revalidating them against each parameter's
min/max. A value that was in bounds when it was written will still be in
bounds when it's read, so this only bites if something edits the database
directly.
Licence
Apache-2.0. See LICENSE.txt.