Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
83a9841
preliminary implementation, no testing done
alberto-escobar Sep 17, 2024
c29c03c
Simulator dimension mismatches & fluid generation config (#435)
eomielan Sep 23, 2024
3964bd0
Land Data Generator Script (#434)
SPDonaghy Sep 25, 2024
a3337c6
production db setup (#437)
JordanChen123 Sep 26, 2024
420e27c
Implemented power mode frame and ROS callbacks send data to CAN (#428)
lross03 Sep 28, 2024
593fe37
Fixed minor bug in getting current_heading for rudder_actuation_routine
alberto-escobar Sep 28, 2024
acc685d
Merge branch 'main' into alberto-escobar/425-update-low-level-control…
alberto-escobar Oct 26, 2024
084b7b2
fixed some minor issues with getting values from goal_handler and par…
alberto-escobar Oct 26, 2024
f184dda
Merge remote-tracking branch 'origin/main' into alberto-escobar/425-u…
alberto-escobar Jan 12, 2025
01d44df
Merge branch 'main' into alberto-escobar/425-update-low-level-control…
alberto-escobar Jan 25, 2025
4278efd
redid implementation of rudder actuation routine
alberto-escobar Jan 25, 2025
38c5f6b
Merge branch 'alberto-escobar/425-update-low-level-control-node' of h…
alberto-escobar Jan 25, 2025
69296d4
added init_sail_controller method
alberto-escobar Jan 25, 2025
fdc77e3
added more elaborate log call to observer RudderController
alberto-escobar Jan 25, 2025
bda6ff3
Merge branch 'main' into alberto-escobar/425-update-low-level-control…
alberto-escobar Mar 1, 2025
0300823
added change to kp, things starting to work
alberto-escobar Mar 1, 2025
daac840
added print statement
alberto-escobar Mar 2, 2025
1bf3723
implemented controllers
alberto-escobar Mar 8, 2025
c7cfc8a
finished implementing
alberto-escobar Mar 8, 2025
8589d87
updated mock sail trim tab upper and lower bound
alberto-escobar Mar 8, 2025
421f6f3
got rate.sleep to work
alberto-escobar Mar 9, 2025
8f6e9e4
Merge branch 'main' into alberto-escobar/425-update-low-level-control…
alberto-escobar Mar 9, 2025
e24476b
smal fix for mypy to pass
alberto-escobar Mar 9, 2025
0d4174f
Merge branch 'alberto-escobar/425-update-low-level-control-node' of h…
alberto-escobar Mar 9, 2025
7e73002
changed warn statements to info statements
alberto-escobar Mar 9, 2025
d67d5d4
changed `self._parameters...` to `self.get_parameters...` and appropr…
alberto-escobar Mar 29, 2025
8d6aeab
added cp to globals.yaml
alberto-escobar Mar 29, 2025
99044f8
Merge branch 'main' into alberto-escobar/425-update-low-level-control…
alberto-escobar Mar 29, 2025
6fc5d7a
Merge branch 'main' into alberto-escobar/425-update-low-level-control…
alberto-escobar Mar 29, 2025
1d9c59a
minro refractoring
alberto-escobar Mar 29, 2025
c3d0463
moved gps check
alberto-escobar Mar 29, 2025
8fc3d70
make controller intializers private (deffs did not forget this)
alberto-escobar Mar 29, 2025
4611cc3
changed float(i) to i
alberto-escobar Mar 29, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@

import boat_simulator.common.constants as Constants
from boat_simulator.common.types import Scalar
from boat_simulator.nodes.low_level_control.controller import (
RudderController,
SailController,
)
from boat_simulator.nodes.low_level_control.decorators import (
MutuallyExclusiveActionRoutine,
)
Expand Down Expand Up @@ -60,6 +64,8 @@ def __init__(self):
self.__init_feedback_execution_rates()
self.__init_subscriptions()
self.__init_action_servers()
self.__init_rudder_controller()
self.__init_sail_controller()
self.get_logger().debug("Node initialization complete. Starting execution...")

def __init_private_attributes(self):
Expand All @@ -71,6 +77,8 @@ def __init_private_attributes(self):
self._is_rudder_action_active = False
self._is_sail_action_active = False
self.__gps = None
self.__rudder_controller = None
self.__sail_controller = None

def __declare_ros_parameters(self):
"""Declares ROS parameters from the global configuration file that will be used in this
Expand All @@ -92,6 +100,7 @@ def __declare_ros_parameters(self):
("rudder.pid.kp", rclpy.Parameter.Type.DOUBLE),
("rudder.pid.ki", rclpy.Parameter.Type.DOUBLE),
("rudder.pid.kd", rclpy.Parameter.Type.DOUBLE),
("rudder.pid.cp", rclpy.Parameter.Type.DOUBLE),
("rudder.pid.buffer_size", rclpy.Parameter.Type.INTEGER),
("wingsail.disable_actuation", rclpy.Parameter.Type.BOOL),
("wingsail.fixed_angle_deg", rclpy.Parameter.Type.DOUBLE),
Expand Down Expand Up @@ -129,13 +138,15 @@ def __init_feedback_execution_rates(self):
"""
self.get_logger().debug("Initializing rate objects...")
self.__rudder_action_feedback_rate = self.create_rate(
frequency=self.get_parameter("rudder.actuation_execution_period_sec")
frequency=1.0
/ self.get_parameter("rudder.actuation_execution_period_sec")
.get_parameter_value()
.double_value,
clock=self.get_clock(),
)
self.__sail_action_feedback_rate = self.create_rate(
frequency=self.get_parameter("wingsail.actuation_execution_period_sec")
frequency=1.0
/ self.get_parameter("wingsail.actuation_execution_period_sec")
.get_parameter_value()
.double_value,
clock=self.get_clock(),
Expand Down Expand Up @@ -175,6 +186,44 @@ def __init_action_servers(self):
callback_group=self.sail_action_callback_group,
)

def __init_rudder_controller(self):
# initial heading value needed here
current_heading = 0.0
desired_heading = 0.0
current_control_ang = self.rudder_angle
time_step = (
self.get_parameter("rudder.actuation_execution_period_sec")
.get_parameter_value()
.double_value
)
kp = self.get_parameter("rudder.pid.kp").get_parameter_value().double_value
cp = self.get_parameter("rudder.pid.cp").get_parameter_value().double_value
control_speed = 1 / time_step # not sure if this is the right value to use
self.__rudder_controller = RudderController(
current_heading, desired_heading, current_control_ang, time_step, kp, cp, control_speed
)

def __init_sail_controller(self):
target_angle = (
self.get_parameter("wingsail.fixed_angle_deg").get_parameter_value().double_value
)
current_control_ang = (
self.get_parameter("wingsail.fixed_angle_deg").get_parameter_value().double_value
)
time_step = (
self.get_parameter("wingsail.actuation_execution_period_sec")
.get_parameter_value()
.double_value
)
control_speed = (
self.get_parameter("wingsail.actuation_speed_deg_per_sec")
.get_parameter_value()
.double_value
)
self.__sail_controller = SailController(
target_angle, current_control_ang, time_step, control_speed
)

def __gps_sub_callback(self, msg: GPS):
"""Stores the latest GPS data.

Expand Down Expand Up @@ -202,19 +251,37 @@ def __rudder_actuation_routine(
Returns:
Optional[SimRudderActuation_Result]: The result message if successful.
"""
self.get_logger().debug("Beginning rudder actuation...")

# TODO Placeholder loop. Replace with PID ctrl once implemented.
feedback_msg = SimRudderActuation.Feedback()
for i in range(Constants.RUDDER_ACTUATION_NUM_LOOP_EXECUTIONS):
feedback_msg.rudder_angle = float(i)
self.get_logger().debug(f"Rudder Action Server feedback: {i}")
self.get_logger().debug(f"Is Rudder Action Active? {self.is_rudder_action_active}")
goal_handle.publish_feedback(feedback=feedback_msg)
self.rudder_action_feedback_rate.sleep()
if self.get_parameter("rudder.disable_actuation").get_parameter_value().bool_value:
self.get_logger().info("Rudder actuation disabled.")
elif not self.gps:
self.get_logger().error("No GPS Data available.")
else:
self.get_logger().info("Rudder actuation enabled.")

current_heading = self.gps.heading.heading

desired_heading = goal_handle.request.desired_heading.heading.heading

self.__rudder_controller.reset_setpoint(desired_heading, current_heading)
self.get_logger().info(
f"Current rudder angle: {self.__rudder_controller.current_control_ang} "
+ f"Desired rudder angle: {self.__rudder_controller.setpoint}"
)
feedback_msg = SimRudderActuation.Feedback()
self._is_rudder_action_active = True
while not self.__rudder_controller.is_target_reached:
self.__rudder_controller.update_state()
i = self.__rudder_controller.current_control_ang
feedback_msg.rudder_angle = i
goal_handle.publish_feedback(feedback=feedback_msg)
self.__rudder_angle = i
self.rudder_action_feedback_rate.sleep()
self.get_logger().info(f"New rudder angle: {self.rudder_angle}")
self.get_logger().info("Rudder actuation complete.")

self._is_rudder_action_active = False
goal_handle.succeed()

result = SimRudderActuation.Result()
result.remaining_angular_distance = 0.0
return result
Expand All @@ -232,17 +299,34 @@ def __sail_actuation_routine(
Returns:
Optional[SimSailTrimTabActuation_Result]: The result message if successful.
"""
self.get_logger().debug("Beginning sail actuation...")

# TODO Placeholder loop. Replace with sail ctrl once implemented.
feedback_msg = SimSailTrimTabActuation.Feedback()
for i in range(Constants.SAIL_ACTUATION_NUM_LOOP_EXECUTIONS):
feedback_msg.current_angular_position = float(i)
self.get_logger().debug(f"Sail Action Server feedback: {i}")
self.get_logger().debug(f"Is Sail Action Active? {self.is_sail_action_active}")
goal_handle.publish_feedback(feedback=feedback_msg)
self.sail_action_feedback_rate.sleep()

if self.get_parameter("wingsail.disable_actuation").get_parameter_value().bool_value:
self.get_logger().info("Trim tab actuation disabled.")

else:
self.get_logger().info("Trim tab actuation enabled.")
current_trim_tab_angle = self.sail_trim_tab_angle
desired_trim_tab_angle = goal_handle.request.desired_angular_position
self.get_logger().info(
f"Current trim tab angle: {current_trim_tab_angle} "
+ f"Desired trim tab angle: {desired_trim_tab_angle}"
)
self.__sail_controller.reset_setpoint(desired_trim_tab_angle)

feedback_msg = SimSailTrimTabActuation.Feedback()
self._is_sail_action_active = True
while not self.__sail_controller.is_target_reached:
self.__sail_controller.update_state()
i = self.__sail_controller.current_control_ang
feedback_msg.current_angular_position = i
goal_handle.publish_feedback(feedback=feedback_msg)
self.__sail_trim_tab_angle = i
self.sail_action_feedback_rate.sleep()
self.get_logger().info(
f"New trim tab angle {self.__sail_controller.current_control_ang}"
)
self.get_logger().info("Trim tab actuation complete.")
self._is_sail_action_active = False
goal_handle.succeed()

result = SimSailTrimTabActuation.Result()
Expand Down
6 changes: 6 additions & 0 deletions src/global_launch/config/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,12 @@ Otherwise, the PID mechanism is used to control the rudder angle.
- _Datatype_: `double`
- _Range_: `[0.0, MAX_DOUBLE)`

**`rudder.pid.cp`**

- _Description_: The tuning parameter for the rudder control action. Only used if `rudder.disable_actuation` is false.
- _Datatype_: `double`
- _Range_: `[0.0, MAX_DOUBLE)`

**`wingsail.actuation_execution_period_sec`**

- _Description_: The period at which the main loop in the sail action server executes in seconds.
Expand Down
13 changes: 7 additions & 6 deletions src/global_launch/config/globals.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -35,15 +35,16 @@ low_level_control_node:
fixed_angle_deg: 0.0
actuation_execution_period_sec: 0.5
pid:
kp: 0.0
ki: 0.0
kd: 0.0
kp: 0.01
ki: 0.01
kd: 0.01
cp: 0.01
buffer_size: 50
wingsail:
disable_actuation: false
fixed_angle_deg: 0.0
actuation_execution_period_sec: 0.5
actuation_speed_deg_per_sec: 0.1
actuation_speed_deg_per_sec: 1.0
physics_engine_node:
ros__parameters:
logging_throttle_period_sec: 2.0
Expand Down Expand Up @@ -85,6 +86,6 @@ mock_data_node:
mock_desired_heading_lower_bound: -179.99
mock_desired_heading_upper_bound: 180.00
mock_sail_trim_tab: True
mock_sail_trim_tab_lower_bound: -40.0
mock_sail_trim_tab_upper_bound: 40.0
mock_sail_trim_tab_lower_bound: -7.0
mock_sail_trim_tab_upper_bound: 7.0
pub_period_sec: 5.0
Loading