-
Notifications
You must be signed in to change notification settings - Fork 0
Feature/mid level planner/main #30
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
… all of them should be in map frame]
Co-authored-by: Aryan Naveen <aryan_naveen@college.harvard.edu>
…need to figure out.
…d a plan, it will fall back to follow the original high level plan.
GoldenZephyr
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great progress! I left some specific comments. At a high level, I think there are two structural changes we should make.
- Let's plan to always have a mid-level planner, but the mid-level planner that is used is flexible. For the case where we want to fall back to the current behavior, the mid-level planner should just be an "identity" planner, i.e. it returns the high-level plan.
- I think we want to split up the mid-level planner, Occupancy Map, and ROS logic for updating the occupancy map slightly differently. The mid-level planner should be in charge of instantiating the occupancy map (and ROS pub/subs for updating the map)
Also, it would be great to add the instructions for how to test this functionality offboard the robot (either from a bag or the fake occupancy map), either here or in the ADT4 README
...xecutor_interface/robot_executor_interface/src/robot_executor_interface/mid_level_planner.py
Outdated
Show resolved
Hide resolved
...xecutor_interface/robot_executor_interface/src/robot_executor_interface/mid_level_planner.py
Outdated
Show resolved
Hide resolved
...xecutor_interface/robot_executor_interface/src/robot_executor_interface/mid_level_planner.py
Outdated
Show resolved
Hide resolved
...xecutor_interface/robot_executor_interface/src/robot_executor_interface/mid_level_planner.py
Outdated
Show resolved
Hide resolved
...xecutor_interface/robot_executor_interface/src/robot_executor_interface/mid_level_planner.py
Outdated
Show resolved
Hide resolved
| return [m, start, end] | ||
|
|
||
|
|
||
| def to_viz_msg(self, action, marker_ns): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there any reason that these functions for creating marker arrays from the action descriptions won't work here? https://github.com/robustrobotics/spot_tools/blob/main/robot_executor_interface/robot_executor_interface_ros/src/robot_executor_interface_ros/action_descriptions_ros.py
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When we use the existing functions we get this strange error Failed to publish path: Unknown action type <class 'robot_executor_msgs.msg._action_sequence_msg.ActionSequenceMsg the issue is for whatever reason our action type has _ before _action_sequence_msg and it should not be there?
|
@GoldenZephyr Now the branch should be mostly refactored according to the suggestions you gave. But there might be further small changes needed. |
GoldenZephyr
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good progress. Made a couple more comments (and I think there might be a small number of comments from last time to wrap up). Also,
- You'll want to rebase on main (and resolve the conflict, let me know if you need any help with that) so that CI will run
- I think some of the functions used to publish viz markers for the fake path can be used from the existing
robot_executoraction_description utilities rather than implemented here (see comment below).
I haven't had a chance to try running on my side yet, but thanks for adding the steps in the README
| def clone_grid(self): | ||
| return self.occupancy_map.copy() if self.occupancy_map is not None else None | ||
|
|
||
| def set_grid(self, grid, resolution, origin, robot_pose, update_time): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Need to acquire the lock for the duration of this function (what if one thread tries accessing this information while it is being set, and only some of the fields have updated?)
...xecutor_interface/robot_executor_interface/src/robot_executor_interface/mid_level_planner.py
Outdated
Show resolved
Hide resolved
...xecutor_interface/robot_executor_interface/src/robot_executor_interface/mid_level_planner.py
Outdated
Show resolved
Hide resolved
...xecutor_interface/robot_executor_interface/src/robot_executor_interface/mid_level_planner.py
Outdated
Show resolved
Hide resolved
| from robot_executor_msgs.msg import ActionSequenceMsg, ActionMsg | ||
|
|
||
|
|
||
| def get_robot_pose(tf_buffer, parent_frame: str, child_frame: str): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's make a utils.py in this directory for now. We can think about a more centralized utils directory outside of spot_tools_ros later
|
|
||
| def occupancy_map_callback(self, msg): | ||
|
|
||
| with self.occupancy_map: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would recommend handling the locking inside the implementation of set_grid, and then this function doesn't need to worry about acquiring the lock at all.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What if the ros updater updates the grid in the middle of the plan_path function?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What specifically is the worry? During the time when plan_path assumes the occupancy map isn't changing, it should acquire the lock. If it has the lock and we receive a message here to update the occupancy map, we wait here until we can get the lock. That should work fine, although we do need to make sure that spot_executor_ros has its ROS callbacks setup up properly to ensure that blocking in the occupancy map callback doesn't block other ROS updates (specifically, we need to make sure spot_executor_ros has a MultiThreadedExecutor and also puts this callback in its own mutually exclusive callback group.
As a starting point, make sure that only the necessary lines are within this locking block. I think its should only be the call to set_map. And then I think it will be clear that we can just move the acquisition of the lock into the top of the set_map function (as opposed to right before calling the function).
| ma.markers.append(m2) | ||
| return ma | ||
|
|
||
| def build_marker(pt, ns, frame, mid=0, color=[1,0,0]): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just to follow up on this, can the two marker-building functions be combined into one? If not, they need docstrings explaining the difference.
|
There is small one line change in hydra_ros for the active window sink config. Do we want to make a PR on that repo as well? |
…_level_planner/main
…_level_planner/main
GoldenZephyr
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks very close, just a couple of things:
- I think there might still be a couple of comments unaddressed from last time. Let me know if you have any questions on those.
- Most of the time, there's no reason to commit commented out code. For any commented out line of code, I would either delete it, uncomment it, or leave a more extensive comment discussing the code, what it does, and why it's there as a comment.
- any TODOs or similar notes in comments should either be deleted (if they aren't adding much information / aren't very important), or enough context should be added to understand what's involved with implementing the TODO.
- I think this was an unresolved comment, but in the PR there's some code for converting an ActionDescription message to an RVIZ marker message. The robot_executor package has implementations of this already, can we use those instead of adding code here?
| a_star_path_execute = a_star_path_metric | ||
|
|
||
| # project global point to local index | ||
| # TODO: add comment to explain code |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should resolve this TODO
| if frontier_cells.size == 0: | ||
| return free_cell_candidate | ||
|
|
||
| # dists_frontier = np.linalg.norm(frontier_cells - np.array(goal).T, axis=1) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
remove?
| return 0 <= cell[0] < rows and 0 <= cell[1] < cols | ||
|
|
||
| def is_obstacle(cell): | ||
| # return self.occupancy_map[cell[0], cell[1]] != 0 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
remove?
| # return self.occupancy_map[cell[0], cell[1]] != 0 | ||
| # -1 unknown, 100 occupied, 0 free | ||
| return self.occupancy_map[cell[0], cell[1]] > 0 # threshold | ||
| # TODO: might be the case |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
remove? or clarify?
| Input: high level path in <robot>/odom frame, Nx2 numpy array | ||
| Output: (bool, path) -> (success, path in odom frame) | ||
| ''' | ||
| # self.feedback.print("INFO", f"{high_level_path_metric[-1]}") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
uncomment or remove
| x=target_point.x, y=target_point.y, angle=yaw_angle | ||
| ) | ||
| feedback.print("INFO", f"Navigating to waypoint {current_waypoint}") | ||
| # feedback.print("INFO", f"Navigating to waypoint {target_point}") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
uncomment or remove
| occ_map = np.array(msg.data, dtype=np.int8).reshape((h, w)) | ||
|
|
||
| # put test code here to see status | ||
| # robot_pose = self.spot_interface.get_pose() # not working in sim ?? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is this resolved?
|
|
||
| def occupancy_map_callback(self, msg): | ||
|
|
||
| with self.occupancy_map: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What specifically is the worry? During the time when plan_path assumes the occupancy map isn't changing, it should acquire the lock. If it has the lock and we receive a message here to update the occupancy map, we wait here until we can get the lock. That should work fine, although we do need to make sure that spot_executor_ros has its ROS callbacks setup up properly to ensure that blocking in the occupancy map callback doesn't block other ROS updates (specifically, we need to make sure spot_executor_ros has a MultiThreadedExecutor and also puts this callback in its own mutually exclusive callback group.
As a starting point, make sure that only the necessary lines are within this locking block. I think its should only be the call to set_map. And then I think it will be clear that we can just move the acquisition of the lock into the top of the set_map function (as opposed to right before calling the function).
|
Oh also I think CI is failing because of formatting or code linting -- I would recommend running the pre-commit hooks locally to check what the issues are. |
I think we should be able to just include the active window sinks in the hydra config that's already in ADT4. If you put the contents of this file (https://github.com/MIT-SPARK/Hydra-ROS/blob/3d7d24ed88232ab6173c7e009504a5f762539d6c/hydra_ros/config/sinks/active_window_sinks.yaml) (plus whatever modifications you have) in the ADT4 Hydra config under the |
As a complement to this PR.