Core Concepts
Reforge Robotics builds tooling for robot calibration, dynamic model identification, and model-based control. To use Reforge's software, there are three (3) core components you need to be familiar with:
Reforge SDK - a PyPi (pip-installable) package containing the calibration and control modules for users to install. See the SDK documentation for usage.
Reforge Inteface SDK - an open-source Github repository that contains code for implementing Reforge's interface with your robot's SDK, running the calibration routines, and calling the cloud API to process calibration data. This repository includes the installable Reforge SDK in the
requirements.txtfile. See the Interface SDK documentation for usage.Reforge Cloud API - Reforge's cloud-based API endpoints with functions to generate and fine-tune models for control using calibration data from the robots. See the API reference for usage.
A typical flow goes as follows:
- Clone the Reforge Interface SDK repository, add your robot's SDK to
requirements.txt, and install libraries.
git clone https://github.com/reforge-robotics/reforge-interface.git
python3 -m venv venv
source venv/bin/activate
pip install -r requirements.txt
- Integrate the robot's interface with the URDF and SDK (see automatic or manual integrations).
- Run the calibration routine with your api token.
python3 -m robot.run calibrate <robot_ip>
--freq <data_sample_frequency> --identify <reforge_api_token>
- After the calibration is complete, the data files will be stored in
src/robot/data/{YYYY}-{M}-{D}. Thereforge_coreSDK will attempt to push the data file to the Reforge API where our API will process the file and generate a PyTorch model for each of robot's joints. As a fallback, the data will be sent to calibration@reforgerobotics.com and we will manually send the models to the email associated with yourrobot_idon the Client Portal. If the robot is not connected to the internet, the identification will fail and you will need to manually upload your data from the Client Portal or send it via email. You can remove the--identifyflag if you do not want the identification to run automatically. - After the models are received from the API, they are be stored in the
src/robot/models/currentfolder (as well as thesrc/robot/models/{YYYY}-{M}-{D}folder). - To use the models for control, generate a trajectory you want to send to the robot and run that trajectory through the controller. For example:
import numpy as np
from pathlib import Path
from reforge_core.control.python.covalent_wrapper import (
ShaperInterface,
RobotState,
)
THIS_DIR = Path(__file__).resolve().parent
REPO_ROOT = THIS_DIR.parents[2]
# --- Configuration ---
Ts = 0.005 # 200 Hz sampling
num_axes = 3 # zero-indexed number of axes to compensate (i.e., 0,1,2)
num_joints = 6 # number of joints in the robot
python_src_root = REPO_ROOT / "src"
urdf_filepath = REPO_ROOT / "src/robot/urdf/test_robot.urdf"
def main():
# --- Initialize ---
shaper = ShaperInterface(
sample_time=Ts,
python_src_root=str(python_src_root),
urdf_filepath=str(urdf_filepath),
num_axes=num_axes,
num_joints=num_joints,
)
# --- Example trajectory ---
N = 200
times = np.arange(N) * Ts
# Generate a simple sinusoidal trajectory on 3 shaped joints
trajectory = np.zeros((N, num_joints))
trajectory[:, 0] = 0.25 * np.sin(2 * np.pi * 1.0 * t) # 1 Hz motion
trajectory[:, 1] = 0.20 * np.sin(2 * np.pi * 0.8 * t + 1)
trajectory[:, 2] = 0.15 * np.sin(2 * np.pi * 1.2 * t + 2)
# Sample-by-sample stream. Useful when you don't know the entire trajectory apriori.
positions = []
velocities = []
accelerations = []
last_time = times[0] if len(times) else 0.0
for i, cmd in enumerate(trajectory):
state = RobotState(joint_angles=cmd)
sample = shaper.shape_sample(cmd, state)
positions.append((times[i], sample.positions))
velocities.append((times[i], sample.velocities))
accelerations.append((times[i], sample.accelerations))
last_time = times[i]
# Shaper adds a small delay, and will need to extend the time to finish.
for tail_idx, tail in enumerate(shaper.finalize()):
t = last_time + (tail_idx + 1) * shaper.sample_time
positions.append((t, tail.positions))
velocities.append((t, tail.velocities))
accelerations.append((t, tail.accelerations))
print("Sample-by-sample shaper complete.\n Send positions, velocities, and accelerations to the robot.")
# Reset the shaper
shaper.reset()
# With the whole trajectory
states = [RobotState(joint_angles=trajectory[i].copy()) for i in range(N)]
shaped_traj = shaper.shape_trajectory(trajectory, states, time_vector=list(times))
print("Trajectory shaper complete.\n Send shaped_traj.positions, shaped_traj.velocities, shaped_traj.accelerations to the robot.")
if __name__ == "__main__":
main()
If you want to dive deeper, the following technical notes describe the theoretical foundations of our software approach.
System Identification – System identification is the methodology used to resolve the physical dynamics of a robot. This process identifies the parameters of the robot's Equations of Motion (EOM). See System Identification for the theoretical basis.
Physics-Based Model – A Finite Element Analysis (FEA) engine that models the real-world physics of the robot. It executes a full machine calibration by explicitly calculating and compensating for structural deformations. See Physics-Based Modeling for technical details.