2626from .utils .save_params import save_params
2727from .state .imu import ImuState
2828from .state .control import ControlState
29+ from .control .axis_controller import (
30+ AxisController ,
31+ AngularAxisController ,
32+ LinearAxisController ,
33+ )
2934
3035
3136class StingrayCoreControlNode (Node ):
@@ -117,9 +122,6 @@ def __init__(self):
117122 self .declare_parameter ('axes' , ["surge" , "sway" , "heave" , "roll" , "pitch" , "yaw" ])
118123 self .axes = list (self .get_parameter ('axes' ).get_parameter_value ().string_array_value )
119124
120- self .imu = ImuState ()
121- self .control = ControlState .from_axes (self .axes )
122-
123125 self .param_keys = ["K_p" , "K_1" , "K_2" , "K_i" , "I_min" , "I_max" , "out_sat" , "ap_K" , "ap_T" ]
124126
125127 # внутри ноды
@@ -141,6 +143,31 @@ def __init__(self):
141143
142144 self .get_logger ().info (f"Controllers initialized: { self .controllers } " )
143145
146+ self .imu = ImuState ()
147+ self .control = ControlState .from_axes (self .axes )
148+
149+ # --- Axis controllers (angular / linear split) ---
150+ self .axis_ctrl : dict [str , AxisController ] = {
151+ "yaw" : AngularAxisController (
152+ controller = self .controllers ["yaw" ],
153+ angle_fn = lambda : self .imu .yaw ,
154+ rate_fn = lambda : self .imu .rate_z ,
155+ feedback_flag_fn = lambda : self .flag_setup_feedback_speed ,
156+ ),
157+ "pitch" : AngularAxisController (
158+ controller = self .controllers ["pitch" ],
159+ angle_fn = lambda : self .imu .pitch ,
160+ rate_fn = lambda : self .imu .rate_y ,
161+ feedback_flag_fn = lambda : self .flag_setup_feedback_speed ,
162+ ),
163+ "heave" : LinearAxisController (
164+ controller = self .controllers ["heave" ],
165+ pos_fn = lambda : self .depth ,
166+ vel_fn = lambda : 0.0 , # пока нет оценки вертикальной скорости
167+ accel_fn = lambda : 0.0 ,
168+ feedback_flag_fn = lambda : self .flag_setup_feedback_speed ,
169+ ),
170+ }
144171
145172 qos = QoSProfile (depth = 10 )
146173
@@ -211,17 +238,21 @@ def control_loop(self):
211238 dt = now - self .last_time if self .last_time is not None else 0.0
212239 self .last_time = now
213240 self .last_dt = dt
214- # self.get_logger().info(f"self.flag_setup_feedback_speed={self.flag_setup_feedback_speed}")
241+
215242 # === 1. Определяем управляющие воздействия ===
216- u_surge = self .compute_surge () if self .control .enabled ["surge" ] else self .control .impact ["surge" ]
217- u_sway = self .compute_sway () if self .control .enabled ["sway" ] else self .control .impact ["sway" ]
218- u_heave = self .compute_heave () if self .control .enabled ["heave" ] else self .control .impact ["heave" ]
219- u_roll = self .compute_roll () if self .control .enabled ["roll" ] else self .control .impact ["roll" ]
220- u_pitch = self .compute_pitch () if self .control .enabled ["pitch" ] else self .control .impact ["pitch" ]
221- u_yaw = self .compute_yaw () if self .control .enabled ["yaw" ] else self .control .impact ["yaw" ]
243+ u : dict [str , float ] = {}
244+
245+ for axis in self .axes :
246+ if axis in self .axis_ctrl and self .control .enabled [axis ]:
247+ u [axis ] = self .axis_ctrl [axis ].compute (
248+ target = self .control .impact [axis ],
249+ dt = self .last_dt ,
250+ )
251+ else :
252+ u [axis ] = self .control .impact [axis ]
222253
223254 # === 2. Преобразуем в команды thrusters ===
224- control_list = [u_surge , u_sway , u_heave , u_roll , u_pitch , u_yaw ]
255+ control_list = [u [ "surge" ], u [ "sway" ], u [ "heave" ], u [ "roll" ], u [ "pitch" ], u [ "yaw" ] ]
225256 thruster_cmds = self .mixer .mix_from_list (control_list )
226257
227258 # === 3. Публикуем UInt8MultiArray ===
@@ -304,73 +335,6 @@ def control_mode_flags_callback(self, msg: UInt8):
304335 self .control .enabled ["pitch" ] = bool (flags & (1 << 4 ))
305336 self .control .enabled ["roll" ] = bool (flags & (1 << 5 ))
306337
307- # === Заглушки регуляторов ===
308- def compute_surge (self ):
309- return 0.0
310-
311- def compute_sway (self ):
312- return 0.0
313-
314- def compute_heave (self ):
315- dt = self .last_dt
316- return self .depth_ctrl .update (
317- self .control .impact ["heave" ],
318- self .depth ,
319- dt ,
320- self .flag_setup_feedback_speed ,
321- param_update = {
322- "K_p" : self .controllers ["heave" ].K_p ,
323- "K_i" : self .controllers ["heave" ].K_i ,
324- "K_1" : self .controllers ["heave" ].K_1 ,
325- "K_2" : self .controllers ["heave" ].K_2 ,
326- "ap_T" : self .controllers ["heave" ].ap_T ,
327- "ap_K" : self .controllers ["heave" ].ap_K ,
328- "out_sat" : self .controllers ["heave" ].out_sat ,
329- })
330-
331-
332- def compute_roll (self ):
333- return 0.0
334-
335-
336- def compute_pitch (self ):
337- dt = self .last_dt
338- return self .pitch_ctrl .update (
339- self .control .impact ["pitch" ],
340- self .imu .pitch ,
341- self .imu .rate_y ,
342- dt ,
343- self .flag_setup_feedback_speed ,
344- param_update = {
345- "K_p" : self .controllers ["pitch" ].K_p ,
346- "K_i" : self .controllers ["pitch" ].K_i ,
347- "K_1" : self .controllers ["pitch" ].K_1 ,
348- "K_2" : self .controllers ["pitch" ].K_2 ,
349- "ap_T" : self .controllers ["pitch" ].ap_T ,
350- "ap_K" : self .controllers ["pitch" ].ap_K ,
351- "out_sat" : self .controllers ["pitch" ].out_sat ,
352- })
353-
354- def compute_yaw (self ):
355- dt = self .last_dt
356- return self .yaw_ctrl .update (
357- self .control .impact ["yaw" ],
358- self .imu .yaw ,
359- self .imu .rate_z ,
360- dt ,
361- self .flag_setup_feedback_speed ,
362- param_update = {
363- "K_p" : self .controllers ["yaw" ].K_p ,
364- "K_i" : self .controllers ["yaw" ].K_i ,
365- "K_1" : self .controllers ["yaw" ].K_1 ,
366- "K_2" : self .controllers ["yaw" ].K_2 ,
367- "ap_T" : self .controllers ["yaw" ].ap_T ,
368- "ap_K" : self .controllers ["yaw" ].ap_K ,
369- "out_sat" : self .controllers ["yaw" ].out_sat ,
370- })
371-
372-
373-
374338 def _on_params_changed (self , params : list [Parameter ]) -> SetParametersResult :
375339 try :
376340 thruster_params : list [Parameter ] = []
0 commit comments