Skip to content

Commit f67427e

Browse files
amalnanavatiTaylor Kessler Faulkner
andcommitted
[Bugfix] Workspace walls should get default configurations if customized ones don't exist (#201)
* Add a demo-specific custom configuration * Hacky workaround to known rclpy bug with destroyables * Get default robot arm configurations if the customized ones are undefined --------- Co-authored-by: Taylor Kessler Faulkner <taylorkf@cs.washington.edu>
1 parent ec022d7 commit f67427e

File tree

5 files changed

+135
-39
lines changed

5 files changed

+135
-39
lines changed

ada_feeding/config/ada_feeding_action_servers_custom.yaml

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,18 @@ ada_feeding_action_servers:
9494
- side_staging_1
9595
- side_staging_2
9696
- side_staging_3
97-
namespace_to_use: wheelchair_side_table_1
97+
- demo
98+
demo:
99+
MoveFromMouth.tree_kwargs.linear_speed_near_mouth: 0.08
100+
MoveFromMouth.tree_kwargs.max_linear_speed_to_staging_configuration: 0.15
101+
MoveToMouth.tree_kwargs.linear_speed_near_mouth: 0.06
102+
MoveToMouth.tree_kwargs.max_linear_speed: 0.15
103+
MoveToMouth.tree_kwargs.plan_distance_from_mouth:
104+
- 0.05
105+
- 0.0
106+
- -0.01
107+
planning_scene_namespace_to_use: seated
108+
namespace_to_use: demo
98109
side_staging_1:
99110
AcquireFood.tree_kwargs.resting_joint_positions:
100111
- -0.8849039817349507

ada_feeding/config/ada_feeding_action_servers_default.yaml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,7 @@ ada_feeding_action_servers:
55
watchdog_timeout_sec: 0.5 # sec
66

77
default:
8-
# TODO: Post-deployment, change this back!
9-
planning_scene_namespace_to_use: seated_90
8+
planning_scene_namespace_to_use: seated
109

1110
# A list of the names of the action servers to create. Each one must have
1211
# it's own parameters (below) specifying action_type and tree_class.

ada_planning_scene/ada_planning_scene/ada_planning_scene.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
# Standard imports
77
import threading
8+
import traceback
89
from typing import List
910

1011
# Third-party imports
@@ -381,6 +382,23 @@ def parameter_callback(self, params: List[Parameter]) -> SetParametersResult:
381382
return SetParametersResult(successful=True)
382383

383384

385+
def spin(node: Node, executor: MultiThreadedExecutor) -> None:
386+
"""
387+
Spin the node in the executor.
388+
"""
389+
try:
390+
rclpy.spin(node, executor=executor)
391+
except rclpy._rclpy_pybind11.InvalidHandle:
392+
# There is a known issue in rclpy where it doesn't properly handle destruction of
393+
# elements in the executor.
394+
# - https://github.com/ros2/rclpy/issues/1355
395+
# - https://github.com/ros2/rclpy/issues/1206
396+
# - https://github.com/ros2/rclpy/issues/1142
397+
# This is a **very hacky** workaround to prevent the node from crashing.
398+
traceback.print_exc()
399+
spin(node, executor)
400+
401+
384402
def main(args: List = None) -> None:
385403
"""
386404
Create the ROS2 node.

ada_planning_scene/ada_planning_scene/workspace_walls.py

Lines changed: 102 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -808,7 +808,7 @@ def cleanup():
808808
):
809809
prefix = ""
810810
else:
811-
prefix = response.values[0].string_value + "."
811+
prefix = response.values[0].string_value
812812

813813
cleanup()
814814
return True, prefix
@@ -826,31 +826,33 @@ def __joint_states_callback(self, msg: JointState) -> None:
826826
if name in self.__articulated_joint_names:
827827
self.__joint_states[name] = msg.position[i]
828828

829-
def __get_robot_configurations(
829+
def __get_robot_configurations_within_prefix(
830830
self,
831+
prefix: str,
832+
configurations_parameter_names: List[str],
831833
rate_hz: float = 10.0,
832834
timeout: Duration = Duration(seconds=5),
833835
publish_feedback: Optional[Callable[[], None]] = None,
834-
include_current_robot_config: bool = True,
835836
) -> Tuple[bool, Dict[str, List[float]]]:
836837
"""
837-
Get the robot's configurations.
838+
Get the robot's configurations within a prefix.
838839
839840
Parameters
840841
----------
842+
prefix: The prefix to add to the parameter name.
843+
configurations_parameter_names: The names of the parameters that contain robot
844+
joint configurations that should be contained within the workspace walls.
841845
rate_hz: The rate at which to call the service.
842846
timeout: The timeout for the service.
843847
publish_feedback: If not None, call this function periodically to publish feedback.
844-
include_current_robot_config: Whether to include the current robot configuration.
845-
This can override the value set in the parameter.
846848
847849
Returns
848850
-------
849851
success: True if successful, False otherwise.
850852
robot_configurations: A map from the parameter name to the configuration.
851853
"""
852-
# pylint: disable=too-many-locals, too-many-branches
853-
# A few above is fine
854+
# pylint: disable=too-many-locals, too-many-arguments
855+
# One over is fine.
854856

855857
# Start the time
856858
start_time = self.__node.get_clock().now()
@@ -859,35 +861,11 @@ def __get_robot_configurations(
859861
def cleanup():
860862
self.__node.destroy_rate(rate)
861863

862-
# Get the prefix
863-
success, prefix = self.__get_parameter_prefix(
864-
rate_hz, get_remaining_time(self.__node, start_time, timeout)
865-
)
866-
if not success:
867-
self.__node.get_logger().error("Failed to get the parameter prefix.")
868-
cleanup()
869-
return False, {}
870-
871-
# Wait for the service to be ready
872-
self.__node.get_logger().info(
873-
"Waiting for the get robot configurations parameter service."
874-
)
875-
while not self.__get_robot_configurations_parameter_service.service_is_ready():
876-
if not check_ok(self.__node, start_time, timeout):
877-
self.__node.get_logger().error(
878-
"Timeout while waiting for the get robot configurations parameter service."
879-
)
880-
cleanup()
881-
return False, {}
882-
if publish_feedback is not None:
883-
publish_feedback()
884-
rate.sleep()
885-
886864
# Get the robot configurations
887865
robot_configurations = {}
888866
request = GetParameters.Request()
889867
request.names = [
890-
prefix + name for name in self.__robot_configurations_parameter_names
868+
".".join([prefix, name]) for name in configurations_parameter_names
891869
]
892870
self.__node.get_logger().info(
893871
f"Getting robot configurations from parameters: {request.names}"
@@ -916,7 +894,7 @@ def cleanup():
916894
for i, param in enumerate(response.values):
917895
if param.type != ParameterType.PARAMETER_DOUBLE_ARRAY:
918896
continue
919-
robot_configurations[self.__robot_configurations_parameter_names[i]] = list(
897+
robot_configurations[configurations_parameter_names[i]] = list(
920898
param.double_array_value
921899
)
922900
if publish_feedback is not None:
@@ -926,6 +904,96 @@ def cleanup():
926904
cleanup()
927905
return False, {}
928906

907+
cleanup()
908+
return True, robot_configurations
909+
910+
def __get_robot_configurations(
911+
self,
912+
rate_hz: float = 10.0,
913+
timeout: Duration = Duration(seconds=5),
914+
publish_feedback: Optional[Callable[[], None]] = None,
915+
include_current_robot_config: bool = True,
916+
) -> Tuple[bool, Dict[str, List[float]]]:
917+
"""
918+
Get the robot's configurations.
919+
920+
Parameters
921+
----------
922+
rate_hz: The rate at which to call the service.
923+
timeout: The timeout for the service.
924+
publish_feedback: If not None, call this function periodically to publish feedback.
925+
include_current_robot_config: Whether to include the current robot configuration.
926+
This can override the value set in the parameter.
927+
928+
Returns
929+
-------
930+
success: True if successful, False otherwise.
931+
robot_configurations: A map from the parameter name to the configuration.
932+
"""
933+
# pylint: disable=too-many-locals, too-many-branches
934+
# A few above is fine
935+
936+
# Start the time
937+
start_time = self.__node.get_clock().now()
938+
rate = self.__node.create_rate(rate_hz)
939+
940+
def cleanup():
941+
self.__node.destroy_rate(rate)
942+
943+
# Get the prefix
944+
success, prefix = self.__get_parameter_prefix(
945+
rate_hz, get_remaining_time(self.__node, start_time, timeout)
946+
)
947+
if not success:
948+
self.__node.get_logger().error("Failed to get the parameter prefix.")
949+
cleanup()
950+
return False, {}
951+
952+
# Wait for the service to be ready
953+
self.__node.get_logger().info(
954+
"Waiting for the get robot configurations parameter service."
955+
)
956+
while not self.__get_robot_configurations_parameter_service.service_is_ready():
957+
if not check_ok(self.__node, start_time, timeout):
958+
self.__node.get_logger().error(
959+
"Timeout while waiting for the get robot configurations parameter service."
960+
)
961+
cleanup()
962+
return False, {}
963+
if publish_feedback is not None:
964+
publish_feedback()
965+
rate.sleep()
966+
967+
# Get the robot configurations
968+
_, robot_configurations = self.__get_robot_configurations_within_prefix(
969+
prefix,
970+
self.__robot_configurations_parameter_names,
971+
rate_hz,
972+
get_remaining_time(self.__node, start_time, timeout),
973+
publish_feedback=publish_feedback,
974+
)
975+
remaining_configurations_parameter_names = [
976+
name
977+
for name in self.__robot_configurations_parameter_names
978+
if name not in robot_configurations
979+
]
980+
_, default_robot_configurations = self.__get_robot_configurations_within_prefix(
981+
"default",
982+
remaining_configurations_parameter_names,
983+
rate_hz,
984+
get_remaining_time(self.__node, start_time, timeout),
985+
publish_feedback=publish_feedback,
986+
)
987+
robot_configurations.update(default_robot_configurations)
988+
# If we got some but not all of them, raise an error but continue
989+
if len(robot_configurations) != len(
990+
self.__robot_configurations_parameter_names
991+
):
992+
self.__node.get_logger().error("Failed to get robot configurations.")
993+
if len(robot_configurations) == 0:
994+
cleanup()
995+
return False, {}
996+
929997
# Add the current joint state
930998
if (
931999
self.__workspace_walls_contain_current_robot_config

ada_planning_scene/config/ada_planning_scene.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ ada_planning_scene:
2525
- bedside
2626
- seated_90
2727
- bedside_90
28-
namespace_to_use: seated_90 # bedside_90 #
28+
namespace_to_use: seated
2929

3030
############################################################################
3131
# Parameters related to the PlanningSceneInitializer class
@@ -294,7 +294,7 @@ ada_planning_scene:
294294
- "MoveAbovePlate.tree_kwargs.joint_positions"
295295
- "MoveToRestingPosition.tree_kwargs.goal_configuration"
296296
- "MoveToStagingConfiguration.tree_kwargs.goal_configuration"
297-
- "MoveToStowLocation.tree_kwargs.tree_kwargs"
297+
- "MoveToStowLocation.tree_kwargs.joint_positions"
298298

299299
# Which joints in the robot's URDF are fixed (along with their values).
300300
# These are used when computing the bounds of different robot arm configurationss.

0 commit comments

Comments
 (0)