Skip to content

Rework wind cost function in ompl objectives#817

Open
AMaharaj16 wants to merge 15 commits intomainfrom
AMaharaj16/wind-cost-rework-793
Open

Rework wind cost function in ompl objectives#817
AMaharaj16 wants to merge 15 commits intomainfrom
AMaharaj16/wind-cost-rework-793

Conversation

@AMaharaj16
Copy link
Copy Markdown
Contributor

The function wind_direction_cost() in ompl_objectives.py now correctly returns 1.0 when the segment heading lies within NO_GO_ZONE radians (45 degrees) of directly upwind (0) or directly downwind (π), and applies sin80(2θ) otherwise. Also replaced old test with new fully passing test suite for this improved implementation in test_ompl_objectives.py.

The wind cost function looks like this:
Screenshot 2026-02-18 222413

Copy link
Copy Markdown
Contributor

@raghumanimehta raghumanimehta left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please take a look at the longest comment I left on this review before anything else.

"""Computes a wind alignment cost based on the absolute angle θ between the segment
bearing and the true wind direction.

1) If θ ≤ NO_GO_ZONE or θ ≥ π − NO_GO_ZONE (i.e., within 45 degrees of directly upwind or
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what is theta? Please define what you mean by theta here.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Directly above, it says "Computes a wind alignment cost based on the absolute angle θ between the segment bearing and the true wind direction." Is this not sufficient?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it's sufficient. can you extract that definition and write it like: "theta: ..." ?

return UPWIND_COST_MULTIPLIER * cos_angle
else:
return DOWNWIND_COST_MULTIPLIER * abs(cos_angle)
# NO-GO ZONE
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This comment, imo, is not required. The reader can understand what this is for by reading the if statement and the docs about the funciton.

@@ -107,12 +115,13 @@ def wind_direction_cost(s1: cs.XY, s2: cs.XY, tw_direction_rad: float) -> float:
"""
segment_true_bearing_rad = cs.get_path_segment_true_bearing(s1, s2, rad=True)
tw_angle_rad = abs(wcs.get_true_wind_angle(segment_true_bearing_rad, tw_direction_rad))
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NOT YOUR FAULT.

While reviewing the PR, I realized that the conventions used in PATH are not consistent. Can you please look into it? Or let me know if you want me to look into it.
This funciton's example said that 0 degrees is from the bow. Other parts of the codebase are using 0 degrees as to the bow. This inconsistency is not nice. We should fix it asap. I am not going to review this PR for the time being.

If you do look into this issue, please also change the naming of the winds to our new standard. Eg. tw_speed_kmph_bcrather than wind_speed. There are also some cases where we name it as tw_speed_kmph, however notice the coordinate system is missing. Change these .i.e append bc or gc accordingly .

@AMaharaj16
Copy link
Copy Markdown
Contributor Author

The main inconsistency I have found is that global_to_boat_coordinate and boat_to_global_coordinate both assume headwind is 180 degrees, when it should be 0 degrees. This is because we want our wind convention to align with the idea that wind direction is where the wind is coming from, not where the wind is going to.

For example:

  • 0 degrees in boat coords -> headwind or wind travelling from front to back of boat.
  • 0 degrees in global coords -> wind travelling from north to south.

The rest of wind_coord_systems.py is fine. For global_to_boat_coordinate and boat_to_global_coordinate, I will adjust these functions, their tests, and wherever they get called.

wind_direction (float): The direction of the wind in radians (-pi, pi]
wind_speed (float): The speed of the wind in m/s
tw_direction_rad_gc (float): The direction of wind in global coordinate radians (-pi, pi]
tw_speed_kmph (float): The speed of the true wind in km/h
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

want to emphasize here that I converted m/s to km/h. need clarification on impacts this may have, if any.

@raghumanimehta raghumanimehta added the path Pathfinding team label Apr 10, 2026
Copy link
Copy Markdown
Contributor

@raghumanimehta raghumanimehta left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the PR! One of the function changes is incorrect and there are some naming inconsistencies that need to be ironed out.
Also the documentation for wind system was not updated (WindReference.md), please do that and also add brief documentation in source code in wind_coord_systems.py.



def boat_to_global_coordinate(boat_heading: float, wind_direction: float):
def boat_to_global_coordinate(boat_heading_deg_gc: float, aw_direction_deg_bc: float):
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please rename aw_direction_deg_bc to aw_dir_deg_bc like it is in other files.


TRUE_WIND_SPEEDS = [0.0, 11.1, 14.8, 18.5, 22.2, 25.9, 29.6, 37.0, 55.0, 75.0]
SAILING_ANGLES = [0, 45, 50, 60, 75, 90, 110, 120, 135, 150, 180]
TW_SPEEDS = [0.0, 11.1, 14.8, 18.5, 22.2, 25.9, 29.6, 37.0, 55.0, 75.0]
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add unit here please.

TRUE_WIND_SPEEDS = [0.0, 11.1, 14.8, 18.5, 22.2, 25.9, 29.6, 37.0, 55.0, 75.0]
SAILING_ANGLES = [0, 45, 50, 60, 75, 90, 110, 120, 135, 150, 180]
TW_SPEEDS = [0.0, 11.1, 14.8, 18.5, 22.2, 25.9, 29.6, 37.0, 55.0, 75.0]
SAILING_ANGLES_DEG = [0, 45, 50, 60, 75, 90, 110, 120, 135, 150, 180]
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What exactly is SAILING_ANGLES?

"""Computes a wind alignment cost based on the absolute angle θ between the segment
bearing and the true wind direction.

1) If θ ≤ NO_GO_ZONE or θ ≥ π − NO_GO_ZONE (i.e., within 45 degrees of directly upwind or
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it's sufficient. can you extract that definition and write it like: "theta: ..." ?



def get_true_wind_angle(boat_heading_rad: float, tw_dir_rad: float) -> float:
def get_true_wind_angle(boat_heading_rad_gc: float, tw_dir_rad_gc: float) -> float:
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.


bw_speed_kmph = boat_speed_kmph
bw_dir_rad = math.radians(cs.bound_to_180(boat_heading_deg + 180.0))
bw_dir_rad = math.radians(cs.bound_to_180(boat_heading_deg_gc + 180.0))
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

for consistency, you should add gc as a suffix here as well

calculations will break down.
"""
tw_dir_rad = math.radians(tw_dir_deg)
tw_dir_rad = math.radians(tw_dir_deg_gc)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

for consistency, you should add gc as a suffix here as well

bw_dir_rad = math.radians(cs.bound_to_180(boat_heading_deg + 180))
aw_east_kmph = aw_speed_kmph * math.sin(aw_dir_rad)
aw_north_kmph = aw_speed_kmph * math.cos(aw_dir_rad)
bw_dir_rad = math.radians(cs.bound_to_180(boat_heading_deg_gc + 180))
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

for consistency, you should add gc as a suffix here as well

20
"""
return cs.bound_to_180(boat_heading + wind_direction + 180.0)
return cs.bound_to_180(boat_heading_deg_gc + aw_direction_deg_bc)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is wrong. the function before this change was in fact correct. Your tests are wrong as well. Here is why consider the example:

boat heading gc = -45.0 deg
aw_dir_bc = 0.0 deg

If you draw this out on a paper, you should see that this points to 135.0 deg which is exactly what the previous function was doing. Your change will return 0.0 deg which is wrong.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

path Pathfinding team

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants