Skip to content

Add direct navigation commands (move, turn, strafe, stop, stand/sit)#41

Open
harelb wants to merge 4 commits intomainfrom
feature/direct-navigation-commands
Open

Add direct navigation commands (move, turn, strafe, stop, stand/sit)#41
harelb wants to merge 4 commits intomainfrom
feature/direct-navigation-commands

Conversation

@harelb
Copy link
Copy Markdown

@harelb harelb commented Mar 26, 2026

Summary

  • Adds MoveRelative, TurnRelative, Strafe, Stop, and StandSit action dataclasses to robot_executor_interface
  • Implements executor dispatch methods in SpotExecutor using navigate_to_relative_pose / navigate_to_absolute_pose
  • Adds ~/pause ROS topic to hold position and block new sequences without cutting power (robot stays standing)
  • Adds unit tests (tests/test_direct_navigation.py) and on-robot verification script (examples/test_direct_navigation_on_robot.py)
  • Adds spot_tools_ros/scripts/nav_test.sh for quick interactive testing via source nav_test.sh + one-liner commands
  • Updates ActionMsg.msg with new type constants and fields (scalar_value, stand_sit_action)
  • Updates ROS serialization in action_descriptions_ros.py

Test plan

  • Unit tests pass: python -m pytest spot_tools/tests/test_direct_navigation.py -v
  • On-robot: source nav_test.sh then verify forward, backward, turn_left, turn_right, strafe_left, strafe_right, sit, stand, stop
  • Pause/resume: pause halts motion and holds pose; resume accepts new commands

harelb added 3 commits March 25, 2026 00:57
Add 5 new action types (MoveRelative, TurnRelative, Strafe, Stop, StandSit)
that bypass the PDDL planning pipeline for direct robot control via chat.
Add pause/resume mechanism on ~/pause topic for non-LLM emergency stopping.
Include unit tests and on-robot verification script.
@harelb harelb requested a review from y-veys March 26, 2026 16:04


@to_viz_msg.register
def _(action: MoveRelative, marker_ns):
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

We should definitely add visualization conversion functions here. I know it's a little tricky to figure out where to actually call them from, but I think having that capability is pretty important for understanding what the robot's trying to do. I think we would want to add an extra lightweight node that just listens on the appropriate topic, and publishes the markers associated with these new actions.

timer_period_s, self.hb_callback, callback_group=heartbeat_timer_group
)

def pause_callback(self, msg):
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

@y-veys Can you confirm that the pause callback implementation is compatible with the interrupt functionality you were working on previously?

# --- Action Dataclass Tests ---


class TestActionDataclasses:
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I don't think these tests are useful, and I think they should be removed -- they currently only test whether Python's dataclasses are implemented correctly.

# --- Executor Dispatch Tests ---


class TestExecutorDispatch:
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I also do not think these tests are useful -- they break the abstraction enabled by the executor. It would be useful to have a "closed loop" test that checks whether spot actually ends up at the desired location (which we can more or less test, because the fake spot has the step function), but not this assertion about what function gets called.

# --- ROS Message Serialization Tests ---


class TestMessageSerialization:
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

These tests should live in robot_executor_interface_ros (not here). Also, I would prefer to implement an equality operator (either as an actual override for ==, or as a multiple-dispatched function) to check equality, rather than relying on the asserts here. That makes things much more straightforward to extend in the future.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Seems like the discussion about implementing equality was dropped during the move of the tests

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

If we are going to have tests, we should run them in CI. It should be reasonably straightforward (we just need to uncomment this line and update the path

#- name: Run test script
. And we might also need to change the line before that one to install robot_executor in addition to spot_tools. )

- Add @to_viz_msg functions for MoveRelative (cyan arrow), TurnRelative (orange cylinder), Strafe (yellow arrow), Stop (red cube), StandSit (green/blue sphere)
- Remove TestActionDataclasses (tests Python, not our code)
- Remove TestExecutorDispatch (mock-based, breaks abstraction)
- Move TestMessageSerialization to robot_executor_interface_ros/tests
- Enable pytest in CI with proper dependencies
@harelb
Copy link
Copy Markdown
Author

harelb commented Mar 27, 2026

Work in progress: addressing review feedback from GoldenZephyr.

  • Added visualization markers for navigation commands
  • Refactored tests (removed dataclass/dispatch tests, moved serialization tests)
  • Enabled pytest in CI
  • Confirm pause callback compatibility with interrupt functionality (waiting on y-veys)

Copy link
Copy Markdown
Collaborator

@GoldenZephyr GoldenZephyr left a comment

Choose a reason for hiding this comment

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

see also comment about equality checking in tests

def _(action: MoveRelative, marker_ns):
return []
m = Marker()
m.header.frame_id = "body"
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I don't think this is the right way to visualize the relative commands. I think we want to be able to visualize a series of these commands in a way that represents the overall robot motion.

Representing all of the commands with respect to the current body frame does not match the semantics of what is being commanded of the robot (not to mention that hard-coding the frame here is very bad...). I think the most reasonable way of visualizing the trajectory is to transform the relative commands into the same fixed frame as the other actions, based on what the state of the robot should be when it executes the relative commands. This will require a little extra logic in the function that visualize the sequence of actions, as we have to roll forward the state from the previous actions. I think you can use an instance of SpotExecutor and fake spot to use the existing interpretation of these commands, although it might be slightly more straightforward to add the logic directly here.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants