calibrateDrag.py
Go to the documentation of this file.
1 #! /usr/bin/env python3
2 import rospy
3 import actionlib
4 import yaml
5 
6 import riptide_controllers.msg
7 from nav_msgs.msg import Odometry
8 from geometry_msgs.msg import Quaternion, Vector3, Twist
9 from dynamic_reconfigure.client import Client
10 
11 from tf.transformations import euler_from_quaternion, quaternion_from_euler
12 from math import pi
13 import numpy as np
14 
15 # Z axis is a little off, load interia from puddles.yaml, and update dynamic reconfigure
16 
17 
18 class CalibrateDragAction(object):
19 
20  _result = riptide_controllers.msg.CalibrateDragResult()
21 
22  def __init__(self):
23  self.orientation_pub = rospy.Publisher("orientation", Quaternion, queue_size=5)
24  self.position_pub = rospy.Publisher("position", Vector3, queue_size=5)
25  self.lin_vel_pub = rospy.Publisher("linear_velocity", Vector3, queue_size=5)
26  self.ang_vel_pub = rospy.Publisher("angular_velocity", Vector3, queue_size=5)
27 
28  # Get the mass and COM
29  with open(rospy.get_param('~vehicle_config'), 'r') as stream:
30  vehicle = yaml.safe_load(stream)
31  mass = vehicle['mass']
32  rotational_inertia = np.array(vehicle['inertia'])
33  self.inertia = np.array([mass, mass, mass, rotational_inertia[0], rotational_inertia[1], rotational_inertia[2]])
34 
35  self._as = actionlib.SimpleActionServer("calibrate_drag", riptide_controllers.msg.CalibrateDragAction, execute_cb=self.execute_cb, auto_start=False)
36  self._as.start()
37  self.client = Client("controller", timeout=30)
38 
39  # Example use: r, p, y = get_euler(odom)
40  # RPY in radians
41  def get_euler(self, odom_msg):
42  quat = odom_msg.pose.pose.orientation
43  quat = [quat.x, quat.y, quat.z, quat.w]
44  return euler_from_quaternion(quat)
45 
46  def restrict_angle(self, angle):
47  return ((angle + 180) % 360 ) - 180
48 
49  # Roll, Pitch, and Yaw configuration
50  def to_orientation(self, r, p, y):
51  r *= pi / 180
52  p *= pi / 180
53  y *= pi / 180
54  quat = quaternion_from_euler(r, p, y)
55  self.orientation_pub.publish(Quaternion(*quat))
56  rospy.sleep(5)
57 
58 
59  # Apply force on corresponding axes and record velocities
60  def collect_data(self, axis, velocity):
61  publish_velocity = [
62  lambda x: self.lin_vel_pub.publish(x, 0, 0),
63  lambda y: self.lin_vel_pub.publish(0, y, 0),
64  lambda z: self.lin_vel_pub.publish(0, 0, z),
65  lambda x: self.ang_vel_pub.publish(x, 0, 0),
66  lambda y: self.ang_vel_pub.publish(0, y, 0),
67  lambda z: self.ang_vel_pub.publish(0, 0, z)
68  ]
69 
70  get_twist = [
71  lambda odom: odom.twist.twist.linear.x,
72  lambda odom: odom.twist.twist.linear.y,
73  lambda odom: odom.twist.twist.linear.z,
74  lambda odom: odom.twist.twist.angular.x,
75  lambda odom: odom.twist.twist.angular.y,
76  lambda odom: odom.twist.twist.angular.z
77  ]
78 
79  get_accel = [
80  lambda twist: twist.linear.x,
81  lambda twist: twist.linear.y,
82  lambda twist: twist.linear.z,
83  lambda twist: twist.angular.x,
84  lambda twist: twist.angular.y,
85  lambda twist: twist.angular.z
86  ]
87 
88 
89  publish_velocity[axis](velocity)
90 
91  rospy.sleep(1)
92  last_vel = 0
93  stable_measurements = 0
94  while stable_measurements < 10:
95  odom_msg = rospy.wait_for_message("odometry/filtered", Odometry)
96  cur_vel = get_twist[axis](odom_msg)
97 
98  if abs((cur_vel - last_vel) / cur_vel) >= 0.1:
99  stable_measurements = 0
100  else:
101  stable_measurements += 1
102  last_vel = cur_vel
103  rospy.sleep(0.1)
104 
105  velocities = []
106  for _ in range (10):
107  odom_msg = rospy.wait_for_message("odometry/filtered", Odometry)
108  velocities.append(get_twist[axis](odom_msg))
109  rospy.sleep(0.1)
110 
111  forces = []
112  for _ in range (10):
113  accel_msg = rospy.wait_for_message("controller/requested_accel", Twist)
114  forces.append(get_accel[axis](accel_msg) * self.inertia[axis])
115  rospy.sleep(0.1)
116 
117  publish_velocity[axis](0)
118  rospy.sleep(0.1)
119 
120  return np.average(velocities), -np.average(forces)
121 
122  # Calcualte the multivariable linear regression of linear and quadratic damping
123  def calculate_parameters(self, velocities, forces):
124  y = np.array(forces)
125  X = np.array([velocities, np.abs(velocities) * np.array(velocities)])
126  X = X.T # transpose so input vectors are along the rows
127  return np.linalg.lstsq(X,y)[0]
128 
129  # Set depth in rqt before running action
130  def execute_cb(self, goal):
131  self.client.update_configuration({
132  "linear_x": 0,
133  "linear_y": 0,
134  "linear_z": 0,
135  "linear_rot_x": 0,
136  "linear_rot_y": 0,
137  "linear_rot_z": 0,
138  "quadratic_x": 0,
139  "quadratic_y": 0,
140  "quadratic_z": 0,
141  "quadratic_rot_x": 0,
142  "quadratic_rot_y": 0,
143  "quadratic_rot_z": 0
144  })
145 
146  # Initialize starting position of robot
147  odom_msg = rospy.wait_for_message("odometry/filtered", Odometry)
148  startYaw = self.get_euler(odom_msg)[2] * 180 / pi
149  startPosition = odom_msg.pose.pose.position
150  rospy.loginfo("Starting drag calibration")
151 
152  linear_params = np.zeros(6)
153  quadratic_params = np.zeros(6)
154 
155  # Euler for ease of use
156  axes_test_orientations = [
157  [0, 0, startYaw],
158  [0, 0, self.restrict_angle(startYaw - 90)],
159  [0, -85, startYaw],
160  [0, -85, startYaw],
161  [90, 0, startYaw],
162  [0, 0, startYaw]
163  ]
164 
165  axis_velocities = [
166  [0.05, -0.05, .1, -.1, .2, -.2],
167  [0.05, -0.05, .1, -.1, .2, -.2],
168  [-0.05, 0.05, -.1, .1, -.2, .2],
169  [0.2, -0.2, 0.5, -0.5, 1.2, -1.2],
170  [0.2, -0.2, 0.5, -0.5, 1.2, -1.2],
171  [0.2, -0.2, 0.5, -0.5, 1.2, -1.2],
172  ]
173 
174  for axis in range(6):
175  self.position_pub.publish(startPosition)
176  self.to_orientation(*axes_test_orientations[axis])
177 
178  forces = []
179  velocities = []
180  for requested_velocity in axis_velocities[axis]:
181  velocity, force = self.collect_data(axis, requested_velocity)
182  forces.append(force)
183  velocities.append(velocity)
184 
185  linear_params[axis], quadratic_params[axis] = self.calculate_parameters(velocities, forces)
186  rospy.loginfo("Linear: %f" % linear_params[axis])
187  rospy.loginfo("Quadratic: %f" % quadratic_params[axis])
188 
189  self.to_orientation(0, 0, startYaw)
190 
191  rospy.loginfo("Drag calibration completed.")
192 
193  self.client.update_configuration({
194  "linear_x": linear_params[0],
195  "linear_y": linear_params[1],
196  "linear_z": linear_params[2],
197  "linear_rot_x": linear_params[3],
198  "linear_rot_y": linear_params[4],
199  "linear_rot_z": linear_params[5],
200  "quadratic_x": quadratic_params[0],
201  "quadratic_y": quadratic_params[1],
202  "quadratic_z": quadratic_params[2],
203  "quadratic_rot_x": quadratic_params[3],
204  "quadratic_rot_y": quadratic_params[4],
205  "quadratic_rot_z": quadratic_params[5]
206  })
207 
208  self._result.linear_drag = linear_params
209  self._result.quadratic_drag = quadratic_params
210  self._as.set_succeeded(self._result)
211 
212 
213 if __name__ == '__main__':
214  rospy.init_node('calibrate_drag')
216  rospy.spin()
calibrateDrag.CalibrateDragAction.__init__
def __init__(self)
Definition: calibrateDrag.py:22
calibrateDrag.CalibrateDragAction.lin_vel_pub
lin_vel_pub
Definition: calibrateDrag.py:25
calibrateDrag.CalibrateDragAction
Definition: calibrateDrag.py:18
calibrateDrag.CalibrateDragAction.get_euler
def get_euler(self, odom_msg)
Definition: calibrateDrag.py:41
calibrateDrag.CalibrateDragAction.restrict_angle
def restrict_angle(self, angle)
Definition: calibrateDrag.py:46
calibrateDrag.CalibrateDragAction.to_orientation
def to_orientation(self, r, p, y)
Definition: calibrateDrag.py:50
calibrateDrag.CalibrateDragAction.orientation_pub
orientation_pub
Definition: calibrateDrag.py:23
calibrateDrag.CalibrateDragAction.calculate_parameters
def calculate_parameters(self, velocities, forces)
Definition: calibrateDrag.py:123
calibrateDrag.CalibrateDragAction.execute_cb
def execute_cb(self, goal)
Definition: calibrateDrag.py:130
calibrateDrag.CalibrateDragAction._result
_result
Definition: calibrateDrag.py:20
calibrateDrag.CalibrateDragAction.collect_data
def collect_data(self, axis, velocity)
Definition: calibrateDrag.py:60
calibrateDrag.CalibrateDragAction.ang_vel_pub
ang_vel_pub
Definition: calibrateDrag.py:26
calibrateDrag.CalibrateDragAction.inertia
inertia
Definition: calibrateDrag.py:33
actionlib::SimpleActionServer
calibrateDrag.CalibrateDragAction.client
client
Definition: calibrateDrag.py:37
calibrateDrag.CalibrateDragAction._as
_as
Definition: calibrateDrag.py:35
calibrateDrag.CalibrateDragAction.position_pub
position_pub
Definition: calibrateDrag.py:24


riptide_controllers
Author(s): Blaine Miller, Mitchell Sayre
autogenerated on Wed Mar 2 2022 00:50:23