183 lines
5.7 KiB
Plaintext
183 lines
5.7 KiB
Plaintext
<?xml version="1.0" ?>
|
|
<%= "<!-- this file was generated using embedded ruby -->" %>
|
|
<sdf version='1.6'>
|
|
<world name='default'>
|
|
<gui>
|
|
<camera name='user_camera'>
|
|
<pose>17 3 22 0 1.1 <%= Math::PI %></pose>
|
|
<view_controller>orbit</view_controller>
|
|
</camera>
|
|
</gui>
|
|
<include>
|
|
<uri>model://sun</uri>
|
|
</include>
|
|
<include>
|
|
<uri>model://ground_plane</uri>
|
|
</include>
|
|
<gravity>0 2 -9.81</gravity>
|
|
<%
|
|
# World with several models with varying number of collision spheres
|
|
# SI units (length in meters)
|
|
require "matrix"
|
|
def a_to_s(v)
|
|
Array(v).join(" ")
|
|
end
|
|
|
|
# Geometry
|
|
ball_radius = 0.2
|
|
face_altitude = 0.5
|
|
side_length = face_altitude / (Math::sqrt(3) / 2.0)
|
|
ball_volume = 4.0 / 3.0 * Math::PI * ball_radius**3
|
|
def sphere_collision(name_suffix, pos, radius, color="Green", slip=1, friction=0.5)
|
|
"""<collision name='collision_#{name_suffix}'>
|
|
<pose>#{ a_to_s(pos) } 0 0 0</pose>
|
|
<geometry>
|
|
<sphere>
|
|
<radius>#{ radius }</radius>
|
|
</sphere>
|
|
</geometry>
|
|
<surface>
|
|
<friction>
|
|
<ode>
|
|
<mu>#{ friction }</mu>
|
|
<mu2>#{ friction }</mu2>
|
|
<slip1>#{ slip }</slip1>
|
|
<slip2>#{ slip }</slip2>
|
|
</ode>
|
|
</friction>
|
|
</surface>
|
|
</collision>
|
|
<visual name='visual_#{ name_suffix }'>
|
|
<pose>#{ a_to_s(pos) } 0 0 0</pose>
|
|
<geometry>
|
|
<sphere>
|
|
<radius>#{ radius }</radius>
|
|
</sphere>
|
|
</geometry>
|
|
<material>
|
|
<script>
|
|
<uri>file://media/materials/scripts/gazebo.material</uri>
|
|
<name>Gazebo/#{ color }</name>
|
|
</script>
|
|
</material>
|
|
</visual>"""
|
|
end
|
|
|
|
models = {}
|
|
# "lowball" has one collision sphere with a hanging center of mass,
|
|
# which makes the ball slide instead of roll
|
|
models["lowball"] = {
|
|
:inertia_offset => Vector[0, 0, -0.3],
|
|
:ball_locations => {
|
|
"a" => Vector[0, 0, 0] ,
|
|
}
|
|
}
|
|
# "twoball" has two collision spheres
|
|
# it will slide in one direction and roll in the other direction
|
|
models["twoball"] = {
|
|
:ball_locations => {
|
|
"a" => Vector[0, side_length / 2.0, 0] ,
|
|
"b" => Vector[0, -side_length / 2.0, 0] ,
|
|
}
|
|
}
|
|
# "triball" has three collision spheres arranged in an equilateral triangle
|
|
# it will slide in any direction
|
|
models["triball"] = {
|
|
:ball_locations => {
|
|
"a" => Vector[ 2.0 / 3.0 * face_altitude, 0, 0] ,
|
|
"b" => Vector[-1.0 / 3.0 * face_altitude, side_length / 2.0, 0] ,
|
|
"c" => Vector[-1.0 / 3.0 * face_altitude, -side_length / 2.0, 0] ,
|
|
}
|
|
}
|
|
|
|
# there are several pairs of test cases
|
|
# each pair has the same product of mass and slip,
|
|
mass_slip = {}
|
|
mass_slip["0.2a"] = { :mass => 1.0, :slip => 0.2, :color => "Red"}
|
|
mass_slip["0.2b"] = { :mass => 2.0, :slip => 0.1, :color => "Red"}
|
|
mass_slip["0.4a"] = { :mass => 2.0, :slip => 0.2, :color => "Green"}
|
|
mass_slip["0.4b"] = { :mass => 4.0, :slip => 0.1, :color => "Green"}
|
|
mass_slip["0.6a"] = { :mass => 3.0, :slip => 0.2, :color => "Blue"}
|
|
mass_slip["0.6b"] = { :mass => 6.0, :slip => 0.1, :color => "Blue"}
|
|
|
|
models.keys.each_with_index do |model_prefix, i|
|
|
model = models[model_prefix]
|
|
ball_locations = model[:ball_locations]
|
|
ball_count = ball_locations.length
|
|
inertia_offset = model[:inertia_offset]
|
|
inertia_offset = model.key?(:inertia_offset) ? model[:inertia_offset] : Vector[0, 0, 0]
|
|
|
|
mass_slip.keys.each_with_index do |ms_name, ii|
|
|
ms = mass_slip[ms_name]
|
|
mass = ms[:mass]
|
|
slip = ms[:slip]
|
|
color = ms[:color]
|
|
|
|
# inertia
|
|
link_mass = mass
|
|
ball_mass = link_mass * 1.0/ball_count
|
|
ball_ixx = 2.0/5.0 * ball_mass * ball_radius**2
|
|
ball_iyy = 2.0/5.0 * ball_mass * ball_radius**2
|
|
ball_izz = 2.0/5.0 * ball_mass * ball_radius**2
|
|
|
|
# center of mass (com) and lumped inertia of balls
|
|
ball_com = Vector[0, 0, 0]
|
|
ball_locations.keys.each do |k|
|
|
ball_com += ball_locations[k] / ball_count
|
|
end
|
|
link_ixx = ball_count * ball_ixx
|
|
link_iyy = ball_count * ball_iyy
|
|
link_izz = ball_count * ball_izz
|
|
link_ixy = 0.0
|
|
link_ixz = 0.0
|
|
link_iyz = 0.0
|
|
ball_locations.keys.each do |k|
|
|
dx = ball_locations[k][0] - ball_com[0]
|
|
dy = ball_locations[k][1] - ball_com[1]
|
|
dz = ball_locations[k][2] - ball_com[2]
|
|
link_ixx += ball_mass * (dy**2 + dz**2)
|
|
link_iyy += ball_mass * (dz**2 + dx**2)
|
|
link_izz += ball_mass * (dx**2 + dy**2)
|
|
link_ixy -= ball_mass * dx*dy
|
|
link_ixz -= ball_mass * dx*dz
|
|
link_iyz -= ball_mass * dy*dz
|
|
end
|
|
|
|
model_name = "#{model_prefix}_#{ms_name}"
|
|
model_pose = Vector[2*ii, -2*i, 0, 0, 0, 0]
|
|
%>
|
|
<model name="<%= model_name %>">
|
|
<pose><%= a_to_s(model_pose) %></pose>
|
|
<link name="link">
|
|
<pose>0 0 <%= ball_radius %> 0 0 0</pose>
|
|
<inertial>
|
|
<pose><%= a_to_s(ball_com + inertia_offset) %> 0 0 0</pose>
|
|
<mass><%= link_mass %></mass>
|
|
<inertia>
|
|
<ixx><%= link_ixx %></ixx>
|
|
<iyy><%= link_iyy %></iyy>
|
|
<izz><%= link_izz %></izz>
|
|
<ixy><%= link_ixy %></ixy>
|
|
<ixz><%= link_ixz %></ixz>
|
|
<iyz><%= link_iyz %></iyz>
|
|
</inertia>
|
|
</inertial>
|
|
<%
|
|
# Place sphere collision and visual at each corner
|
|
ball_locations.keys.each_index do |first|
|
|
key = ball_locations.keys[first]
|
|
pos = ball_locations[key]
|
|
%>
|
|
<%= sphere_collision(key, pos, ball_radius, color, slip) %>
|
|
<%
|
|
end
|
|
%>
|
|
</link>
|
|
</model>
|
|
<%
|
|
end
|
|
end
|
|
%>
|
|
</world>
|
|
</sdf>
|