26 from nav_msgs.msg
import Odometry
27 from geometry_msgs.msg
import Quaternion, Vector3, Twist
28 from std_msgs.msg
import Empty, Bool
29 from tf.transformations
import quaternion_multiply, quaternion_inverse, quaternion_slerp
31 from abc
import ABC, abstractmethod
33 from dynamic_reconfigure.server
import Server
34 from riptide_controllers.cfg
import NewControllerConfig
36 import riptide_controllers.msg
40 return np.array([msg.x, msg.y, msg.z, msg.w])
41 return np.array([msg.x, msg.y, msg.z])
45 Rotates world-frame vector to body-frame
47 Rotates vector to body frame
50 orientation (np.array): The current orientation of the robot as a quaternion
51 vector (np.array): The 3D vector to rotate
54 np.array: 3 dimensional rotated vector
58 vector = np.append(vector, 0)
59 orientationInv = quaternion_inverse(orientation)
60 newVector = quaternion_multiply(orientationInv, quaternion_multiply(vector, orientation))
65 Scales a vector to obey maximums
68 vector (np.array): The unscaled vector
69 max_vector (np.array): The maximum values for each element
72 np.array: Vector that obeys the maximums
77 for i
in range(len(vector)):
78 if abs(vector[i]) > max_vector[i]:
79 element_scale = max_vector[i] / abs(vector[i])
80 if element_scale < scale:
103 Computes a corrective velocity.
105 If self.targetPosition is not None, will return a corrective body-frame velocity that moves the robot in the direction of self.targetPosiiton. Otherwise returns 0 vector.
108 odom (Odometry): The latest odometry message
111 np.array: 3 dimensional vector representing corrective body-frame velocity.
119 Computes a corrective acceleration.
121 If self.targetVelocity is not None, will return a corrective body-frame acceleration that transitions the robot twoards the desired self.targetVelocity. Otherwise returns 0 vector.
124 correctiveVelocity (np.array): Body-frame velocity vector that adds on to the self.targetVelocity. Is used in position correction.
125 odom (Odometry): The latest odometry message
128 np.array: 3 dimensional vector representing corrective body-frame acceleration.
137 Puts the controller in the Position state and sets self.targetPosition to targetPosition
140 targetPosition (np.array or Vector3): World-frame vector or quaternion to be achieved by the controller
144 self.targetPosition =
msgToNumpy(targetPosition)
147 self.targetVelocity = np.zeros(3)
148 self.targetAcceleration =
None
154 Puts the controller in the Velocity state and sets self.targetVelocity to targetVelocity
157 targetVelocity (np.array): Body-frame vector to be achieved by the controller
167 Disables the controller
169 Puts the controller in the Disabled state
179 Updates the controller
181 Will compute an output acceleration to achieve the desired state
184 odom (Odometry): The latest odometry message
187 np.array: 3 dimensional vector representing net body-frame acceleration.
191 netAccel = np.zeros(3)
216 super(LinearCascadedPController, self).
__init__()
223 currentPosition =
msgToNumpy(odom.pose.pose.position)
225 orientation =
msgToNumpy(odom.pose.pose.orientation)
235 currentVelocity =
msgToNumpy(odom.twist.twist.linear)
236 outputAccel = (targetVelocity - currentVelocity) * self.
velocityP
244 super(AngularCascadedPController, self).
__init__()
251 currentOrientation =
msgToNumpy(odom.pose.pose.orientation)
254 intermediateOrientation = quaternion_slerp(currentOrientation, self.
targetPosition, 0.01)
255 dq = (intermediateOrientation - currentOrientation)
256 outputVel = quaternion_multiply(quaternion_inverse(currentOrientation), dq)[:3] * self.
positionP
267 targetVelocity[i] = self.
maxVelocity[i] * targetVelocity[i] / abs(targetVelocity[i])
268 currentVelocity =
msgToNumpy(odom.twist.twist.angular)
269 outputAccel = (targetVelocity - currentVelocity) * self.
velocityP
276 self.
mass = np.array(config[
"mass"])
277 self.
com = np.array(config[
"com"])
289 Converts vehicle acceleration into required net force.
291 Will take the required acceleration and consider mass, buoyancy, drag, and precession to compute the required net force.
294 odom (Odometry): The latest odometry message.
295 linearAccel (np.array): The linear body-frame acceleration.
296 angularAccel (np.array): The angular body-frame acceleration.
299 np.array: 3 dimensional vector representing net body-frame force.
300 np.array: 3 dimensional vector representing net body-frame torque.
304 linearVelo =
msgToNumpy(odom.twist.twist.linear)
305 angularVelo =
msgToNumpy(odom.twist.twist.angular)
306 orientation =
msgToNumpy(odom.pose.pose.orientation)
309 netForce = linearAccel * self.
mass
310 netTorque = angularAccel * self.
inertia
314 buoyancyTorque = np.cross((self.
cob-self.
com), bodyFrameBuoyancy)
315 precessionTorque = -np.cross(angularVelo, (self.
inertia * angularVelo))
321 netForce = netForce - bodyFrameBuoyancy - dragForce - gravityForce
322 netTorque = netTorque - buoyancyTorque - precessionTorque - dragTorque
324 return netForce, netTorque
328 def __init__(self, linear_controller, angular_controller):
335 start = rospy.get_rostime()
337 for point
in goal.trajectory.points:
339 while (rospy.get_rostime() - start) < point.time_from_start:
340 if self.
_as.is_preempt_requested():
345 self.
_as.set_preempted()
357 last_point = goal.trajectory.points[-1]
361 self.
_as.set_succeeded()
366 config_path = rospy.get_param(
"~vehicle_config")
367 with open(config_path,
'r')
as stream:
368 config = yaml.safe_load(stream)
384 self.
forcePub = rospy.Publisher(
"net_force", Twist, queue_size=1)
385 self.
steadyPub = rospy.Publisher(
"steady", Bool, queue_size=1)
386 self.
accelPub = rospy.Publisher(
"~requested_accel", Twist, queue_size=1)
387 rospy.Subscriber(
"odometry/filtered", Odometry, self.
updateState)
388 rospy.Subscriber(
"orientation", Quaternion, self.
angularController.setTargetPosition)
389 rospy.Subscriber(
"angular_velocity", Vector3, self.
angularController.setTargetVelocity)
391 rospy.Subscriber(
"position", Vector3, self.
linearController.setTargetPosition)
392 rospy.Subscriber(
"linear_velocity", Vector3, self.
linearController.setTargetVelocity)
394 rospy.Subscriber(
"off", Empty, self.
turnOff)
395 rospy.Subscriber(
"state/kill_switch", Bool, self.
switch_cb)
403 "linear_position_p_x": config[
"linear_position_p"][0],
404 "linear_position_p_y": config[
"linear_position_p"][1],
405 "linear_position_p_z": config[
"linear_position_p"][2],
406 "linear_velocity_p_x": config[
"linear_velocity_p"][0],
407 "linear_velocity_p_y": config[
"linear_velocity_p"][1],
408 "linear_velocity_p_z": config[
"linear_velocity_p"][2],
409 "angular_position_p_x": config[
"angular_position_p"][0],
410 "angular_position_p_y": config[
"angular_position_p"][1],
411 "angular_position_p_z": config[
"angular_position_p"][2],
412 "angular_velocity_p_x": config[
"angular_velocity_p"][0],
413 "angular_velocity_p_y": config[
"angular_velocity_p"][1],
414 "angular_velocity_p_z": config[
"angular_velocity_p"][2],
415 "linear_x": config[
"linear_damping"][0],
416 "linear_y": config[
"linear_damping"][1],
417 "linear_z": config[
"linear_damping"][2],
418 "linear_rot_x": config[
"linear_damping"][3],
419 "linear_rot_y": config[
"linear_damping"][4],
420 "linear_rot_z": config[
"linear_damping"][5],
421 "quadratic_x": config[
"quadratic_damping"][0],
422 "quadratic_y": config[
"quadratic_damping"][1],
423 "quadratic_z": config[
"quadratic_damping"][2],
424 "quadratic_rot_x": config[
"quadratic_damping"][3],
425 "quadratic_rot_y": config[
"quadratic_damping"][4],
426 "quadratic_rot_z": config[
"quadratic_damping"][5],
427 "volume": config[
"volume"],
428 "center_x": config[
'cob'][0],
429 "center_y": config[
'cob'][1],
430 "center_z": config[
'cob'][2],
431 "max_linear_velocity_x": config[
"maximum_linear_velocity"][0],
432 "max_linear_velocity_y": config[
"maximum_linear_velocity"][1],
433 "max_linear_velocity_z": config[
"maximum_linear_velocity"][2],
434 "max_linear_accel_x": config[
"maximum_linear_acceleration"][0],
435 "max_linear_accel_y": config[
"maximum_linear_acceleration"][1],
436 "max_linear_accel_z": config[
"maximum_linear_acceleration"][2],
437 "max_angular_velocity_x": config[
"maximum_angular_velocity"][0],
438 "max_angular_velocity_y": config[
"maximum_angular_velocity"][1],
439 "max_angular_velocity_z": config[
"maximum_angular_velocity"][2],
440 "max_angular_accel_x": config[
"maximum_angular_acceleration"][0],
441 "max_angular_accel_y": config[
"maximum_angular_acceleration"][1],
442 "max_angular_accel_z": config[
"maximum_angular_acceleration"][2]
449 self.
accelPub.publish(Twist(Vector3(*linearAccel), Vector3(*angularAccel)))
451 if np.linalg.norm(linearAccel) > 0
or np.linalg.norm(angularAccel) > 0:
457 netForce, netTorque = np.zeros(3), np.zeros(3)
461 if not np.array_equal(self.
lastTorque, netTorque)
or \
462 not np.array_equal(self.
lastForce, netForce):
464 self.
forcePub.publish(Twist(Vector3(*netForce), Vector3(*netTorque)))
529 if __name__ ==
'__main__':
530 rospy.init_node(
"controller")