Added additional control abstractions to output.
This commit is contained in:
@@ -54,14 +54,17 @@ class SE3Control(object):
|
|||||||
self.kd_pos = np.array([4.0, 4.0, 9])
|
self.kd_pos = np.array([4.0, 4.0, 9])
|
||||||
self.kp_att = 544
|
self.kp_att = 544
|
||||||
self.kd_att = 46.64
|
self.kd_att = 46.64
|
||||||
|
self.kp_vel = 0.1*self.kp_pos # P gain for velocity controller (only used when the control abstraction is cmd_vel)
|
||||||
|
|
||||||
# Linear map from individual rotor forces to scalar thrust and vector
|
# Linear map from individual rotor forces to scalar thrust and vector
|
||||||
# moment applied to the vehicle.
|
# moment applied to the vehicle.
|
||||||
k = self.k_m/self.k_eta # Ratio of torque to thrust coefficient.
|
k = self.k_m/self.k_eta # Ratio of torque to thrust coefficient.
|
||||||
|
|
||||||
# Below is an automated generation of the control allocator matrix. It assumes that all thrust vectors are aligned
|
# Below is an automated generation of the control allocator matrix. It assumes that all thrust vectors are aligned
|
||||||
# with the z axis and that the "sign" of each rotor yaw moment alternates starting with positive for r1.
|
# with the z axis and that the "sign" of each rotor yaw moment alternates starting with positive for r1. 'TM' = "thrust and moments"
|
||||||
self.f_to_TM = np.vstack((np.ones((1,self.num_rotors)),np.hstack([np.cross(self.rotor_pos[key],np.array([0,0,1])).reshape(-1,1)[0:2] for key in self.rotor_pos]), (k * self.rotor_dir).reshape(1,-1)))
|
self.f_to_TM = np.vstack((np.ones((1,self.num_rotors)),
|
||||||
|
np.hstack([np.cross(self.rotor_pos[key],np.array([0,0,1])).reshape(-1,1)[0:2] for key in self.rotor_pos]),
|
||||||
|
(k * self.rotor_dir).reshape(1,-1)))
|
||||||
self.TM_to_f = np.linalg.inv(self.f_to_TM)
|
self.TM_to_f = np.linalg.inv(self.f_to_TM)
|
||||||
|
|
||||||
def update_ref(self, t, flat_output):
|
def update_ref(self, t, flat_output):
|
||||||
@@ -179,9 +182,12 @@ class SE3Control(object):
|
|||||||
Outputs:
|
Outputs:
|
||||||
control_input, a dict describing the present computed control inputs with keys
|
control_input, a dict describing the present computed control inputs with keys
|
||||||
cmd_motor_speeds, rad/s
|
cmd_motor_speeds, rad/s
|
||||||
|
cmd_motor_thrusts, N
|
||||||
cmd_thrust, N
|
cmd_thrust, N
|
||||||
cmd_moment, N*m
|
cmd_moment, N*m
|
||||||
cmd_q, quaternion [i,j,k,w]
|
cmd_q, quaternion [i,j,k,w]
|
||||||
|
cmd_w, angular rates in the body frame, rad/s
|
||||||
|
cmd_v, velocity in the world frame, m/s
|
||||||
"""
|
"""
|
||||||
cmd_motor_speeds = np.zeros((4,))
|
cmd_motor_speeds = np.zeros((4,))
|
||||||
cmd_thrust = 0
|
cmd_thrust = 0
|
||||||
@@ -196,7 +202,7 @@ class SE3Control(object):
|
|||||||
"""Return vector corresponding to given skew symmetric matrix."""
|
"""Return vector corresponding to given skew symmetric matrix."""
|
||||||
return np.array([-S[1,2], S[0,2], -S[0,1]])
|
return np.array([-S[1,2], S[0,2], -S[0,1]])
|
||||||
|
|
||||||
# Desired force vector.
|
# Get the desired force vector.
|
||||||
pos_err = state['x'] - flat_output['x']
|
pos_err = state['x'] - flat_output['x']
|
||||||
dpos_err = state['v'] - flat_output['x_dot']
|
dpos_err = state['v'] - flat_output['x_dot']
|
||||||
F_des = self.mass * (- self.kp_pos*pos_err
|
F_des = self.mass * (- self.kp_pos*pos_err
|
||||||
@@ -225,21 +231,29 @@ class SE3Control(object):
|
|||||||
w_des = np.array([0, 0, flat_output['yaw_dot']])
|
w_des = np.array([0, 0, flat_output['yaw_dot']])
|
||||||
w_err = state['w'] - w_des
|
w_err = state['w'] - w_des
|
||||||
|
|
||||||
# Angular control; vector units of N*m.
|
# Desired torque, in units N-m.
|
||||||
u2 = self.inertia @ (-self.kp_att*att_err - self.kd_att*w_err)
|
u2 = self.inertia @ (-self.kp_att*att_err - self.kd_att*w_err) + np.cross(state['w'], self.inertia@state['w']) # Includes compensation for wxJw component
|
||||||
|
|
||||||
|
# Compute command body rates by doing PD on the attitude error.
|
||||||
|
cmd_w = -self.kp_att*att_err - self.kd_att*w_err
|
||||||
|
|
||||||
# Compute motor speeds. Avoid taking square root of negative numbers.
|
# Compute motor speeds. Avoid taking square root of negative numbers.
|
||||||
TM = np.array([u1, u2[0], u2[1], u2[2]])
|
TM = np.array([u1, u2[0], u2[1], u2[2]])
|
||||||
cmd_motor_forces = self.TM_to_f @ TM
|
cmd_rotor_thrusts = self.TM_to_f @ TM
|
||||||
cmd_motor_speeds = cmd_motor_forces / self.k_eta
|
cmd_motor_speeds = cmd_rotor_thrusts / self.k_eta
|
||||||
cmd_motor_speeds = np.sign(cmd_motor_speeds) * np.sqrt(np.abs(cmd_motor_speeds))
|
cmd_motor_speeds = np.sign(cmd_motor_speeds) * np.sqrt(np.abs(cmd_motor_speeds))
|
||||||
|
|
||||||
cmd_thrust = u1
|
# Assign controller commands.
|
||||||
cmd_moment = u2
|
cmd_thrust = u1 # Commanded thrust, in units N.
|
||||||
cmd_q = Rotation.from_matrix(R_des).as_quat()
|
cmd_moment = u2 # Commanded moment, in units N-m.
|
||||||
|
cmd_q = Rotation.from_matrix(R_des).as_quat() # Commanded attitude as a quaternion.
|
||||||
|
cmd_v = -self.kp_vel*pos_err + flat_output['x_dot'] # Commanded velocity in world frame (if using cmd_vel control abstraction), in units m/s
|
||||||
|
|
||||||
control_input = {'cmd_motor_speeds':cmd_motor_speeds,
|
control_input = {'cmd_motor_speeds':cmd_motor_speeds,
|
||||||
|
'cmd_motor_thrusts':cmd_rotor_thrusts,
|
||||||
'cmd_thrust':cmd_thrust,
|
'cmd_thrust':cmd_thrust,
|
||||||
'cmd_moment':cmd_moment,
|
'cmd_moment':cmd_moment,
|
||||||
'cmd_q':cmd_q}
|
'cmd_q':cmd_q,
|
||||||
|
'cmd_w':cmd_w,
|
||||||
|
'cmd_v':cmd_v}
|
||||||
return control_input
|
return control_input
|
||||||
Reference in New Issue
Block a user