repose_collision/
robots.rs1use crate::model::CuCollisionModelParams;
4use crate::model::CuRobotCollisionModel;
5use crate::shapes::CuCollisionShape;
6use crate::shapes::CuLinkShape;
7use crate::shapes::capsule_m;
8use crate::shapes::sphere_m;
9use cu29::prelude::*;
10use cu29::units::si::f64::Length as Length64;
11use cu29::units::si::length::meter;
12use repose_kinematics::CuRobotPreset;
13use serde::Deserialize;
14use serde::Deserializer;
15use serde::Serialize;
16use serde::Serializer;
17
18fn igus_rebel_link_shapes() -> [CuLinkShape; 6] {
20 let capsule = |a, b, r| CuCollisionShape::Capsule(capsule_m(a, b, r));
21 let shapes = [
22 capsule([0.0, 0.0, -0.10], [0.0, 0.0, 0.04], 0.052),
24 capsule([0.0, 0.0, 0.02], [0.0, 0.0, 0.20], 0.045),
26 capsule([0.0, 0.0, 0.02], [0.0, 0.0, 0.12], 0.042),
28 capsule([0.0, 0.0, 0.02], [0.0, 0.0, 0.11], 0.038),
30 capsule([0.0, 0.0, 0.01], [0.0, 0.0, 0.05], 0.034),
32 CuCollisionShape::Sphere(sphere_m([0.0, 0.0, 0.02], 0.032)),
34 ];
35 let mut frame = 0;
36 shapes.map(|shape| {
37 frame += 1;
38 CuLinkShape::new(shape, Some(frame - 1))
39 })
40}
41
42fn igus_rebel_params() -> CuCollisionModelParams {
43 CuCollisionModelParams {
44 safety_margin: Length64::new::<meter>(0.005),
45 skip_adjacent_links: true,
46 }
47}
48
49pub fn igus_rebel_collision_model() -> CuRobotCollisionModel<6> {
55 CuRobotCollisionModel::assemble(&igus_rebel_link_shapes(), igus_rebel_params())
57}
58
59#[derive(Debug, Clone, Copy, PartialEq)]
76pub enum CuCollisionModelSpec<const M: usize> {
77 Preset(CuRobotPreset),
79 Inline {
81 shapes: [CuLinkShape; M],
83 params: CuCollisionModelParams,
85 },
86}
87
88impl<const M: usize> From<CuRobotPreset> for CuCollisionModelSpec<M> {
89 fn from(preset: CuRobotPreset) -> Self {
90 Self::Preset(preset)
91 }
92}
93
94impl<const M: usize> CuCollisionModelSpec<M> {
95 pub fn resolve<const N: usize>(&self) -> CuResult<CuRobotCollisionModel<N, M>> {
97 match self {
98 Self::Preset(CuRobotPreset::IgusRebel) => {
99 if N != CuRobotPreset::IgusRebel.dof() {
100 return Err(CuError::from(
101 "repose_collision: preset `igus_rebel` collision model needs N = 6",
102 ));
103 }
104 CuRobotCollisionModel::new(&igus_rebel_link_shapes(), igus_rebel_params())
105 }
106 Self::Inline { shapes, params } => CuRobotCollisionModel::new(shapes, *params),
107 }
108 }
109}
110
111#[derive(Serialize, Deserialize)]
112#[serde(deny_unknown_fields)]
113struct InlineModel<const M: usize> {
114 #[serde(with = "crate::serde_arrays::link_shape_array")]
115 shapes: [CuLinkShape; M],
116 #[serde(default = "default_safety_margin")]
117 safety_margin: Length64,
118 #[serde(default = "default_skip_adjacent_links")]
119 skip_adjacent_links: bool,
120}
121
122fn default_safety_margin() -> Length64 {
123 CuCollisionModelParams::default().safety_margin
124}
125
126fn default_skip_adjacent_links() -> bool {
127 CuCollisionModelParams::default().skip_adjacent_links
128}
129
130impl<const M: usize> Serialize for CuCollisionModelSpec<M> {
131 fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
132 match self {
133 Self::Preset(preset) => preset.serialize(serializer),
134 Self::Inline { shapes, params } => InlineModel {
135 shapes: *shapes,
136 safety_margin: params.safety_margin,
137 skip_adjacent_links: params.skip_adjacent_links,
138 }
139 .serialize(serializer),
140 }
141 }
142}
143
144impl<'de, const M: usize> Deserialize<'de> for CuCollisionModelSpec<M> {
145 fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
146 use serde::de::IntoDeserializer;
147 use serde::de::MapAccess;
148 use serde::de::Visitor;
149 use serde::de::value::MapAccessDeserializer;
150
151 struct SpecVisitor<const K: usize>;
152 impl<'de, const K: usize> Visitor<'de> for SpecVisitor<K> {
153 type Value = CuCollisionModelSpec<K>;
154 fn expecting(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
155 write!(
156 f,
157 "a robot preset name (\"igus_rebel\") or an inline collision model {{\"shapes\": [...]}}"
158 )
159 }
160 fn visit_str<E: serde::de::Error>(self, v: &str) -> Result<Self::Value, E> {
161 CuRobotPreset::deserialize(v.into_deserializer()).map(CuCollisionModelSpec::Preset)
162 }
163 fn visit_map<A: MapAccess<'de>>(self, map: A) -> Result<Self::Value, A::Error> {
164 let inline = InlineModel::<K>::deserialize(MapAccessDeserializer::new(map))?;
165 Ok(CuCollisionModelSpec::Inline {
166 shapes: inline.shapes,
167 params: CuCollisionModelParams {
168 safety_margin: inline.safety_margin,
169 skip_adjacent_links: inline.skip_adjacent_links,
170 },
171 })
172 }
173 }
174 deserializer.deserialize_any(SpecVisitor::<M>)
175 }
176}