use crate::{Body, Joint, State};
use crate::math::{GRAVITY, SpatialInertia, SpatialTransform, Vec3};
#[derive(Debug, Clone)]
pub struct Actuator {
pub name: String,
pub joint_name: String,
pub joint_idx: usize,
pub gear: f64,
pub ctrl_range: Option<[f64; 2]>,
}
#[derive(Debug, Clone)]
pub struct Model {
pub bodies: Vec<Body>,
pub joints: Vec<Joint>,
pub gravity: Vec3,
pub dt: f64,
pub nq: usize,
pub nv: usize,
pub q_offsets: Vec<usize>,
pub v_offsets: Vec<usize>,
pub actuators: Vec<Actuator>,
}
impl Model {
pub fn default_state(&self) -> State {
State::new(self.nq, self.nv, self.bodies.len())
}
pub fn nbodies(&self) -> usize {
self.bodies.len()
}
}
pub struct ModelBuilder {
bodies: Vec<Body>,
joints: Vec<Joint>,
gravity: Vec3,
dt: f64,
}
impl ModelBuilder {
pub fn new() -> Self {
Self {
bodies: Vec::new(),
joints: Vec::new(),
gravity: Vec3::new(0.0, 0.0, -GRAVITY),
dt: 0.001,
}
}
pub fn gravity(mut self, g: Vec3) -> Self {
self.gravity = g;
self
}
pub fn dt(mut self, dt: f64) -> Self {
self.dt = dt;
self
}
pub fn add_revolute_body(
mut self,
name: &str,
parent: i32,
parent_to_joint: SpatialTransform,
inertia: SpatialInertia,
) -> Self {
let joint_idx = self.joints.len();
self.joints.push(Joint::revolute(parent_to_joint));
self.bodies.push(Body {
name: name.to_string(),
inertia,
parent,
joint_idx,
geometry: None,
});
self
}
pub fn add_prismatic_body(
mut self,
name: &str,
parent: i32,
parent_to_joint: SpatialTransform,
axis: Vec3,
inertia: SpatialInertia,
) -> Self {
let joint_idx = self.joints.len();
self.joints.push(Joint::prismatic(parent_to_joint, axis));
self.bodies.push(Body {
name: name.to_string(),
inertia,
parent,
joint_idx,
geometry: None,
});
self
}
pub fn add_spherical_body(
mut self,
name: &str,
parent: i32,
parent_to_joint: SpatialTransform,
inertia: SpatialInertia,
) -> Self {
let joint_idx = self.joints.len();
self.joints.push(Joint::spherical(parent_to_joint));
self.bodies.push(Body {
name: name.to_string(),
inertia,
parent,
joint_idx,
geometry: None,
});
self
}
pub fn add_free_body(
mut self,
name: &str,
parent: i32,
parent_to_joint: SpatialTransform,
inertia: SpatialInertia,
) -> Self {
let joint_idx = self.joints.len();
self.joints.push(Joint::free(parent_to_joint));
self.bodies.push(Body {
name: name.to_string(),
inertia,
parent,
joint_idx,
geometry: None,
});
self
}
pub fn add_fixed_body(
mut self,
name: &str,
parent: i32,
parent_to_joint: SpatialTransform,
inertia: SpatialInertia,
) -> Self {
let joint_idx = self.joints.len();
self.joints.push(Joint::fixed(parent_to_joint));
self.bodies.push(Body {
name: name.to_string(),
inertia,
parent,
joint_idx,
geometry: None,
});
self
}
pub fn add_body(
mut self,
name: &str,
parent: i32,
joint: Joint,
inertia: SpatialInertia,
) -> Self {
let joint_idx = self.joints.len();
self.joints.push(joint);
self.bodies.push(Body {
name: name.to_string(),
inertia,
parent,
joint_idx,
geometry: None,
});
self
}
pub fn add_free_body_with_geometry(
mut self,
name: &str,
parent: i32,
parent_to_joint: SpatialTransform,
inertia: SpatialInertia,
geometry: super::Body,
) -> Self {
let joint_idx = self.joints.len();
self.joints.push(Joint::free(parent_to_joint));
self.bodies.push(Body {
name: name.to_string(),
inertia,
parent,
joint_idx,
geometry: geometry.geometry,
});
self
}
pub fn build(self) -> Model {
let mut nq = 0;
let mut nv = 0;
let mut q_offsets = Vec::new();
let mut v_offsets = Vec::new();
for joint in &self.joints {
q_offsets.push(nq);
v_offsets.push(nv);
nq += joint.ndof();
nv += joint.ndof();
}
Model {
bodies: self.bodies,
joints: self.joints,
gravity: self.gravity,
dt: self.dt,
nq,
nv,
q_offsets,
v_offsets,
actuators: Vec::new(),
}
}
}
impl Default for ModelBuilder {
fn default() -> Self {
Self::new()
}
}