use crate::Error;
use image::{ImageBuffer, Luma, RgbaImage};
use nalgebra::{
DVector, Isometry3, Matrix3xX, Matrix4, Matrix6xX, Quaternion, Translation3, UnitQuaternion,
Vector3, Vector6, U3,
};
use rubullet_sys::{
b3BodyInfo, b3ContactPointData, b3DynamicsInfo, b3JointInfo, b3JointSensorState, b3LinkState,
b3OpenGLVisualizerCameraInfo, b3PhysicsSimulationParameters, b3RayHitInfo, b3UserConstraint,
b3VisualShapeData,
};
use std::convert::TryFrom;
use std::ffi::CStr;
use std::os::raw::c_int;
use std::path::PathBuf;
use std::time::Duration;
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
pub struct BodyId(pub(crate) c_int);
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
pub struct VisualId(pub(crate) c_int);
impl VisualId {
pub const NONE: VisualId = VisualId(-1);
}
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
pub struct CollisionId(pub(crate) c_int);
impl CollisionId {
pub const NONE: CollisionId = CollisionId(-1);
}
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
pub struct TextureId(pub(crate) c_int);
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
pub struct ItemId(pub(crate) c_int);
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
pub struct ConstraintId(pub(crate) c_int);
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
pub struct LogId(pub(crate) c_int);
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
pub struct StateId(pub(crate) c_int);
#[derive(Debug, PartialEq, Copy, Clone)]
pub enum JointType {
Revolute = 0,
Prismatic = 1,
Spherical = 2,
Planar = 3,
Fixed = 4,
Point2Point = 5,
Gear = 6,
}
impl TryFrom<i32> for JointType {
type Error = Error;
fn try_from(value: i32) -> Result<Self, Self::Error> {
match value {
0 => Ok(JointType::Revolute),
1 => Ok(JointType::Prismatic),
2 => Ok(JointType::Spherical),
3 => Ok(JointType::Planar),
4 => Ok(JointType::Fixed),
5 => Ok(JointType::Point2Point),
6 => Ok(JointType::Gear),
_ => Err(Error::new("could not convert into a valid joint type")),
}
}
}
#[derive(Debug)]
pub struct JointInfo {
pub joint_index: usize,
pub joint_name: String,
pub joint_type: JointType,
pub q_index: i32,
pub u_index: i32,
#[doc(hidden)]
pub flags: JointInfoFlags,
pub joint_damping: f64,
pub joint_friction: f64,
pub joint_lower_limit: f64,
pub joint_upper_limit: f64,
pub joint_max_force: f64,
pub joint_max_velocity: f64,
pub link_name: String,
pub joint_axis: Vector3<f64>,
pub parent_frame_pose: Isometry3<f64>,
pub parent_index: Option<usize>,
}
impl From<b3JointInfo> for JointInfo {
fn from(b3: b3JointInfo) -> Self {
unsafe {
let b3JointInfo {
m_link_name,
m_joint_name,
m_joint_type,
m_q_index,
m_u_index,
m_joint_index,
m_flags,
m_joint_damping,
m_joint_friction,
m_joint_upper_limit,
m_joint_lower_limit,
m_joint_max_force,
m_joint_max_velocity,
m_parent_frame,
m_child_frame: _,
m_joint_axis,
m_parent_index,
m_q_size: _,
m_u_size: _,
} = b3;
let parent_index = match m_parent_index {
-1 => None,
index => Some(index as usize),
};
JointInfo {
link_name: CStr::from_ptr(m_link_name.as_ptr())
.to_string_lossy()
.into_owned(),
joint_name: CStr::from_ptr(m_joint_name.as_ptr())
.to_string_lossy()
.into_owned(),
joint_type: JointType::try_from(m_joint_type).unwrap(),
q_index: m_q_index,
u_index: m_u_index,
joint_index: m_joint_index as usize,
flags: JointInfoFlags::from_bits(m_flags).expect("Could not parse JointInfoFlags"),
joint_damping: m_joint_damping,
joint_friction: m_joint_friction,
joint_upper_limit: m_joint_upper_limit,
joint_lower_limit: m_joint_lower_limit,
joint_max_force: m_joint_max_force,
joint_max_velocity: m_joint_max_velocity,
parent_frame_pose: Isometry3::<f64>::from_parts(
Translation3::from(Vector3::from_column_slice(&m_parent_frame[0..4])),
UnitQuaternion::from_quaternion(Quaternion::from_parts(
m_parent_frame[6],
Vector3::from_column_slice(&m_parent_frame[3..6]),
)),
),
joint_axis: m_joint_axis.into(),
parent_index,
}
}
}
}
pub struct InverseKinematicsNullSpaceParameters<'a> {
pub lower_limits: &'a [f64],
pub upper_limits: &'a [f64],
pub joint_ranges: &'a [f64],
pub rest_poses: &'a [f64],
}
pub struct InverseKinematicsParameters<'a> {
pub end_effector_link_index: usize,
pub target_position: Vector3<f64>,
pub target_orientation: Option<UnitQuaternion<f64>>,
pub limits: Option<InverseKinematicsNullSpaceParameters<'a>>,
pub joint_damping: Option<&'a [f64]>,
pub solver: IkSolver,
pub current_position: Option<&'a [f64]>,
pub max_num_iterations: Option<usize>,
pub residual_threshold: Option<f64>,
}
pub enum IkSolver {
Dls = 0,
Sdls = 1,
}
impl From<IkSolver> for i32 {
fn from(solver: IkSolver) -> Self {
solver as i32
}
}
impl<'a> Default for InverseKinematicsParameters<'a> {
fn default() -> Self {
InverseKinematicsParameters {
end_effector_link_index: 0,
target_position: Vector3::zeros(),
target_orientation: None,
limits: None,
joint_damping: None,
solver: IkSolver::Dls,
current_position: None,
max_num_iterations: None,
residual_threshold: None,
}
}
}
pub struct InverseKinematicsParametersBuilder<'a> {
params: InverseKinematicsParameters<'a>,
}
impl<'a> InverseKinematicsParametersBuilder<'a> {
pub fn new(end_effector_link_index: usize, target_pose: &'a Isometry3<f64>) -> Self {
let target_position = target_pose.translation.vector;
let params = InverseKinematicsParameters {
end_effector_link_index,
target_position,
target_orientation: Some(target_pose.rotation),
..Default::default()
};
InverseKinematicsParametersBuilder { params }
}
pub fn ignore_orientation(mut self) -> Self {
self.params.target_orientation = None;
self
}
pub fn use_null_space(mut self, limits: InverseKinematicsNullSpaceParameters<'a>) -> Self {
self.params.limits = Some(limits);
self
}
pub fn set_joint_damping(mut self, joint_damping: &'a [f64]) -> Self {
self.params.joint_damping = Some(joint_damping);
self
}
pub fn set_ik_solver(mut self, solver: IkSolver) -> Self {
self.params.solver = solver;
self
}
pub fn set_current_position(mut self, current_position: &'a [f64]) -> Self {
self.params.current_position = Some(current_position);
self
}
pub fn set_max_num_iterations(mut self, iterations: usize) -> Self {
self.params.max_num_iterations = Some(iterations);
self
}
pub fn set_residual_threshold(mut self, residual_threshold: f64) -> Self {
self.params.residual_threshold = Some(residual_threshold);
self
}
pub fn build(self) -> InverseKinematicsParameters<'a> {
self.params
}
}
pub struct AddDebugTextOptions {
pub text_color_rgb: [f64; 3],
pub text_size: f64,
pub life_time: f64,
pub text_orientation: Option<UnitQuaternion<f64>>,
pub parent_object_id: Option<BodyId>,
pub parent_link_index: Option<usize>,
pub replace_item_id: Option<ItemId>,
}
impl Default for AddDebugTextOptions {
fn default() -> Self {
AddDebugTextOptions {
text_color_rgb: [1.; 3],
text_size: 1.,
life_time: 0.,
text_orientation: None,
parent_object_id: None,
parent_link_index: None,
replace_item_id: None,
}
}
}
pub struct AddDebugLineOptions {
pub line_color_rgb: [f64; 3],
pub line_width: f64,
pub life_time: f64,
pub parent_object_id: Option<BodyId>,
pub parent_link_index: Option<usize>,
pub replace_item_id: Option<ItemId>,
}
impl Default for AddDebugLineOptions {
fn default() -> Self {
AddDebugLineOptions {
line_color_rgb: [1.; 3],
line_width: 1.,
life_time: 0.,
parent_object_id: None,
parent_link_index: None,
replace_item_id: None,
}
}
}
#[derive(Debug, Clone)]
pub struct Jacobian {
pub jacobian: Matrix6xX<f64>,
}
impl<T: Into<DVector<f64>>> std::ops::Mul<T> for Jacobian {
type Output = Velocity;
fn mul(self, q_dot: T) -> Self::Output {
let vel = self.jacobian * q_dot.into();
Velocity(vel)
}
}
impl Jacobian {
pub fn get_linear_jacobian(&self) -> Matrix3xX<f64> {
Matrix3xX::from(self.jacobian.fixed_rows::<U3>(0))
}
pub fn get_angular_jacobian(&self) -> Matrix3xX<f64> {
Matrix3xX::from(self.jacobian.fixed_rows::<U3>(3))
}
}
pub enum ExternalForceFrame {
LinkFrame = 1,
WorldFrame = 2,
}
#[derive(Debug, Copy, Clone, Default)]
pub struct KeyboardEvent {
pub key: char,
pub(crate) key_state: i32,
}
impl KeyboardEvent {
pub fn was_triggered(&self) -> bool {
self.key_state & 2 == 2
}
pub fn is_down(&self) -> bool {
self.key_state & 1 == 1
}
pub fn is_released(&self) -> bool {
self.key_state & 4 == 4
}
}
#[derive(Debug, Copy, Clone)]
pub enum MouseEvent {
Move {
mouse_pos_x: f32,
mouse_pos_y: f32,
},
Button {
mouse_pos_x: f32,
mouse_pos_y: f32,
button_index: i32,
button_state: MouseButtonState,
},
}
#[derive(Debug, Copy, Clone)]
pub struct MouseButtonState {
pub(crate) flag: i32,
}
impl MouseButtonState {
pub fn was_triggered(&self) -> bool {
self.flag & 2 == 2
}
pub fn is_pressed(&self) -> bool {
self.flag & 1 == 1
}
pub fn is_released(&self) -> bool {
self.flag & 4 == 4
}
}
#[derive(Debug, Default, Copy, Clone)]
pub struct JointState {
pub joint_position: f64,
pub joint_velocity: f64,
pub joint_force_torque: [f64; 6],
pub joint_motor_torque: f64,
}
impl From<b3JointSensorState> for JointState {
fn from(b3: b3JointSensorState) -> Self {
let b3JointSensorState {
m_joint_position,
m_joint_velocity,
m_joint_force_torque,
m_joint_motor_torque,
} = b3;
JointState {
joint_position: m_joint_position,
joint_velocity: m_joint_velocity,
joint_force_torque: m_joint_force_torque,
joint_motor_torque: m_joint_motor_torque,
}
}
}
pub struct UrdfOptions {
pub base_transform: Isometry3<f64>,
pub use_fixed_base: bool,
pub use_maximal_coordinates: Option<bool>,
pub flags: LoadModelFlags,
pub global_scaling: f64,
}
impl Default for UrdfOptions {
fn default() -> UrdfOptions {
UrdfOptions {
base_transform: Isometry3::identity(),
use_fixed_base: false,
use_maximal_coordinates: None,
global_scaling: -1.0,
flags: LoadModelFlags::NONE,
}
}
}
pub struct SdfOptions {
pub use_maximal_coordinates: bool,
pub global_scaling: f64,
}
impl Default for SdfOptions {
fn default() -> Self {
SdfOptions {
use_maximal_coordinates: false,
global_scaling: 1.0,
}
}
}
pub enum ControlCommand {
Position(f64),
PositionWithPd {
target_position: f64,
target_velocity: f64,
position_gain: f64,
velocity_gain: f64,
maximum_velocity: Option<f64>,
},
Velocity(f64),
Torque(f64),
Pd {
target_position: f64,
target_velocity: f64,
position_gain: f64,
velocity_gain: f64,
maximum_velocity: Option<f64>,
},
}
impl ControlCommand {
pub(crate) fn get_int(&self) -> i32 {
match self {
ControlCommand::Position(_) => 2,
ControlCommand::Velocity(_) => 0,
ControlCommand::Torque(_) => 1,
ControlCommand::Pd { .. } => 3,
ControlCommand::PositionWithPd { .. } => 2,
}
}
}
pub enum ControlCommandArray<'a> {
Positions(&'a [f64]),
PositionsWithPd {
target_positions: &'a [f64],
target_velocities: &'a [f64],
position_gains: &'a [f64],
velocity_gains: &'a [f64],
},
Velocities(&'a [f64]),
Torques(&'a [f64]),
Pd {
target_positions: &'a [f64],
target_velocities: &'a [f64],
position_gains: &'a [f64],
velocity_gains: &'a [f64],
},
}
impl ControlCommandArray<'_> {
pub(crate) fn get_int(&self) -> i32 {
match self {
ControlCommandArray::Positions(_) => 2,
ControlCommandArray::Velocities(_) => 0,
ControlCommandArray::Torques(_) => 1,
ControlCommandArray::Pd { .. } => 3,
ControlCommandArray::PositionsWithPd { .. } => 2,
}
}
}
pub enum DebugVisualizerFlag {
CovEnableGui = 1,
CovEnableShadows,
CovEnableWireframe,
CovEnableVrTeleporting,
CovEnableVrPicking,
CovEnableVrRenderControllers,
CovEnableRendering,
CovEnableSyncRenderingInternal,
CovEnableKeyboardShortcuts,
CovEnableMousePicking,
CovEnableYAxisUp,
CovEnableTinyRenderer,
CovEnableRgbBufferPreview,
CovEnableDepthBufferPreview,
CovEnableSegmentationMarkPreview,
CovEnablePlanarReflection,
CovEnableSingleStepRendering,
}
#[derive(Debug)]
pub struct LinkState {
pub world_pose: Isometry3<f64>,
pub local_inertial_pose: Isometry3<f64>,
pub world_link_frame_pose: Isometry3<f64>,
pub world_velocity: Option<Velocity>,
}
impl LinkState {
pub fn get_linear_world_velocity(&self) -> Result<Vector3<f64>, Error> {
match &self.world_velocity {
None => {Err(Error::new("LinkState contains no velocity. You have to set compute_link_velocity to true in get_link_state() to get the velocity"))}
Some(velocity) => {Ok(velocity.get_linear_velocity())}
}
}
pub fn get_angular_world_velocity(&self) -> Result<Vector3<f64>, Error> {
match &self.world_velocity {
None => {Err(Error::new("LinkState contains no velocity. You have to set compute_link_velocity to true in get_link_state() to get the velocity"))}
Some(velocity) => {Ok(velocity.get_angular_velocity())}
}
}
pub fn get_world_velocity(&self) -> Result<&Velocity, Error> {
match &self.world_velocity {
None => {Err(Error::new("LinkState contains no velocity. You have to set compute_link_velocity to true in get_link_state() to get the velocity"))}
Some(velocity) => {Ok(velocity)}
}
}
pub fn get_world_velocity_vector(&self) -> Result<Vector6<f64>, Error> {
match &self.world_velocity {
None => {Err(Error::new("LinkState contains no velocity. You have to set compute_link_velocity to true in get_link_state() to get the velocity"))}
Some(velocity) => {Ok(velocity.to_vector())}
}
}
}
impl From<(b3LinkState, bool)> for LinkState {
fn from(b3: (b3LinkState, bool)) -> Self {
let (
b3LinkState {
m_world_position,
m_world_orientation,
m_local_inertial_position,
m_local_inertial_orientation,
m_world_link_frame_position,
m_world_link_frame_orientation,
m_world_linear_velocity,
m_world_angular_velocity,
m_world_aabb_min: _,
m_world_aabb_max: _,
},
velocity_valid,
) = b3;
let mut state = LinkState {
world_pose: position_orientation_to_isometry(m_world_position, m_world_orientation),
local_inertial_pose: position_orientation_to_isometry(
m_local_inertial_position,
m_local_inertial_orientation,
),
world_link_frame_pose: position_orientation_to_isometry(
m_world_link_frame_position,
m_world_link_frame_orientation,
),
world_velocity: None,
};
if velocity_valid {
let velocity: [f64; 6] = [
m_world_linear_velocity[0],
m_world_linear_velocity[1],
m_world_linear_velocity[2],
m_world_angular_velocity[0],
m_world_angular_velocity[1],
m_world_angular_velocity[2],
];
state.world_velocity = Some(velocity.into());
}
state
}
}
pub(crate) fn position_orientation_to_isometry(
position: [f64; 3],
orientation: [f64; 4],
) -> Isometry3<f64> {
Isometry3::<f64>::from_parts(
Translation3::from(Vector3::from_column_slice(&position)),
UnitQuaternion::from_quaternion(Quaternion::from_parts(
orientation[3],
Vector3::from_column_slice(&orientation[0..3]),
)),
)
}
pub(crate) fn combined_position_orientation_array_to_isometry(
combined: [f64; 7],
) -> Isometry3<f64> {
let position = [combined[0], combined[1], combined[2]];
let orientation = [combined[3], combined[4], combined[5], combined[6]];
position_orientation_to_isometry(position, orientation)
}
pub struct VisualShapeOptions {
pub frame_offset: Isometry3<f64>,
pub rgba_colors: [f64; 4],
pub specular_colors: [f64; 3],
#[doc(hidden)]
pub flags: Option<VisualShapeFlags>,
}
impl Default for VisualShapeOptions {
fn default() -> Self {
VisualShapeOptions {
frame_offset: Isometry3::translation(0., 0., 0.),
rgba_colors: [1.; 4],
specular_colors: [1.; 3],
flags: None,
}
}
}
pub enum GeometricCollisionShape {
Sphere {
radius: f64,
},
Box {
half_extents: Vector3<f64>,
},
Capsule {
radius: f64,
height: f64,
},
Cylinder {
radius: f64,
height: f64,
},
Plane {
plane_normal: Vector3<f64>,
},
MeshFile {
filename: PathBuf,
mesh_scaling: Option<Vector3<f64>>,
flags: Option<i32>,
},
Mesh {
vertices: Vec<[f64; 3]>,
indices: Option<Vec<i32>>,
mesh_scaling: Option<Vector3<f64>>,
},
HeightfieldFile {
filename: PathBuf,
mesh_scaling: Option<Vector3<f64>>,
texture_scaling: f64,
},
Heightfield {
mesh_scaling: Option<Vector3<f64>>,
texture_scaling: f64,
data: Vec<f32>,
num_rows: usize,
num_columns: usize,
replace_heightfield: Option<CollisionId>,
},
}
pub enum GeometricVisualShape {
Sphere {
radius: f64,
},
Box {
half_extents: Vector3<f64>,
},
Capsule {
radius: f64,
length: f64,
},
Cylinder {
radius: f64,
length: f64,
},
Plane {
plane_normal: Vector3<f64>,
},
MeshFile {
filename: PathBuf,
mesh_scaling: Option<Vector3<f64>>,
},
Mesh {
mesh_scaling: Option<Vector3<f64>>,
vertices: Vec<[f64; 3]>,
indices: Vec<i32>,
uvs: Option<Vec<[f64; 2]>>,
normals: Option<Vec<[f64; 3]>>,
},
}
pub struct MultiBodyOptions {
pub base_mass: f64,
pub base_pose: Isometry3<f64>,
pub base_inertial_frame_pose: Isometry3<f64>,
pub link_masses: Vec<f64>,
pub link_collision_shapes: Vec<CollisionId>,
pub link_visual_shapes: Vec<VisualId>,
pub link_poses: Vec<Isometry3<f64>>,
pub link_inertial_frame_poses: Vec<Isometry3<f64>>,
pub link_parent_indices: Vec<i32>,
pub link_joint_types: Vec<JointType>,
pub link_joint_axis: Vec<Vector3<f64>>,
pub use_maximal_coordinates: bool,
pub flags: Option<LoadModelFlags>,
}
impl Default for MultiBodyOptions {
fn default() -> Self {
MultiBodyOptions {
base_pose: Isometry3::translation(0., 0., 0.),
base_inertial_frame_pose: Isometry3::translation(0., 0., 0.),
base_mass: 0.0,
link_masses: Vec::new(),
link_collision_shapes: Vec::new(),
link_visual_shapes: Vec::new(),
link_poses: Vec::new(),
link_inertial_frame_poses: Vec::new(),
link_parent_indices: Vec::new(),
link_joint_types: Vec::new(),
link_joint_axis: Vec::new(),
use_maximal_coordinates: false,
flags: None,
}
}
}
pub struct ChangeVisualShapeOptions {
pub shape: VisualId,
pub texture_id: Option<TextureId>,
pub rgba_color: Option<[f64; 4]>,
pub specular_color: Option<[f64; 3]>,
#[doc(hidden)]
pub flags: Option<VisualShapeFlags>,
}
impl Default for ChangeVisualShapeOptions {
fn default() -> Self {
ChangeVisualShapeOptions {
shape: VisualId(-1),
texture_id: None,
rgba_color: None,
specular_color: None,
flags: None,
}
}
}
#[derive(Debug)]
pub struct BodyInfo {
pub base_name: String,
pub body_name: String,
}
impl From<b3BodyInfo> for BodyInfo {
fn from(info: b3BodyInfo) -> Self {
unsafe {
BodyInfo {
base_name: CStr::from_ptr(info.m_baseName.as_ptr())
.to_string_lossy()
.into_owned(),
body_name: CStr::from_ptr(info.m_bodyName.as_ptr())
.to_string_lossy()
.into_owned(),
}
}
}
}
#[derive(Debug)]
pub struct VisualShapeData {
pub body_id: BodyId,
pub link_index: Option<usize>,
pub visual_geometry_type: i32,
pub dimensions: [f64; 3],
pub mesh_asset_file_name: String,
pub local_visual_frame_pose: Isometry3<f64>,
pub rgba_color: [f64; 4],
pub texture_id: Option<TextureId>,
}
impl From<b3VisualShapeData> for VisualShapeData {
fn from(b3: b3VisualShapeData) -> Self {
unsafe {
let link_index = match b3.m_linkIndex {
-1 => None,
index => Some(index as usize),
};
VisualShapeData {
body_id: BodyId(b3.m_objectUniqueId),
link_index,
visual_geometry_type: b3.m_visualGeometryType,
dimensions: b3.m_dimensions,
mesh_asset_file_name: CStr::from_ptr(b3.m_meshAssetFileName.as_ptr())
.to_string_lossy()
.into_owned(),
local_visual_frame_pose: combined_position_orientation_array_to_isometry(
b3.m_localVisualFrame,
),
rgba_color: b3.m_rgbaColor,
texture_id: None,
}
}
}
}
pub struct Images {
pub width: usize,
pub height: usize,
pub rgba: RgbaImage,
pub depth: ImageBuffer<Luma<f32>, Vec<f32>>,
pub segmentation: ImageBuffer<Luma<i32>, Vec<i32>>,
}
#[derive(Debug)]
pub struct Velocity(Vector6<f64>);
impl Velocity {
pub fn get_linear_velocity(&self) -> Vector3<f64> {
self.0.fixed_rows::<U3>(0).into()
}
pub fn get_angular_velocity(&self) -> Vector3<f64> {
self.0.fixed_rows::<U3>(3).into()
}
pub fn to_vector(&self) -> Vector6<f64> {
self.0
}
}
impl From<[f64; 6]> for Velocity {
fn from(input: [f64; 6]) -> Self {
Velocity(input.into())
}
}
impl From<Vector6<f64>> for Velocity {
fn from(input: Vector6<f64>) -> Self {
Velocity(input)
}
}
bitflags::bitflags! {
pub struct LoadModelFlags : i32 {
const NONE = 0;
const URDF_USE_INERTIA_FROM_FILE = 2;
const URDF_USE_SELF_COLLISION = 8;
const URDF_USE_SELF_COLLISION_EXCLUDE_PARENT = 16;
const URDF_USE_SELF_COLLISION_EXCLUDE_ALL_PARENTS = 32;
const URDF_RESERVED = 64;
const URDF_USE_IMPLICIT_CYLINDER = 128;
const URDF_GLOBAL_VELOCITIES_MB = 256;
const MJCF_COLORS_FROM_FILE = 512;
const URDF_ENABLE_CACHED_GRAPHICS_SHAPES = 1024;
const URDF_ENABLE_SLEEPING = 2048;
const URDF_INITIALIZE_SAT_FEATURES = 4096;
const URDF_USE_SELF_COLLISION_INCLUDE_PARENT = 8192;
const URDF_PARSE_SENSORS = 16384;
const URDF_USE_MATERIAL_COLORS_FROM_MTL = 32768;
const URDF_USE_MATERIAL_TRANSPARANCY_FROM_MTL = 65536;
const URDF_MAINTAIN_LINK_ORDER = 131072;
const URDF_ENABLE_WAKEUP = 262144;
const URDF_MERGE_FIXED_LINKS = 1 << 19;
const URDF_IGNORE_VISUAL_SHAPES = 1 << 20;
const URDF_IGNORE_COLLISION_SHAPES = 1 << 21;
const URDF_PRINT_URDF_INFO = 1 << 22;
const URDF_GOOGLEY_UNDEFINED_COLORS = 1 << 23;
}
}
impl Default for LoadModelFlags {
fn default() -> Self {
LoadModelFlags::NONE
}
}
bitflags::bitflags! {
#[doc(hidden)]
pub struct JointInfoFlags : i32 {
const NONE = 0;
const JOINT_CHANGE_MAX_FORCE = 1;
const JOINT_CHANGE_CHILD_FRAME_POSITION = 2;
const JOINT_CHANGE_CHILD_FRAME_ORIENTATION = 4;
}
}
impl Default for JointInfoFlags {
fn default() -> Self {
JointInfoFlags::NONE
}
}
#[derive(Default)]
pub struct ChangeConstraintOptions {
pub joint_child_pivot: Option<Vector3<f64>>,
pub joint_child_frame_orientation: Option<UnitQuaternion<f64>>,
pub max_force: Option<f64>,
pub gear_ratio: Option<f64>,
pub gear_aux_link: Option<usize>,
pub relative_position_target: Option<f64>,
pub erp: Option<f64>,
}
#[derive(Debug)]
pub struct ConstraintInfo {
pub id: ConstraintId,
pub parent_body: BodyId,
pub parent_link_index: Option<usize>,
pub child_body: Option<BodyId>,
pub child_link_index: Option<usize>,
pub constraint_type: JointType,
pub joint_axis: Vector3<f64>,
pub joint_parent_frame_pose: Isometry3<f64>,
pub joint_child_frame_pose: Isometry3<f64>,
pub max_applied_force: f64,
pub gear_ratio: f64,
pub gear_aux_link: Option<usize>,
pub relative_position_target: f64,
pub erp: f64,
}
impl From<b3UserConstraint> for ConstraintInfo {
fn from(b3: b3UserConstraint) -> Self {
#[allow(non_snake_case)]
let b3UserConstraint {
m_parentBodyIndex,
m_parentJointIndex,
m_childBodyIndex,
m_childJointIndex,
m_parentFrame,
m_childFrame,
m_jointAxis,
m_jointType,
m_maxAppliedForce,
m_userConstraintUniqueId,
m_gearRatio,
m_gearAuxLink,
m_relativePositionTarget,
m_erp,
} = b3;
let parent_joint_index = {
if m_parentJointIndex >= 0 {
Some(m_parentJointIndex as usize)
} else {
None
}
};
let child_link_index = {
if m_childJointIndex >= 0 {
Some(m_childJointIndex as usize)
} else {
None
}
};
let gear_aux_link = {
if m_gearAuxLink >= 0 {
Some(m_gearAuxLink as usize)
} else {
None
}
};
let child_body = {
if m_childBodyIndex >= 0 {
Some(BodyId(m_childBodyIndex))
} else {
None
}
};
ConstraintInfo {
id: ConstraintId(m_userConstraintUniqueId),
parent_body: BodyId(m_parentBodyIndex),
parent_link_index: parent_joint_index,
child_body,
child_link_index,
constraint_type: JointType::try_from(m_jointType).unwrap(),
joint_axis: m_jointAxis.into(),
joint_parent_frame_pose: combined_position_orientation_array_to_isometry(m_parentFrame),
joint_child_frame_pose: combined_position_orientation_array_to_isometry(m_childFrame),
max_applied_force: m_maxAppliedForce,
gear_ratio: m_gearRatio,
gear_aux_link,
relative_position_target: m_relativePositionTarget,
erp: m_erp,
}
}
}
bitflags::bitflags! {
pub struct ActivationState : i32 {
const ENABLE_SLEEPING = 1;
const DISABLE_SLEEPING = 2;
const WAKE_UP = 4;
const SLEEP = 8;
const ENABLE_WAKEUP = 16;
const DISABLE_WAKEUP = 32;
}
}
#[derive(Default, Debug, Clone)]
pub struct ChangeDynamicsOptions {
pub mass: Option<f64>,
pub lateral_friction: Option<f64>,
pub spinning_friction: Option<f64>,
pub rolling_friction: Option<f64>,
pub restitution: Option<f64>,
pub linear_damping: Option<f64>,
pub angular_damping: Option<f64>,
pub contact_stiffness_and_damping: Option<(f64, f64)>,
pub friction_anchor: Option<bool>,
pub local_inertia_diagonal: Option<Vector3<f64>>,
pub ccd_swept_sphere_radius: Option<f64>,
pub contact_processing_threshold: Option<f64>,
pub activation_state: Option<ActivationState>,
pub joint_damping: Option<f64>,
pub anisotropic_friction: Option<f64>,
pub max_joint_velocity: Option<f64>,
pub collision_margin: Option<f64>,
pub joint_limits: Option<(f64, f64)>,
pub joint_limit_force: Option<f64>,
}
#[derive(Debug)]
pub struct DynamicsInfo {
pub mass: f64,
pub lateral_friction: f64,
pub spinning_friction: f64,
pub rolling_friction: f64,
pub restitution: f64,
pub contact_stiffness_and_damping: Option<(f64, f64)>,
pub local_inertia_diagonal: Vector3<f64>,
pub local_inertial_pose: Isometry3<f64>,
pub body_type: BodyType,
pub collision_margin: f64,
}
#[derive(Debug, PartialOrd, PartialEq)]
pub enum BodyType {
RigidBody = 1,
MultiBody = 2,
SoftBody = 3,
}
impl From<b3DynamicsInfo> for DynamicsInfo {
fn from(b3: b3DynamicsInfo) -> Self {
#[allow(unused, non_snake_case)]
let b3DynamicsInfo {
m_mass,
m_localInertialDiagonal,
m_localInertialFrame,
m_lateralFrictionCoeff,
m_rollingFrictionCoeff,
m_spinningFrictionCoeff,
m_restitution,
m_contactStiffness,
m_contactDamping,
m_activationState,
m_bodyType,
m_angularDamping,
m_linearDamping,
m_ccdSweptSphereRadius,
m_contactProcessingThreshold,
m_frictionAnchor,
m_collisionMargin,
m_dynamicType,
} = b3;
let contact_stiffness_and_damping = {
if m_contactStiffness <= 0. || m_contactDamping <= 0. {
None
} else {
Some((m_contactStiffness, m_contactDamping))
}
};
DynamicsInfo {
mass: m_mass,
lateral_friction: m_lateralFrictionCoeff,
spinning_friction: m_spinningFrictionCoeff,
rolling_friction: m_rollingFrictionCoeff,
restitution: m_restitution,
contact_stiffness_and_damping,
local_inertia_diagonal: m_localInertialDiagonal.into(),
local_inertial_pose: combined_position_orientation_array_to_isometry(
m_localInertialFrame,
),
body_type: match m_bodyType {
1 => BodyType::RigidBody,
2 => BodyType::MultiBody,
3 => BodyType::SoftBody,
_ => panic!("internal error: Unknown BodyType ({})", m_bodyType),
},
collision_margin: m_collisionMargin,
}
}
}
#[derive(Debug)]
pub struct Aabb {
pub min: Vector3<f64>,
pub max: Vector3<f64>,
}
#[derive(Debug, Copy, Clone)]
pub struct OverlappingObject {
pub body: BodyId,
pub link_index: Option<usize>,
}
#[derive(Debug, Copy, Clone)]
pub struct ContactPoint {
#[doc(hidden)]
pub contact_flag: i32,
pub body_a: Option<BodyId>,
pub body_b: Option<BodyId>,
pub link_index_a: Option<usize>,
pub link_index_b: Option<usize>,
pub position_on_a: Vector3<f64>,
pub position_on_b: Vector3<f64>,
pub contact_normal_on_b: Vector3<f64>,
pub contact_distance: f64,
pub normal_force: Option<f64>,
pub lateral_friction_1: Vector3<f64>,
pub lateral_friction_2: Vector3<f64>,
}
impl From<b3ContactPointData> for ContactPoint {
fn from(b3: b3ContactPointData) -> Self {
#[allow(non_snake_case)]
let b3ContactPointData {
m_contactFlags,
m_bodyUniqueIdA,
m_bodyUniqueIdB,
m_linkIndexA,
m_linkIndexB,
m_positionOnAInWS,
m_positionOnBInWS,
m_contactNormalOnBInWS,
m_contactDistance,
m_normalForce,
m_linearFrictionForce1,
m_linearFrictionForce2,
m_linearFrictionDirection1,
m_linearFrictionDirection2,
} = b3;
let mut lateral_friction_1: Vector3<f64> = m_linearFrictionDirection1.into();
lateral_friction_1 *= m_linearFrictionForce1;
let mut lateral_friction_2: Vector3<f64> = m_linearFrictionDirection2.into();
lateral_friction_2 *= m_linearFrictionForce2;
let link_index_a = {
if m_linkIndexA.is_negative() {
None
} else {
Some(m_linkIndexA as usize)
}
};
let link_index_b = {
if m_linkIndexB.is_negative() {
None
} else {
Some(m_linkIndexB as usize)
}
};
let body_a = {
if m_bodyUniqueIdA < 0 {
None
} else {
Some(BodyId(m_bodyUniqueIdA))
}
};
let body_b = {
if m_bodyUniqueIdB < 0 {
None
} else {
Some(BodyId(m_bodyUniqueIdB))
}
};
ContactPoint {
contact_flag: m_contactFlags,
body_a,
body_b,
link_index_a,
link_index_b,
position_on_a: m_positionOnAInWS.into(),
position_on_b: m_positionOnBInWS.into(),
contact_normal_on_b: m_contactNormalOnBInWS.into(),
contact_distance: m_contactDistance,
normal_force: Some(m_normalForce),
lateral_friction_1,
lateral_friction_2,
}
}
}
pub enum LoggingType {
Minitaur = 0,
GenericRobot,
VrControllers,
VideoMp4,
Commands,
ContactPoints,
ProfileTimings,
AllCommands,
ReplayAllCommands,
CustomTimer,
}
#[derive(Debug, Default)]
pub struct StateLoggingOptions {
pub object_ids: Vec<BodyId>,
pub max_log_dof: Option<usize>,
pub body_a: Option<BodyId>,
pub link_index_a: Option<Option<usize>>,
pub body_b: Option<BodyId>,
pub link_index_b: Option<Option<usize>>,
#[doc(hidden)]
pub device_type_filter: Option<i32>,
pub log_flags: Option<LogFlags>,
}
bitflags::bitflags! {
pub struct LogFlags : i32 {
const JOINT_MOTOR_TORQUES = 1;
const JOINT_USER_TORQUES = 2;
const JOINT_TORQUES = 3;
}
}
#[derive(Default, Debug)]
pub struct SetPhysicsEngineParameterOptions {
pub fixed_time_step: Option<Duration>,
pub num_solver_iterations: Option<usize>,
pub use_split_impulse: Option<bool>,
pub split_impulse_penetration_threshold: Option<f64>,
pub num_sub_steps: Option<usize>,
pub collision_filter_mode: Option<usize>,
pub contact_breaking_threshold: Option<f64>,
pub max_num_cmd_per_1_ms: Option<i32>,
pub enable_file_caching: Option<bool>,
pub restitution_velocity_threshold: Option<f64>,
pub erp: Option<f64>,
pub contact_erp: Option<f64>,
pub friction_erp: Option<f64>,
pub enable_cone_friction: Option<bool>,
pub deterministic_overlapping_pairs: Option<bool>,
pub allowed_ccd_penetration: Option<f64>,
pub joint_feedback_mode: Option<JointFeedbackMode>,
pub solver_residual_threshold: Option<f64>,
pub contact_slop: Option<f64>,
pub enable_sat: Option<bool>,
pub constraint_solver_type: Option<ConstraintSolverType>,
pub global_cfm: Option<f64>,
pub minimum_solver_island_size: Option<usize>,
pub report_solver_analytics: Option<bool>,
pub warm_starting_factor: Option<f64>,
pub sparse_sdf_voxel_size: Option<f64>,
pub num_non_contact_inner_iterations: Option<usize>,
}
#[derive(Debug, PartialOrd, PartialEq)]
pub enum ConstraintSolverType {
None,
Si = 1,
Pgs,
Dantzig,
Lemke,
Nncg,
BlockPgs,
}
#[derive(Debug, PartialOrd, PartialEq)]
pub enum JointFeedbackMode {
None,
WorldSpace = 1,
JointFrame,
}
#[derive(Debug)]
pub struct PhysicsEngineParameters {
pub fixed_time_step: Duration,
pub simulation_time_stamp: Duration,
pub num_solver_iterations: usize,
pub use_split_impulse: bool,
pub split_impulse_penetration_threshold: f64,
pub num_sub_steps: usize,
pub collision_filter_mode: usize,
pub contact_breaking_threshold: f64,
pub enable_file_caching: bool,
pub restitution_velocity_threshold: f64,
pub erp: f64,
pub contact_erp: f64,
pub friction_erp: f64,
pub enable_cone_friction: bool,
pub deterministic_overlapping_pairs: bool,
pub allowed_ccd_penetration: f64,
pub joint_feedback_mode: JointFeedbackMode,
pub solver_residual_threshold: f64,
pub contact_slop: f64,
pub enable_sat: bool,
pub constraint_solver_type: ConstraintSolverType,
pub global_cfm: f64,
pub minimum_solver_island_size: usize,
pub report_solver_analytics: bool,
pub warm_starting_factor: f64,
pub sparse_sdf_voxel_size: f64,
pub num_non_contact_inner_iterations: usize,
pub use_real_time_simulation: bool,
pub gravity: Vector3<f64>,
pub articulated_warm_starting_factor: f64,
pub internal_sim_flags: i32,
pub friction_cfm: f64,
}
fn int_to_bool(int: i32) -> bool {
match int {
0 => false,
1 => true,
_ => panic!("could not convert \"{}\" to boolean", int),
}
}
impl From<b3PhysicsSimulationParameters> for PhysicsEngineParameters {
fn from(b3: b3PhysicsSimulationParameters) -> Self {
#[allow(non_snake_case)]
let b3PhysicsSimulationParameters {
m_deltaTime,
m_simulationTimestamp,
m_gravityAcceleration,
m_numSimulationSubSteps,
m_numSolverIterations,
m_warmStartingFactor,
m_articulatedWarmStartingFactor,
m_useRealTimeSimulation,
m_useSplitImpulse,
m_splitImpulsePenetrationThreshold,
m_contactBreakingThreshold,
m_internalSimFlags,
m_defaultContactERP,
m_collisionFilterMode,
m_enableFileCaching,
m_restitutionVelocityThreshold,
m_defaultNonContactERP,
m_frictionERP,
m_defaultGlobalCFM,
m_frictionCFM,
m_enableConeFriction,
m_deterministicOverlappingPairs,
m_allowedCcdPenetration,
m_jointFeedbackMode,
m_solverResidualThreshold,
m_contactSlop,
m_enableSAT,
m_constraintSolverType,
m_minimumSolverIslandSize,
m_reportSolverAnalytics,
m_sparseSdfVoxelSize,
m_numNonContactInnerIterations,
} = b3;
let joint_feedback_mode = {
match m_jointFeedbackMode {
0 => JointFeedbackMode::None,
1 => JointFeedbackMode::WorldSpace,
2 => JointFeedbackMode::JointFrame,
n => panic!("Unexpected JointFeedbackMode \"{}\"", n),
}
};
let constraint_solver_type = {
match m_constraintSolverType {
0 => ConstraintSolverType::None,
1 => ConstraintSolverType::Si,
2 => ConstraintSolverType::Pgs,
3 => ConstraintSolverType::Dantzig,
4 => ConstraintSolverType::Lemke,
5 => ConstraintSolverType::Nncg,
6 => ConstraintSolverType::BlockPgs,
n => panic!("Unexpected ConstraintSolverType \"{}\"", n),
}
};
PhysicsEngineParameters {
fixed_time_step: Duration::from_secs_f64(m_deltaTime),
simulation_time_stamp: Duration::from_secs_f64(m_simulationTimestamp),
num_solver_iterations: m_numSolverIterations as usize,
use_split_impulse: int_to_bool(m_useSplitImpulse),
split_impulse_penetration_threshold: m_splitImpulsePenetrationThreshold,
num_sub_steps: m_numSimulationSubSteps as usize,
collision_filter_mode: m_collisionFilterMode as usize,
contact_breaking_threshold: m_contactBreakingThreshold,
enable_file_caching: int_to_bool(m_enableFileCaching),
restitution_velocity_threshold: m_restitutionVelocityThreshold,
erp: m_defaultNonContactERP,
contact_erp: m_defaultContactERP,
friction_erp: m_frictionERP,
enable_cone_friction: int_to_bool(m_enableConeFriction),
deterministic_overlapping_pairs: int_to_bool(m_deterministicOverlappingPairs),
allowed_ccd_penetration: m_allowedCcdPenetration,
joint_feedback_mode,
solver_residual_threshold: m_solverResidualThreshold,
contact_slop: m_contactSlop,
enable_sat: int_to_bool(m_enableSAT),
constraint_solver_type,
global_cfm: m_defaultGlobalCFM,
minimum_solver_island_size: m_minimumSolverIslandSize as usize,
report_solver_analytics: int_to_bool(m_reportSolverAnalytics),
warm_starting_factor: m_warmStartingFactor,
sparse_sdf_voxel_size: m_sparseSdfVoxelSize,
num_non_contact_inner_iterations: m_numNonContactInnerIterations as usize,
use_real_time_simulation: int_to_bool(m_useRealTimeSimulation),
gravity: m_gravityAcceleration.into(),
articulated_warm_starting_factor: m_articulatedWarmStartingFactor,
internal_sim_flags: m_internalSimFlags,
friction_cfm: m_frictionCFM,
}
}
}
#[derive(Default, Debug)]
pub struct DebugVisualizerCameraInfo {
pub width: usize,
pub height: usize,
pub view_matrix: Matrix4<f32>,
pub projection_matrix: Matrix4<f32>,
pub camera_up: Vector3<f32>,
pub camera_forward: Vector3<f32>,
pub horizontal: Vector3<f32>,
pub vertical: Vector3<f32>,
pub yaw: f32,
pub pitch: f32,
pub dist: f32,
pub target: Vector3<f32>,
}
impl From<b3OpenGLVisualizerCameraInfo> for DebugVisualizerCameraInfo {
fn from(b3: b3OpenGLVisualizerCameraInfo) -> Self {
#[allow(non_snake_case)]
let b3OpenGLVisualizerCameraInfo {
m_width,
m_height,
m_viewMatrix,
m_projectionMatrix,
m_camUp,
m_camForward,
m_horizontal,
m_vertical,
m_yaw,
m_pitch,
m_dist,
m_target,
} = b3;
DebugVisualizerCameraInfo {
width: m_width as usize,
height: m_height as usize,
view_matrix: Matrix4::from_column_slice(&m_viewMatrix),
projection_matrix: Matrix4::from_column_slice(&m_projectionMatrix),
camera_up: m_camUp.into(),
camera_forward: m_camForward.into(),
horizontal: m_horizontal.into(),
vertical: m_vertical.into(),
yaw: m_yaw,
pitch: m_pitch,
dist: m_dist,
target: m_target.into(),
}
}
}
#[derive(Default, Debug)]
pub struct RayTestOptions {
pub report_hit_number: Option<usize>,
pub collision_filter_mask: Option<i32>,
}
#[derive(Default, Debug)]
pub struct RayTestBatchOptions {
pub parent_object_id: Option<BodyId>,
pub parent_link_index: Option<usize>,
pub num_threads: Option<usize>,
pub report_hit_number: Option<usize>,
pub fraction_epsilon: Option<f64>,
pub collision_filter_mask: Option<i32>,
}
#[derive(Debug, Copy, Clone)]
pub struct RayHitInfo {
pub body_id: BodyId,
pub link_index: Option<usize>,
pub hit_fraction: f64,
pub hit_position: Vector3<f64>,
pub hit_normal: Vector3<f64>,
}
impl RayHitInfo {
pub fn new(ray: b3RayHitInfo) -> Option<Self> {
let link_index = {
assert!(ray.m_hitObjectLinkIndex >= -1);
if ray.m_hitObjectLinkIndex == -1 {
None
} else {
Some(ray.m_hitObjectLinkIndex as usize)
}
};
if ray.m_hitObjectUniqueId < 0 {
None
} else {
Some(RayHitInfo {
body_id: BodyId(ray.m_hitObjectUniqueId),
link_index,
hit_fraction: ray.m_hitFraction,
hit_position: ray.m_hitPositionWorld.into(),
hit_normal: ray.m_hitNormalWorld.into(),
})
}
}
}
#[derive(Debug)]
pub struct SoftBodyOptions {
pub base_pose: Isometry3<f64>,
pub scale: Option<f64>,
pub mass: Option<f64>,
pub collision_margin: Option<f64>,
pub use_mass_spring: bool,
pub use_bending_springs: bool,
pub use_neo_hookean: bool,
pub spring_elastic_stiffness: f64,
pub spring_damping_stiffness: f64,
pub spring_damping_all_directions: bool,
pub spring_bending_stiffness: f64,
pub neo_hookean_mu: f64,
pub neo_hookean_lambda: f64,
pub neo_hookean_damping: f64,
pub friction_coeff: f64,
pub use_face_contact: bool,
pub use_self_collision: bool,
pub repulsion_stiffness: Option<f64>,
pub sim_filename: Option<PathBuf>,
}
impl Default for SoftBodyOptions {
fn default() -> Self {
SoftBodyOptions {
base_pose: Isometry3::identity(),
scale: None,
mass: None,
collision_margin: None,
use_mass_spring: false,
use_bending_springs: false,
use_neo_hookean: false,
spring_elastic_stiffness: 1.,
spring_damping_stiffness: 0.1,
spring_damping_all_directions: false,
spring_bending_stiffness: 0.1,
neo_hookean_mu: 1.,
neo_hookean_lambda: 1.,
neo_hookean_damping: 0.1,
friction_coeff: 0.,
use_face_contact: false,
use_self_collision: false,
repulsion_stiffness: None,
sim_filename: None,
}
}
}
bitflags::bitflags! {
pub struct ResetFlags : i32 {
const DEFORMABLE_WORLD = 1;
const DISCRETE_DYNAMICS_WORLD = 2;
const SIMPLE_BROADPHASE = 4;
}
}
bitflags::bitflags! {
pub struct VisualShapeFlags : i32 {
const TEXTURE_UNIQUE_IDS = 1;
const DOUBLE_SIDED = 4;
}
}
bitflags::bitflags! {
pub struct RendererAuxFlags : i32 {
const SEGMENTATION_MASK_OBJECT_AND_LINKINDEX = 1;
const USE_PROJECTIVE_TEXTURE = 2;
const NO_SEGMENTATION_MASK = 4;
}
}
#[derive(Debug)]
pub enum Renderer {
TinyRenderer = 1 << 16,
BulletHardwareOpenGl = 1 << 17,
}
#[derive(Debug, Default)]
pub struct CameraImageOptions {
pub view_matrix: Option<Matrix4<f32>>,
pub projection_matrix: Option<Matrix4<f32>>,
pub light_direction: Option<Vector3<f32>>,
pub light_color: Option<[f32; 3]>,
pub light_distance: Option<f32>,
pub shadow: Option<bool>,
pub light_ambient_coeff: Option<f32>,
pub light_diffuse_coeff: Option<f32>,
pub light_specular_coeff: Option<f32>,
pub renderer: Option<Renderer>,
pub flags: Option<RendererAuxFlags>,
pub projective_texture_view: Option<Matrix4<f32>>,
pub projective_texture_proj: Option<Matrix4<f32>>,
}