Data contract¶
Typed inputs that carry their conventions: joint order, clock, signal origin, effort kind and unit, valid-sample mask, session and source files. See the decision record Data and result contract. Each type converts to and from the legacy dictionaries and CSV loader.
Dynamic identification input: a trajectory with its conventions attached.
See docs/decisions/data-result-contract.md. Joint order, clock, signal origin, effort kind and unit, the valid-sample mask and the source travel with the arrays instead of being implied by an adapter.
The effort keeps the units it was recorded in (a motor current, a motor-side
torque, a load fraction, a joint torque, or a linear actuator's force).
:meth:TrajectoryData.check_effort decides whether a solver may use it.
TrajectoryData(t, joint_names, q, effort, effort_kind, effort_unit, clock='recorded', dq=None, ddq=None, origin=dict(), effort_conversion='', effort_raw=None, effort_raw_kind=(), effort_raw_unit=(), mask=None, sample_index=None, source=DataSource())
dataclass
¶
A recorded trajectory, in the order of joint_names.
Arrays are (n_samples, n_joints); t is (n_samples,) in seconds.
dq/ddq may be None (to be derived). mask marks valid
samples; nothing is deleted, and filtering runs on the full signal
before the mask selects rows (:meth:stacked_mask).
from_legacy(raw, joint_names, *, effort_kind, effort_unit, clock='recorded', source=None, origin=None, sample_index=None)
classmethod
¶
From the dict load_trajectory_data returns today.
Keys timestamps ((n, 1) or (n,)), positions, velocities,
accelerations, torques; velocities/accelerations may be
None. The legacy dict says nothing about the effort, so its kind
and unit are required here.
Source code in src/figaroh/data/trajectory.py
153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 | |
to_legacy()
¶
The legacy dict, every sample (the mask applies to regressor rows,
after filtering; see :meth:stacked_mask).
Source code in src/figaroh/data/trajectory.py
188 189 190 191 192 193 194 195 196 197 | |
stacked_effort(effort=None)
¶
Joint-major stacking the regressor uses: joint 1's samples, then
joint 2's, ... (effort.T.flatten()).
Source code in src/figaroh/data/trajectory.py
201 202 203 204 205 | |
stacked_mask()
¶
Row mask matching :meth:stacked_effort.
Source code in src/figaroh/data/trajectory.py
207 208 209 | |
converted(scale, offset=0.0, *, effort_kind, effort_unit, description)
¶
effort * scale + offset per joint, keeping the recorded signal.
For a conversion with known constants (reduction ratio, torque
constant, gravity offset); description records the steps.
Source code in src/figaroh/data/trajectory.py
214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 | |
check_effort(model, drive_gain_joints=())
¶
Refuse an effort a dynamic solver must not use as joint effort.
Accepted per joint: joint_torque (N·m) on a revolute joint,
joint_force (N) on a prismatic joint, or a drive-side kind
(motor current/torque, load fraction) on a joint listed in
drive_gain_joints, i.e. whose model identifies an unknown drive
gain. Anything else would be solved as if it were N·m.
Raises:
| Type | Description |
|---|---|
ValueError
|
naming every joint, its kind and unit. |
Source code in src/figaroh/data/trajectory.py
252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 | |
Geometric calibration input: postures and what was observed at them.
See docs/decisions/data-result-contract.md. Kept separate from
:class:~figaroh.data.trajectory.TrajectoryData: postures are independent
samples with points or poses in a named frame, not a time series of
efforts.
PoseObservations(joint_names, q, values=None, point_names=(), measurability=None, frame='', registered_to='', orientation='unspecified', constraint=None, mask=None, session=None, sample_index=None, source=DataSource())
dataclass
¶
Postures q (n, n_joints) and observations values.
values is (n, n_points, 6): x, y, z in m and phix, phiy, phiz in rad
(convention orientation) of each observed point, NaN where a DOF is
not observed (measurability, (n_points, 6)). frame names the
frame the values are expressed in and registered_to the robot frame
it is registered to. A constraint-only dataset (e.g. a contact gap that
must be zero) has values=None and names its constraint.
mask marks valid postures; nothing is deleted.
select_points(names)
¶
The same postures with only the named points (#131).
E.g. a file with four tracked points, of which a calibration fits one: the adapter keeps all four and the calibration selects.
Source code in src/figaroh/data/observations.py
127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 | |
from_csv(path, model, calib_config, *, del_list=(), frame='', registered_to='', orientation='unspecified', source=None)
classmethod
¶
Read the CSV layout calibration.data_loader.load_data reads.
Columns x1, y1, ... phiz1 per marker (the measured DOF only) and
one column per active joint. del_list rows are masked, not
deleted. A session_id column, if present, gives the sessions.
Does not modify calib_config.
Raises:
| Type | Description |
|---|---|
KeyError
|
listing every missing column. |
Source code in src/figaroh/data/observations.py
148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 | |
to_legacy(model, calib_config)
¶
(PEE_measured, q_measured) exactly as load_data returns them.
Valid (unmasked) postures only. PEE_measured is component-major
(x1 over samples, then y1, ...); q_measured is the full
configuration, calib_config["q0"] with the active joints set.
Does not modify calib_config or q0; the sample count is
len(q_measured).
Source code in src/figaroh/data/observations.py
211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 | |
Where a dataset came from (docs/decisions/data-result-contract.md).
Session(id, date=None)
dataclass
¶
A recording's identity: what it is, not how a study uses it.
Roles (training, validation, ...) belong to a
:class:~figaroh.data.protocol.Protocol, not here.
DataSource(files=dict(), adapter='', session=None, notes='')
dataclass
¶
Files (with sha256), the adapter that read them, and the session.
from_files(paths, adapter='', session=None, notes='')
classmethod
¶
Hash the given files now.
Source code in src/figaroh/data/source.py
54 55 56 57 58 59 60 61 62 63 64 | |
file_sha256(path)
¶
sha256 of a file's bytes.
Source code in src/figaroh/data/source.py
24 25 26 27 28 29 30 | |
Which session plays which role in a study (data-result-contract.md).
A session's identity is part of the data (:class:~figaroh.data.source.
Session); its role is not: the same recording can validate one study and
train another. A Protocol assigns roles and names each session's files
by sha256, so a frozen protocol cannot silently change under it.
YAML layout::
name: tiago-mocap-heldout
version: 1
sessions:
- id: 2021-11-30-1544
role: training
files:
data/qualisys_2021-11-30_static_postures.csv: b6c0051e...
Protocol(name, version, sessions)
dataclass
¶
verify(root=None)
¶
Check every session file against its recorded sha256.
Paths are relative to root (default: the working directory).
Raises:
| Type | Description |
|---|---|
ValueError
|
listing every missing or changed file. |
Source code in src/figaroh/data/protocol.py
86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 | |