4242VEHICLE_COMPONENT_ID = 1
4343MANUAL_CONTROL_EXTENSIONS_CODE = 0b00000011
4444
45+ SERVO_OUTPUT_PIN = 12
46+ SERVO_CENTER = 1500
47+ SERVO_MIN = 500
48+ SERVO_MAX = 2500
49+ SERVO_TURN_RATE = 500
50+ SERVO_PRESET_UP = 500
51+ SERVO_PRESET_DOWN = 1500
52+ # If True each button corresponds to a preset
53+ # If false one button moves gradually up and one moves gradually down
54+ SERVO_USE_PRESETS = False
4555
4656UNPRESSED = 0
4757PRESSED = 1
@@ -89,8 +99,8 @@ class ManipButton:
8999class ControllerProfile :
90100 manip_left : int = L1
91101 manip_right : int = R1
92- valve_clockwise : int = TRI_BUTTON
93- valve_counterclockwise : int = SQUARE_BUTTON
102+ servo_up : int = TRI_BUTTON
103+ servo_down : int = SQUARE_BUTTON
94104 roll_left : int = X_BUTTON # positive roll
95105 roll_right : int = O_BUTTON # negative roll
96106 arm_button : int = MENU
@@ -163,7 +173,9 @@ def __init__(self) -> None:
163173 VideoWidgetSwitch , 'switch_right_stream' , qos_profile_system_default
164174 )
165175
166- self .invert_controls = False
176+ self .back_cam_mode = False
177+
178+ self .servo_pwm = SERVO_PRESET_DOWN if SERVO_USE_PRESETS else SERVO_CENTER
167179
168180 # Unix timestamp of the last mavlink heartbeat from the pi
169181 self .last_pi_heartbeat : float = 0
@@ -217,8 +229,9 @@ def send_mavlink_control(self, joy_state: JoystickState) -> None:
217229 axes = joy_state .axes
218230 buttons = joy_state .buttons
219231
220- inv = - 1 if self .invert_controls else 1
232+ inv = - 1 if self .back_cam_mode else 1
221233
234+ # Control thrusters
222235 self .mavlink .mav .manual_control_send (
223236 self .mavlink .target_system ,
224237 int (- self .joystick_map (axes [self .profile .forward ]) * 1000 ) * inv ,
@@ -240,6 +253,33 @@ def send_mavlink_control(self, joy_state: JoystickState) -> None:
240253 int ((buttons [self .profile .roll_left ] - buttons [self .profile .roll_right ]) * 1000 ) * inv ,
241254 )
242255
256+ # Control servo
257+ if SERVO_USE_PRESETS :
258+ if buttons [self .profile .servo_up ]:
259+ self .servo_pwm = SERVO_PRESET_UP
260+ elif buttons [self .profile .servo_down ]:
261+ self .servo_pwm = SERVO_PRESET_DOWN
262+ else :
263+ self .servo_pwm += int (
264+ (buttons [self .profile .servo_down ] - buttons [self .profile .servo_up ])
265+ * SERVO_TURN_RATE
266+ / JOYSTICK_POLL_RATE
267+ )
268+ self .servo_pwm = max (min (self .servo_pwm , SERVO_MAX ), SERVO_MIN )
269+ self .mavlink .mav .command_long_send (
270+ self .mavlink .target_system ,
271+ self .mavlink .target_component ,
272+ mavutil .mavlink .MAV_CMD_DO_SET_SERVO ,
273+ 0 ,
274+ SERVO_OUTPUT_PIN ,
275+ self .servo_pwm ,
276+ 0 ,
277+ 0 ,
278+ 0 ,
279+ 0 ,
280+ 0 ,
281+ )
282+
243283 def manip_callback (self , joy_state : JoystickState ) -> None :
244284 """Process a joystick state and send a ros message to open or close a manipulator if
245285 required.
@@ -338,10 +378,10 @@ def process_camera_buttons(self, joy_state: JoystickState) -> None:
338378 # because DPADs are presented as axes not buttons and using any other axis is non-sensible
339379 if joy_state .buttons [self .profile .cam_front_button ]:
340380 self .right_stream_switch_publisher .publish (VideoWidgetSwitch (relative = False , index = 0 ))
341- self .invert_controls = False
381+ self .back_cam_mode = False
342382 elif joy_state .buttons [self .profile .cam_back_button ]:
343383 self .right_stream_switch_publisher .publish (VideoWidgetSwitch (relative = False , index = 1 ))
344- self .invert_controls = True
384+ self .back_cam_mode = True
345385
346386 def poll_mavlink (self ) -> None :
347387 """Check for incoming mavlink messages from the vehicle and send state updates if
0 commit comments