revel_cartesian_controller.py
Go to the documentation of this file.
1 # Software License Agreement (BSD License)
2 #
3 # Copyright (c) 2017 Svenzva Robotics
4 # All rights reserved.
5 #
6 # Redistribution and use in source and binary forms, with or without
7 # modification, are permitted provided that the following conditions
8 # are met:
9 #
10 # * Redistributions of source code must retain the above copyright
11 # notice, this list of conditions and the following disclaimer.
12 # * Redistributions in binary form must reproduce the above
13 # copyright notice, this list of conditions and the following
14 # disclaimer in the documentation and/or other materials provided
15 # with the distribution.
16 # * Neither the name of Svenzva Robotics LLC nor the names of its
17 # contributors may be used to endorse or promote products derived
18 # from this software without specific prior written permission.
19 #
20 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 # COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30 # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 # POSSIBILITY OF SUCH DAMAGE.
32 
33 """
34 
35 RevelCartesianController is a ROS component that allows cartesian velocity control of the Revel robot.
36 This component is run as part a module of the robot driver, giving it explicit USB / Serial access for
37 greater performance.
38 
39 This method of robot controls require the robot motors to be in velocity control mode.
40 This class expects a 6DOF robot, and is thus untested for custom robot builds. Significant modification
41 to the robot will violate the kinematic model present in the SvenzvaKinematics class.
42 In this event, a generic (or generated) kinematic solver should be used in place of SvenzvaKinematics.
43 
44 Author Maxwell Svetlik
45 Copyright Svenzva Robotics
46 
47 """
48 import rospy
49 import rospkg
50 import math
51 import sys
52 import numpy
53 
54 from pykdl_utils.kdl_parser import kdl_tree_from_urdf_model
55 from urdf_parser_py.urdf import Robot
56 from sensor_msgs.msg import JointState
57 from geometry_msgs.msg import Twist
58 from moveit_msgs.srv import GetStateValidity
60 
61 import moveit_commander
62 import moveit_msgs.msg
63 import geometry_msgs.msg
64 import tf
65 
66 
68 
69  def __init__(self, controller_namespace, mx_io):
70  rospy.Subscriber("/revel/eef_velocity", Twist, self.cart_vel_cb, queue_size=1);
71  rospy.Subscriber("joint_states", JointState, self.js_cb, queue_size=1);
72  rospack = rospkg.RosPack()
73  path = rospack.get_path("svenzva_description");
74  full_path = path + "/robots/svenzva_arm.urdf";
75 
76  f = file(full_path, 'r')
77  self.robot = Robot.from_xml_string(f.read())
78  f.close()
79 
80  self.mx_io = mx_io
81  self.mNumJnts = 6
82  self.gear_ratios = [4,7,7,3,4,1]
83  self.js = JointState()
84  self.js_last = JointState()
85  self.min_limit = 20.0
86  self.max_limit = 100.0
87  self.last_twist = Twist()
88  self.last_cmd = []
89  self.last_cmd_zero = False
90 
91  #Load Svenzva kinematic solver
93  self.ee_velocity = numpy.zeros(6)
94 
95  self.cart_vel = Twist()
96  self.arm_speed_limit = rospy.get_param('arm_speed_limit', 20.0)
97  self.collision_check_enabled = rospy.get_param('collision_check_enabled', False)
98 
100  rospy.loginfo("MoveIt collision check for cartesian movements ENABLED. Using environment information.")
101  try:
102  rospy.wait_for_service('/check_state_validity')
103  self.state_validity_srv = rospy.ServiceProxy('/check_state_validity', GetStateValidity)
104  except rospy.ServiceException as exc:
105  rospy.loginfo("MoveIt not. Cartesian Velocity controller will not use collision checking.")
106  rospy.logerr("Cartesian collision checking DISABLED")
107  self.collision_check_enabled = False
108  else:
109  rospy.loginfo("MoveIt collision check for cartesian movements DISabled. Not using environment information.")
110  self.group = None
111 
112 
113  def js_cb(self, msg):
114  self.js = msg;
115 
116  def rad_to_raw(self, angle):
117  return int(round( angle * 4096.0 / 6.2831853) )
118 
119  def radpm_to_rpm(self, rad_per_min):
120  return rad_per_min * 0.159155
121 
122  def cart_vel_cb(self, msg):
123  self.cart_vel = msg
124 
125  """
126  Uses MoveIt to check if movement would cause collision with scene or self
127  Returns true if movement causes collision
128  false if movement does not cause collision
129  """
130  def check_if_collision(self, qdot_out, scale_factor, dt):
131  rs = moveit_msgs.msg.RobotState()
132 
133  for i in range(0, self.mNumJnts):
134  rs.joint_state.name.append(self.js.name[i])
135  rs.joint_state.position.append(self.js.position[i] + (qdot_out[i]/scale_factor*dt))
136 
137  result = self.state_validity_srv(rs, "svenzva_arm", moveit_msgs.msg.Constraints() )
138  if not result.valid:
139  return True
140  return False
141 
142  def send_zero_vel(self):
143  tup_list = []
144  for i in range(0, self.mNumJnts):
145  tup_list.append( (i+1, 0))
146  self.mx_io.set_multi_speed(tuple(tup_list))
147 
148  def send_last_vel(self):
149  self.mx_io.set_multi_speed(tuple(self.last_cmd))
150 
151  def loop(self):
152  rospy.sleep(1.0)
153  count = 0
154  time_step = 0.025
155  z_sign = 1
156  x_sign = 1
157  self.js_last = self.js
158  while not rospy.is_shutdown():
159  msg = self.cart_vel
160 
161  #continues loop while no velocity messages are incoming
162  if self.cart_vel == Twist():
163  if self.last_cmd_zero:
164  rospy.sleep(0.1)
165  continue
166  self.send_zero_vel()
167  self.last_cmd_zero = True
168  rospy.sleep(0.1)
169  continue
170 
171  joint_positions = numpy.empty(0)
172  for i in range(0, self.mNumJnts):
173  joint_positions = numpy.append(joint_positions, self.js.position[i])
174 
175  lim = 0.0
176  offset = 0.01
177  sleep_next = False
178  self.ee_velocity[0] = msg.linear.x
179  self.ee_velocity[1] = msg.linear.y
180  self.ee_velocity[2] = z_sign * msg.linear.z
181  self.ee_velocity[3] = x_sign * msg.angular.x
182  self.ee_velocity[4] = z_sign * msg.angular.y
183  self.ee_velocity[5] = 0 #msg.angular.z
184 
185 
186  qdot_out = self.jacobian_solver.get_joint_vel(joint_positions, self.ee_velocity)
187 
188 
189  #Singularity handling
190  #wrist_det = self.jacobian_solver.get_jacobian_wrist_det()
191  shoulder_det = self.jacobian_solver.get_jacobian_det()
192  heuristic = 0
193 
194  # This heuristic reduces amplitude of oscillation around singularities
195  # This makes joystick execution smoother, but might cause issues for arbitrary EE velocity in other cases
196  if heuristic == 1:
197  if abs(shoulder_det) < 0.0001 and len(self.last_cmd) > 0 and numpy.linalg.norm(self.last_cmd) != 0:
198  self.send_last_vel()
199  rospy.sleep(0.5)
200  continue
201 
202 
203 
204  if abs(msg.angular.z) > 0:
205  qdot_out[5] = msg.angular.z
206 
207  if not isinstance(qdot_out, numpy.ndarray) and qdot_out == SvenzvaKinematics.ERROR_SINGULAR:
208  rospy.loginfo("Jacobian could not be inverted because it is singular.")
209  continue
210 
211  tup_list = []
212  vals = []
213 
214  scale_factor = 1
215 
216  #check if overall arm velocity violates the ARM_SPEED_LIMIT
217  #Note that the ARM_SPEED_LIMIT caps the arm output, where other speed parameters,
218  #such as linear_scale and angular_scale in JOY nodes, caps the Twist input to this node.
219  acc = 0.0
220  for i in range(0, self.mNumJnts):
221  acc += math.pow(qdot_out[i], 2)
222 
223 
224  vel_scale = math.sqrt(acc) / self.arm_speed_limit
225  if vel_scale > 1.0:
226  scale_factor = vel_scale
227 
228  if scale_factor != 1:
229  rospy.logdebug("Scaling cartesian velocity: scaling all velocity by %f", 1/scale_factor)
230 
231 
232  #check if movement causes collision, if enabled
233 
234  if self.collision_check_enabled and not self.cart_vel == Twist():
235  in_collision = self.check_if_collision(qdot_out, scale_factor, 0.0075)
236  if in_collision:
237  rospy.loginfo("Movement would cause collision with environment.")
238  for i in range(0, self.mNumJnts):
239  tup_list.append( (i+1, 0))
240  self.last_cmd = tup_list
241  self.last_qdot = qdot_out
242  self.mx_io.set_multi_speed(tuple(tup_list))
243  rospy.sleep(0.05)
244  continue
245 
246  for i in range(0, self.mNumJnts):
247  #check if movement violates urdf joint limits
248  if self.robot.joints[i+1].limit.lower >= self.js.position[i] + (qdot_out[i]/scale_factor*0.01) or self.js.position[i] + (qdot_out[i]/scale_factor*0.01) >= self.robot.joints[i+1].limit.upper:
249  rospy.logwarn("Cartesian movement would cause movement outside of joint limits. Skipping...")
250  rospy.logwarn("Movement would violate joint limit: Joint %d moving to %f with limits [%f,%f]", i+1, (qdot_out[i]/scale_factor) + self.js.position[i], self.robot.joints[i+1].limit.lower, self.robot.joints[i+1].limit.upper)
251  tup_list.append( (i+1, 0))
252  else:
253  tup_list.append( (i+1, int(round(self.radpm_to_rpm(qdot_out[i] * self.gear_ratios[i] / scale_factor) / 0.229 ))))
254 
255 
256  if len(tup_list) > 0:
257  self.js_last = self.js
258  self.last_cmd = tup_list
259  self.last_qdot = qdot_out
260  self.mx_io.set_multi_speed(tuple(tup_list))
261  self.last_cmd_zero = False
262  if sleep_next:
263  rospy.sleep(0.5)
264  rospy.sleep(time_step)
265 
266  #alignment singularity detection
267  tup_list = []
268  if self.js.position[4] > lim - 0.03 and self.js.position[4] < lim + 0.03:
269  x_sign *= -1
270  self.send_last_vel()
271  rospy.sleep(0.25)
272  self.send_zero_vel()
273 
274  #alignment singularity detection for J2 & J3
275  if self.js.position[2] > lim - 0.03 and self.js.position[2] < lim + 0.03:
276  z_sign *= -1
277  self.send_last_vel()
278  rospy.sleep(0.25)
279  self.send_zero_vel()
280 
281  rospy.sleep(time_step)
282 


svenzva_drivers
Author(s): Max Svetlik
autogenerated on Wed Oct 28 2020 03:31:27