def _build_body(self, traversed, model, plugin, component, link=None, child_joints=None): """ :param traversed: Set of components that were already traversed, prevents loops (since all connections are two-sided). :type traversed: set :param model: :param plugin: :param component: :type component: Component :param link: :type link: Link :return: The primary link used in this traversal, i.e. the link passed to it or the first link created. """ if component in traversed: return link create_link = link is None traversed.add(component) if create_link: # New tree, create a link. The component name # should contain the body part ID so this name should # be unique. # The position of the link is determined later when we decide # its center of mass. link = Link("link_%s" % component.name, self_collide=True) child_joints = [] model.add_element(link) # Add this component to the link. position = link.to_local_frame(component.get_position()) rotation = link.to_local_direction(component.get_rotation()) component.set_position(position) component.set_rotation(rotation) link.add_element(component) # Add sensors registered on this component plugin.add_elements(component.get_plugin_sensors(link)) for conn in component.connections: if conn.joint: # Create the subtree after the joint other_link = self._build_body(traversed, model, plugin, conn.other) if other_link is None: # This connection was already created # from the other side. continue # Check whether this component is the parent or the child # of the joint connection (it is the parent by default) # This is relevant for another reason, because we will # be moving the internals of the current joint around # to center the inertia later on. This means that for # joints for which the current link is the child we need # to move the joint as well since the joint position is # expressed in the child frame. If the current link is # the parent there is no need to move it with this one, # and since `create_joint` is called after everything # within the child link has been fully neither does # the other link code. parent_link = link child_link = other_link is_child = conn.joint.parent is not component if is_child: parent_link, child_link = other_link, link joint = conn.joint.create_joint(parent_link, child_link, conn.joint.parent, conn.joint.child) model.add_element(joint) if is_child: child_joints.append(joint) else: # Just add this element to the current link self._build_body(traversed, model, plugin, conn.other, link, child_joints) if create_link: # Give the link the inertial properties of the combined collision, # only calculated by the item which created the link. # Note that we need to align the center of mass with the link's origin, # which will move the internal components around. In order to compensate # for this in the internal position we need to reposition the link according # to this change. translation = link.align_center_of_mass() link.translate(-translation) link.calculate_inertial() # Translate all the joints expressed in this link's frame that # were created before repositioning # Note that the joints need the same translation as the child elements # rather than the counter translation of the link. for joint in child_joints: joint.translate(translation) return link
m = Model(name="mybot") sdf = SDF(elements=[m]) geom = Box(SENSOR_BASE_THICKNESS, SENSOR_BASE_WIDTH, SENSOR_BASE_WIDTH, MASS) base = StructureCombination("base", geom) x_sensors = 0.5 * (SENSOR_BASE_THICKNESS + SENSOR_THICKNESS) y_left_sensor = -0.5 * SENSOR_WIDTH - SEPARATION y_right_sensor = 0.5 * SENSOR_WIDTH + SEPARATION left = StructureCombination("left", Box(SENSOR_THICKNESS, SENSOR_WIDTH, SENSOR_HEIGHT, MASS)) left.set_position(Vector3(x_sensors, y_left_sensor, 0)) right = StructureCombination("right", Box(SENSOR_THICKNESS, SENSOR_WIDTH, SENSOR_HEIGHT, MASS)) right.set_position(Vector3(x_sensors, y_right_sensor, 0)) link = Link("my_link") link.add_elements([base, left, right]) link.align_center_of_mass() link.calculate_inertial() m.add_element(link) apply_surface_parameters(m) m.translate(Vector3(0, 0, in_mm(30))) with open("/home/elte/.gazebo/models/test_bot/model.sdf", "w") as f: f.write(str(sdf))