rov_nmb_sm_controller.py
Go to the documentation of this file.
1 #!/usr/bin/env python
2 # Copyright (c) 2016-2019 The UUV Simulator Authors.
3 # All rights reserved.
4 #
5 # Licensed under the Apache License, Version 2.0 (the "License");
6 # you may not use this file except in compliance with the License.
7 # You may obtain a copy of the License at
8 #
9 # http://www.apache.org/licenses/LICENSE-2.0
10 #
11 # Unless required by applicable law or agreed to in writing, software
12 # distributed under the License is distributed on an "AS IS" BASIS,
13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 # See the License for the specific language governing permissions and
15 # limitations under the License.
16 import rospy
17 import numpy as np
18 from uuv_control_interfaces import DPControllerBase
19 from uuv_control_msgs.srv import *
20 
21 
22 class ROV_NMB_SMController(DPControllerBase):
23  """
24  Model-free sliding mode controller based on the work published in [1] and
25  [2], or model-free high order sliding mode controller.
26 
27  [1] Garcia-Valdovinos, Luis Govinda, et al. "Modelling, design and robust
28  control of a remotely operated underwater vehicle." International
29  Journal of Advanced Robotic Systems 11.1 (2014): 1.
30  [2] Salgado-Jimenez, Tomas, Luis G. Garcia-Valdovinos, and Guillermo
31  Delgado-Ramirez. "Control of ROVs using a Model-free 2nd-Order Sliding
32  Mode Approach." Sliding Mode Control (2011): 347-368.
33  """
34 
35  _LABEL = 'Model-free Sliding Mode Controller'
36 
37  def __init__(self):
38  DPControllerBase.__init__(self, is_model_based=False)
39  self._logger.info('Initializing: ' + self._LABEL)
40  self._first_pass = True
41  self._t_init = 0.0
42  self._s_linear_b_init = np.array([0, 0, 0])
43  self._s_angular_b_init = np.array([0, 0, 0])
44 
45  # 'K' gains (help in the initial transient)
46  self._K = np.zeros(6)
47  # Derivative gains
48  self._Kd = np.zeros(6)
49  # Robustness gains
50  self._Ki = np.zeros(6)
51  # Overall proportional gains
52  self._slope = np.zeros(6)
53 
54  if rospy.has_param('~K'):
55  coefs = rospy.get_param('~K')
56  if len(coefs) == 6:
57  self._K = np.array(coefs)
58  else:
59  raise rospy.ROSException('K coefficients: 6 coefficients '
60  'needed')
61 
62  self._logger.info('K=' + str(self._K))
63 
64  if rospy.has_param('~Kd'):
65  coefs = rospy.get_param('~Kd')
66  if len(coefs) == 6:
67  self._Kd = np.array(coefs)
68  else:
69  raise rospy.ROSException('Kd coefficients: 6 coefficients '
70  'needed')
71 
72  self._logger.info('Kd=' + str(self._Kd))
73 
74  if rospy.has_param('~Ki'):
75  coefs = rospy.get_param('~Ki')
76  if len(coefs) == 6:
77  self._Ki = np.array(coefs)
78  else:
79  raise rospy.ROSException('Ki coeffcients: 6 coefficients '
80  'needed')
81  self._logger.info('Ki=' + str(self._Ki))
82 
83  if rospy.has_param('~slope'):
84  coefs = rospy.get_param('~slope')
85  if len(coefs) == 6:
86  self._slope = np.array(coefs)
87  else:
88  raise rospy.ROSException('Slope coefficients: 6 coefficients '
89  'needed')
90 
91  self._logger.info('slope=' + str(self._slope))
92 
93  self._sat_epsilon = 0.8
94  if rospy.has_param('~sat_epsilon'):
95  self._sat_epsilon = max(0.0, rospy.get_param('~sat_epsilon'))
96 
97  self._logger.info('Saturation limits=' + str(self._sat_epsilon))
98 
99  self._summ_sign_sn_linear_b = np.array([0, 0, 0])
100  self._summ_sign_sn_angular_b = np.array([0, 0, 0])
101 
102  self._prev_sign_sn_linear_b = np.array([0, 0, 0])
103  self._prev_sign_sn_angular_b = np.array([0, 0, 0])
104 
105  self._tau = np.zeros(6)
106 
107  self._services['set_sm_controller_params'] = rospy.Service(
108  'set_sm_controller_params',
109  SetSMControllerParams,
111  self._services['get_sm_controller_params'] = rospy.Service(
112  'get_sm_controller_params',
113  GetSMControllerParams,
115 
116  self._is_init = True
117  self._logger.info(self._LABEL + ' ready')
118 
119  def _reset_controller(self):
120  super(ROV_NMB_SMController, self)._reset_controller()
121  self._first_pass = True
122  self._t_init = 0.0
123  self._s_linear_b_init = np.array([0, 0, 0])
124  self._s_angular_b_init = np.array([0, 0, 0])
125  self._prev_t = rospy.get_time()
126  self._summ_sign_sn_linear_b = np.array([0, 0, 0])
127  self._summ_sign_sn_angular_b = np.array([0, 0, 0])
128  self._prev_sign_sn_linear_b = np.array([0, 0, 0])
129  self._prev_sign_sn_angular_b = np.array([0, 0, 0])
130  self._tau = np.zeros(6)
131 
133  return SetSMControllerParamsResponse(True)
134 
136  return GetSMControllerParamsResponse(
137  self._K.tolist(),
138  self._Kd.tolist(),
139  self._Ki.tolist(),
140  self._slope.tolist())
141 
142  def update_controller(self):
143  if not self._is_init:
144  return False
145  t = rospy.Time.now().to_sec()
146 
147  dt = t - self._prev_t
148  if self._prev_t < 0.0:
149  dt = 0.0
150 
151  # Get trajectory errors (reference - actual)
152  e_p_linear_b = self._errors['pos']
153  e_v_linear_b = self._errors['vel'][0:3]
154 
155  e_p_angular_b = self.error_orientation_rpy # check this
156  e_v_angular_b = self._errors['vel'][3:6]
157 
158  # Compute sliding surface s wrt body frame
159  s_linear_b = -e_v_linear_b - np.multiply(self._slope[0:3],
160  e_p_linear_b)
161  s_angular_b = -e_v_angular_b - np.multiply(self._slope[3:6],
162  e_p_angular_b)
163 
164  # Compute exponential decay for transient improvement
165  if self._first_pass == True:
166  self._t_init, self._s_linear_b_init, self._s_angular_b_init = t, s_linear_b, s_angular_b
167  self._first_pass = False
168 
169  sd_linear_b = np.multiply(self._s_linear_b_init,
170  np.exp(-self._K[0:3] * (t - self._t_init)))
171  sd_angular_b = np.multiply(self._s_angular_b_init,
172  np.exp(-self._K[3:6] * (t - self._t_init)))
173 
174  # Compute sliding surface sn wrt body frame
175  sn_linear_b = s_linear_b - sd_linear_b
176  sn_angular_b = s_angular_b - sd_angular_b
177 
178  # Compute summation sign(sn) wrt body frame
179  if self._prev_t > 0.0 and dt > 0.0:
180  self._summ_sign_sn_linear_b = self._summ_sign_sn_linear_b + 0.5 * (
181  self.sat(sn_linear_b, self._sat_epsilon) + self._prev_sign_sn_linear_b) * dt
183  self.sat(sn_angular_b, self._sat_epsilon) + self._prev_sign_sn_angular_b) * dt
184 
185  # Compute extended error wrt body frame
186  sr_linear_b = sn_linear_b + np.multiply(self._Ki[0:3],
188  sr_angular_b = sn_angular_b + np.multiply(self._Ki[3:6],
190 
191  # Compute required forces and torques wrt body frame
192  force_b = -np.multiply(self._Kd[0:3], sr_linear_b)
193  torque_b = -np.multiply(self._Kd[3:6], sr_angular_b)
194 
195  self._tau = np.hstack((force_b, torque_b))
196 
197  self.publish_control_wrench(self._tau)
198 
199  self._prev_sign_sn_linear_b = self.sat(sn_linear_b, self._sat_epsilon)
200  self._prev_sign_sn_angular_b = self.sat(sn_angular_b, self._sat_epsilon)
201  self._prev_t = t
202 
203  @staticmethod
204  def sat(value, epsilon=0.5):
205  assert epsilon >= 0, 'Saturation constant must be greate or equal to zero'
206  if epsilon == 0:
207  return np.sign(value)
208 
209  vec = value / epsilon
210  output = np.zeros(vec.size)
211  for i in range(output.size):
212  if vec[i] > epsilon:
213  output[i] = 1
214  elif vec[i] < -epsilon:
215  output[i] = -1
216  else:
217  output[i] = vec[i]
218  return output
219 
220 if __name__ == '__main__':
221  print('Starting Non-model-based Sliding Mode Controller')
222  rospy.init_node('rov_nmb_sm_controller')
223 
224  try:
226  rospy.spin()
227  except rospy.ROSInterruptException:
228  print('caught exception')
229  print('exiting')


uuv_trajectory_control
Author(s):
autogenerated on Thu Jun 18 2020 03:28:42