personalrobotics / ada_feeding

Robot-assisted feeding demos and projects for the ADA robot
4 stars 4 forks source link

Add BlackboardBehavior and initial AcquireFood tree #102

Closed egordon closed 1 year ago

egordon commented 1 year ago

Description

  1. Adds class behaviors.BlackboardBehavior, which exposes a concise way to map blackboard keys to local strings.
  2. Adds and hooks up the AcquireFood tree to the AcquireFood action server
  3. Creates the behavior ComputeFoodFrame which, given the goal, outputs the food reference frame. It also (optionally) publishes this frame to the TF tree for debugging purposes.
  4. Adds ComputeFoodFrame to the AcquireFoodTree
  5. Uses send_goal to write specific goal arguments to the local blackboard.

Proposal: In general, I think goal and result variables should be read from / written to the current tree blackboard namespace. This better enables subtree inclusion, where previous nodes explicitly write subtree inputs to that subtree's local blackboard and read subtree outputs from that subtree's local blackboard namespace.

For right now, I think it's okay for feedback to utilize the tree root blackboard. However, I think it would be better going forward for us to attach a FeedbackVisitor to construct it every tick instead. Feedback in theory should ideally only be dependent on:

Note that, for subtrees, get_feedback will never be called, so get_feedback, get_result, send_goal should be free to assume that they are running on the main tree and act accordingly.

The upshot of all of this is that tree_root_name becomes deprecated, and all trees can treat their own self.blackboard as the root scope.

Testing procedure

  1. Use https://github.com/personalrobotics/feeding_web_interface/pull/89 (if not merged)
  2. Run the Mock FT Sensor: ros2 run ada_feeding dummy_ft_sensor.py
  3. Run the action servers: ros2 launch ada_feeding ada_feeding_launch.xml use_estop:=false
  4. Run MoveIt in sim: ros2 launch ada_moveit demo.launch.py sim:=mock
  5. Run this code with the default dummy carrot (oriented horizontally in the camera frame): ros2 launch feeding_web_app_ros2_test feeding_dummy_acquirefood_launch.py
  6. Verify the Goal Succeeds (status=0). Open RViz and add an Axis Frame "food" (rescale to 0.1 for visibility), verify that +Z is against gravity and +X is horizontal relative to the camera.
  7. Run this code with the dummy carrot 2 (oriented ~vertically in the camera frame): ros2 launch feeding_web_app_ros2_test feeding_dummy_acquirefood_launch.py request:=above_plate_2_carrot_request.pkl
  8. Verify the Goal Succeeds (status=0). Open RViz and add an Axis Frame "food" (rescale to 0.1 for visibility), verify that +Z is against gravity and +X is vertical relative to the camera and to the "lower right" in the camera frame.

Before opening a pull request

Before Merging

egordon commented 1 year ago

Re. your idea of writing goals in local namespace as opposed to the tree root namespace, I think the only scenario in which that matters is if we use a tree within another tree, and I'm not sure how we would percolate the goal down into every subtree's blackboard. We should discuss more asynch (e.g., on a GitHub issue). For Feedback and Result, I agree that we can create a visitor for those.

We can discuss offline, though I want to flag that we shouldn't conceive of the input of the tree being the action goal specifically. Instead, we can consider a tree to have a set of inputs, like a function, that are implemented as expected variables written to the local blackboard prior to tree execution.

For the root tree, send_goal takes the goal object and writes those variables.

For sub-trees, it is up to the parent tree to write to those variables (by having the keys be the outputs of other nodes or written directly).