bam/docs/identification/acquisition.rst
Upstream Snapshot 8be13016bc Import upstream snapshot 57d13ead53206a6bf0db3d66f86506ae8c2ce01a
Upstream: https://github.com/pollen-robotics/bam
Upstream-Commit: 57d13ead53206a6bf0db3d66f86506ae8c2ce01a
Upstream-Branch: mjlab_frictionloss
2026-08-28 15:42:08 +08:00

242 lines
7.5 KiB
ReStructuredText

Data Acquisition
================
Recording consists of running the actuator through a set of predefined
trajectories while logging position, velocity, and control signals. The
trajectories are played with different P-gain values and with each
mass/length combination. The resulting data is then processed to a fixed
timestep and stored in a structured format for later use in the identification
pipeline.
Installation
------------
First, you need to clone the `BAM repository <https://github.com/Rhoban/bam>`_.
Then, install the extra dependencies for the identification pipeline using
``uv`` (`installation instructions <https://docs.astral.sh/uv/getting-started/installation/>`_):
.. code-block:: text
uv sync --extra identification
Trajectories
----------------------
The trajectories are designed to excite different friction regimes.
Each trajectory runs for 6 seconds.
.. list-table::
:header-rows: 1
:widths: 20 80
:class: traj-table
* - Name
- Description
* - ``sin_time_square``
- :math:`\sin(t^2)` profile — progressively faster oscillations, good
general-purpose trajectory that covers a wide velocity range.
|traj_sin_time_square|
* - ``lift_and_drop``
- Cubic move to −π/2 over 2 s, then torque disabled — the arm falls
under gravity. Disabling the torque can allow to dissociate viscous friction
from the back-EMF induced damping.
|traj_lift_and_drop|
* - ``up_and_down``
- Cubic path 0 → π/2 → 0.8·π/2 — slower motion, emphasizes static
friction and load-dependent effects.
|traj_up_and_down|
* - ``sin_sin``
- :math:`\sin(t)\cdot\pi/2 + \sin(5t)\cdot 0.5\cdot\sin(2t)` — rich
multi-frequency content.
|traj_sin_sin|
.. |traj_sin_time_square| image:: /_static/traj_sin_time_square.png
:width: 100%
:alt: sin_time_square trajectory
.. |traj_lift_and_drop| image:: /_static/traj_lift_and_drop.png
:width: 100%
:alt: lift_and_drop trajectory
.. |traj_up_and_down| image:: /_static/traj_up_and_down.png
:width: 100%
:alt: up_and_down trajectory
.. |traj_sin_sin| image:: /_static/traj_sin_sin.png
:width: 100%
:alt: sin_sin trajectory
Recording
---------
BAM already ships with support for several actuators (the ones whose models
are provided in the library), and is designed to be extended with new ones.
Each manufacturer is implemented in its own package under
``bam/<manufacturer>/``, exposing the same small interface. To record your own
actuator, you therefore either:
- **extend an existing manufacturer package** if your motor's brand is already
supported — simply add your actuator class (for example a new Dynamixel
model in ``bam/dynamixel/``); or
- **create a new** ``bam/<manufacturer>/`` **package** if your manufacturer is
not supported yet.
Each manufacturer package is made of three modules:
- ``actuator.py`` — the only hardware-specific part. It handles the
communication with the motor: reading position, speed and load, and sending
position or current commands. Your actuator class subclasses the base
classes provided in :mod:`bam.actuator`.
- ``record.py`` — plays the trajectories on the motor and logs the resulting
data to JSON. It adapts the generic trajectories to the motor when needed
(for instance, scaling the velocity to stay within the actuator's limits).
- ``all_record.py`` — a convenience script that runs a full recording session
for a given mass/arm configuration, automatically sweeping over all the
P-gain values.
When writing your own package, the existing ``bam/dynamixel/`` implementation
is a good reference to draw inspiration from.
Once these modules are written, recording should be done using the following command:
.. code-block:: text
uv run python -m bam.<manufacturer>.all_record \
--port /dev/ttyUSB0 \
--motor motor_name \
--mass 0.5 \
--arm-mass 0.02 \
--length 0.15 \
--vin 7.5 \
--logdir data_raw
with each length/mass combination. Don't forget to update the mass, length, and arm mass
parameters for each recording.
.. warning::
The P-gain values used in the ``<manufacturer>/record.py`` file are
manufacturer-specific and must be adapted to your motor based on the
manufacturer's specifications: a gain that is meaningful for one firmware
may be far too high or too low for another.
To determine the appropriate P-gain values for your actuator, you can
take the default P-gain value ``kp`` given by the manufacturer and test
[kp/6, kp/4, kp/2, kp].
Raw data format
---------------
Each recording produces one JSON file:
.. code-block:: json
{
"mass": 0.5,
"arm_mass": 0.02,
"length": 0.15,
"kp": 50,
"vin": 7.5,
"motor": "motor_name",
"trajectory": "sin_time_square",
"entries": [
{
"timestamp": 0.0077,
"position": 0.0015,
"speed": 0.024,
"load": 0.0,
"input_volts": 7.5,
"goal_position": 0.0,
"torque_enable": true
},
...
]
}
Entries are logged at the firmware's native rate, which is not necessarily
constant. The processing step resamples them to a fixed timestep.
Checking jitter
---------------
You can use the following script:
.. code-block:: bash
uv run python -m bam.jitter --logdir data_raw/
To visualize the jitter histogram.
Processing
----------
Resample raw logs to a constant timestep before fitting:
.. code-block:: text
uv run python -m bam.process \
--raw data_raw \
--logdir data_processed \
--dt 0.005
``--dt`` is the target timestep in seconds. The
script linearly interpolates between consecutive entries and writes one
processed JSON per raw file into ``data_processed/``.
Plotting
--------
You can plot the processed data using the following command:
.. code-block:: bash
uv run python -m bam.plot \
--actuator xl330 \
--logdir data_processed
Example: Dynamixel XL-330
-------------------------
The Dynamixel XL-330 is supported through the ``bam/dynamixel/``
package. The physical test bench used for this motor is shown in
:doc:`setup`.
To record a full session for a 0.567 kg weight at the tip of a 0.17 m
arm weighing 0.016 kg, the following command is used:
.. code-block:: text
uv run python -m bam.dynamixel.all_record \
--port /dev/ttyUSB0 \
--motor xl330 \
--mass 0.567 \
--arm-mass 0.016 \
--length 0.17 \
--vin 7.5 \
--logdir data_raw
For the XL-330, ``all_record`` automatically sweeps the five P-gain values
``[50, 100, 200, 300, 400]`` over the four trajectories, producing 20
recordings in ``data_raw/``. By repeating the command for each mass/length
combination presented in :doc:`setup`, a complete dataset of 240 6s recordings is obtained.
The video below shows the four trajectories being played on the XL-330 for a
single P-gain value:
.. raw:: html
<div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden; max-width: 100%; margin: 1rem 0 2rem;">
<iframe src="https://www.youtube.com/embed/sWn3lr7Sf4I"
title="XL-330 trajectory acquisition"
style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border: 0;"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
allowfullscreen></iframe>
</div>
Once all sessions are recorded, the raw data are then processed into a fixed timestep as shown
above.