25 from optparse
import OptionParser
29 from tf.transformations
import euler_from_quaternion
30 from gazebo_msgs.srv
import GetModelState, GetModelStateRequest, GetModelStateResponse
31 from gazebo_msgs.srv
import SetModelState, SetModelStateRequest, SetModelStateResponse
32 from gazebo_msgs.msg
import ModelState
33 from geometry_msgs.msg
import Pose
35 _usage =
"""usage: %prog [options] 36 %prog: Moves a model in gazebo 39 Further help on options 46 self.
vel = float(self.options.velocity)
47 self.
name = self.options.name
48 rospy.init_node(
'move' + self.
name)
49 self.
models = self.options.stop_objects.split()
50 rospy.wait_for_service(
'/gazebo/get_model_state')
52 rospy.wait_for_service(
'/gazebo/set_model_state')
61 while not rospy.is_shutdown():
75 rospy.logerr(
"Not all models available yet")
76 rospy.loginfo(
"Ready to move object %s", self.
name)
79 req = GetModelStateRequest()
80 res = GetModelStateResponse()
81 req.model_name = model_name
84 except rospy.service.ServiceException:
89 model_dist = float(
'inf')
92 object_dist = math.sqrt(math.pow(res.pose.position.x-x,2) + math.pow(res.pose.position.y-y,2))
93 model_dist = min(object_dist, model_dist)
97 dx = goal[0] - start[0]
98 dy = goal[1] - start[1]
99 segment_length = math.sqrt(dx**2 + dy**2)
100 segment_time = segment_length/self.
vel 101 yaw = math.atan2(dy, dx)
105 if segment_step_count == 0:
107 segment_time = segment_length/self.
vel/segment_step_count
108 path = numpy.linspace(0, segment_length, segment_step_count)
111 last_time_in_motion = rospy.Time.now()
112 while idx < segment_step_count
and not rospy.is_shutdown():
115 step_x = start[0] + step * math.cos(yaw)
116 step_y = start[1] + step * math.sin(yaw)
120 if(model_dist <= float(self.options.stop_distance)):
121 rospy.logdebug(
"Model too close to object. Stopping!")
123 rospy.logdebug(
"Model move to last waypoint!")
127 object_new_pose = Pose()
128 object_new_pose.position.x = step_x
129 object_new_pose.position.y = step_y
130 quat = tf.transformations.quaternion_from_euler(0.0, 0.0, yaw)
131 object_new_pose.orientation.x = quat[0]
132 object_new_pose.orientation.y = quat[1]
133 object_new_pose.orientation.z = quat[2]
134 object_new_pose.orientation.w = quat[3]
137 model_state = ModelState()
138 model_state.model_name = self.
name 139 model_state.pose = object_new_pose
140 model_state.reference_frame =
'world' 143 self.pub_set_model_state.publish(model_state)
148 last_time_in_motion = rospy.Time.now()
154 object_new_pose = Pose()
155 object_new_pose.position.x = initialpose[0]
156 object_new_pose.position.y = initialpose[1]
157 object_new_pose.position.z = initialpose[2]
158 quat = tf.transformations.quaternion_from_euler(initialpose[3], initialpose[4], initialpose[5])
159 object_new_pose.orientation.x = quat[0]
160 object_new_pose.orientation.y = quat[1]
161 object_new_pose.orientation.z = quat[2]
162 object_new_pose.orientation.w = quat[3]
165 model_state = ModelState()
166 model_state.model_name = self.
name 167 model_state.pose = object_new_pose
168 model_state.reference_frame =
'world' 171 while not rospy.is_shutdown():
173 rospy.logdebug(
"desired model_state: {}".format(model_state))
174 rospy.logdebug(
"current model_state: {}".format(res))
175 if not numpy.any([res.twist.linear.x,res.twist.linear.y,res.twist.linear.z,res.twist.angular.x,res.twist.angular.y,res.twist.angular.z]):
176 rospy.logwarn(
"gazebo physics not yet started")
178 desired_pos = object_new_pose.position
179 current_pos = res.pose.position
180 desired_ori = euler_from_quaternion([object_new_pose.orientation.x,object_new_pose.orientation.y,object_new_pose.orientation.z,object_new_pose.orientation.w])
181 current_ori = euler_from_quaternion([res.pose.orientation.x,res.pose.orientation.y,res.pose.orientation.z,res.pose.orientation.w])
183 rospy.logdebug(numpy.isclose([desired_pos.x,desired_pos.y,desired_pos.z], [current_pos.x,current_pos.y,current_pos.z], atol=0.01))
184 rospy.logdebug(numpy.isclose(desired_ori, current_ori, atol=0.01))
185 if (numpy.allclose([desired_pos.x,desired_pos.y,desired_pos.z], [current_pos.x,current_pos.y,current_pos.z], atol=0.01)
and 186 numpy.allclose(desired_ori, current_ori, atol=0.01)):
187 rospy.loginfo(
"move_initialpose reached")
190 rospy.loginfo(
"publish initialpose")
191 self.pub_set_model_state.publish(model_state)
203 polygon = copy.deepcopy(polygon_in)
204 polygon.append(polygon_in[0])
205 while not rospy.is_shutdown():
206 if len(polygon) <= 1:
208 polygon = copy.deepcopy(polygon_in)
209 polygon.append(polygon_in[0])
225 last_time_in_motion = rospy.Time.now()
226 while not rospy.is_shutdown():
228 rospy.loginfo(
"starting new round")
231 step_x = center[0] + radius * math.sin(yaw)
232 step_y = center[1] + radius * math.cos(yaw)
236 if(model_dist <= float(self.options.stop_distance)):
237 rospy.logdebug(
"Model too close to object. Stopping!")
239 rospy.logdebug(
"Model move to start waypont of the polygone!")
243 object_new_pose = Pose()
244 object_new_pose.position.x = step_x
245 object_new_pose.position.y = step_y
246 quat = tf.transformations.quaternion_from_euler(0.0, 0.0, -yaw)
247 object_new_pose.orientation.x = quat[0]
248 object_new_pose.orientation.y = quat[1]
249 object_new_pose.orientation.z = quat[2]
250 object_new_pose.orientation.w = quat[3]
253 model_state = ModelState()
254 model_state.model_name = self.
name 255 model_state.pose = object_new_pose
256 model_state.reference_frame =
'world' 259 self.pub_set_model_state.publish(model_state)
264 last_time_in_motion = rospy.Time.now()
270 parser = OptionParser(usage=_usage, prog=os.path.basename(sys.argv[0]))
272 parser.add_option(
"-m",
"--mode",
273 dest=
"mode", choices=[
"initialpose",
"polygon",
"circle"], default=
None,
274 help=
"Mode to move model. Required.")
276 parser.add_option(
"-n",
"--name",
277 dest=
"name", metavar=
"STRING", default=
None,
278 help=
"Name of model to be moved. Required.")
280 parser.add_option(
"-i",
"--initialpose",
281 dest=
"initialpose", metavar=
"Initialpose [x, y, z, R, P, Y]", default=
None,
282 help=
"Cartesian Pose, only used for initialpose. Default: None")
284 parser.add_option(
"-v",
"--velocity",
285 dest=
"velocity", metavar=
"Float", default=0.5,
286 help=
"Velocity for movement in [m/s]. Default: 0.5")
288 parser.add_option(
"-p",
"--polygon",
289 dest=
"polygon", metavar=
"List of points [[x1,y1],[x2,y2], ...]", default=
None,
290 help=
"List of points forming a polygon in [m], only used for polygon movement. Default: None")
292 parser.add_option(
"-c",
"--center",
293 dest=
"center", metavar=
"Point [x1,y1]", default=
None,
294 help=
"Center point, only used for circular movement. Default: None")
296 parser.add_option(
"-r",
"--radius",
297 dest=
"radius", metavar=
"Float", default=
None,
298 help=
"Radius, only used for circular movement. Default: None")
300 parser.add_option(
"-o",
"--stop-objects",
301 dest=
"stop_objects", metavar=
"List of objects 'object_1 object_2 ...'", default=
'',
302 help=
"List of Model-Name of objects that are to be avoided. Default: ''")
304 parser.add_option(
"-d",
"--stop-distance",
305 dest=
"stop_distance", metavar=
"Float", default=2.0,
306 help=
"Allowed distance to objects before stopping. Default: 2.0")
308 (self.options, _) = parser.parse_args()
310 if self.options.mode ==
None:
311 parser.error(
"Please provide a valid mode, see -h option.")
312 if self.options.name ==
None:
313 parser.error(
"Please provide a valid model name, see -h option.")
317 if self.options.mode ==
"initialpose":
318 if (self.options.initialpose ==
None):
319 rospy.logerr(
"Please provide a valid initialpose, see -h option. initialpose = " + str(self.options.initialpose))
322 if self.options.mode ==
"polygon":
323 if (self.options.polygon ==
None)
or (type(eval(self.options.polygon))
is not list):
324 rospy.logerr(
"Please provide a valid polygon, see -h option. polygon = " + str(self.options.polygon))
327 if self.options.mode ==
"circle":
328 if self.options.radius ==
None:
329 rospy.logerr(
"Please provide a valid radius. radius = " + str(self.options.radius))
331 if self.options.center ==
None:
332 rospy.logerr(
"Please provide a valid center. center = " + str(self.options.center))
334 self.
move_circle(eval(self.options.center),float(self.options.radius))
337 if __name__ ==
"__main__":
341 except rospy.ROSInterruptException:
def get_model_state(self, model_name)
def move_on_line(self, start, goal)
def move_polygon(self, polygon_in)
def move_circle(self, center, radius)
def get_model_dist(self, x, y)
def move_initialpose(self, initialpose)