diff --git a/feedingwebapp/src/Pages/Constants.js b/feedingwebapp/src/Pages/Constants.js
index 0ac1b99..36268dd 100644
--- a/feedingwebapp/src/Pages/Constants.js
+++ b/feedingwebapp/src/Pages/Constants.js
@@ -122,6 +122,8 @@ export const GET_PARAMETERS_SERVICE_NAME = 'ada_feeding_action_servers/get_param
export const GET_PARAMETERS_SERVICE_TYPE = 'rcl_interfaces/srv/GetParameters'
export const SET_PARAMETERS_SERVICE_NAME = 'ada_feeding_action_servers/set_parameters_atomically'
export const SET_PARAMETERS_SERVICE_TYPE = 'rcl_interfaces/srv/SetParametersAtomically'
+export const PLANNING_SCENE_GET_PARAMETERS_SERVICE_NAME = 'ada_feeding_action_servers/get_parameters'
+export const PLANNING_SCENE_GET_PARAMETERS_SERVICE_TYPE = 'rcl_interfaces/srv/GetParameters'
// The names of parameters users can change in the settings menu
export const DISTANCE_TO_MOUTH_PARAM = 'MoveToMouth.tree_kwargs.plan_distance_from_mouth'
@@ -129,11 +131,12 @@ export const MOVE_TO_MOUTH_SPEED_PARAM = 'MoveToMouth.tree_kwargs.max_linear_spe
export const MOVE_TO_MOUTH_SPEED_NEAR_MOUTH_PARAM = 'MoveToMouth.tree_kwargs.linear_speed_near_mouth'
export const MOVE_FROM_MOUTH_SPEED_PARAM = 'MoveFromMouth.tree_kwargs.max_linear_speed_to_staging_configuration'
export const MOVE_FROM_MOUTH_SPEED_NEAR_MOUTH_PARAM = 'MoveFromMouth.tree_kwargs.linear_speed_near_mouth'
+export const PLANNING_SCENE_PARAM = 'planning_scene_namespace_to_use'
export const ABOVE_PLATE_PARAM_JOINTS = 'MoveAbovePlate.tree_kwargs.joint_positions'
export const STAGING_PARAM_JOINTS = 'MoveToStagingConfiguration.tree_kwargs.goal_configuration'
export const STAGING_PARAM_POSITION = 'MoveFromMouth.tree_kwargs.staging_configuration_position'
export const STAGING_PARAM_ORIENTATION = 'MoveFromMouth.tree_kwargs.staging_configuration_quat_xyzw'
-// TODO: Eventually, we should break AcquireFood into two actionss to avoid these
+// TODO: Eventually, we should break AcquireFood into two actions to avoid these
// two different resting parameters.
export const RESTING_PARAM_JOINTS_1 = 'AcquireFood.tree_kwargs.resting_joint_positions'
// TODO: We may need to remove the orientation constraint from the below action.
diff --git a/feedingwebapp/src/Pages/GlobalState.jsx b/feedingwebapp/src/Pages/GlobalState.jsx
index 5d6e211..c530b38 100644
--- a/feedingwebapp/src/Pages/GlobalState.jsx
+++ b/feedingwebapp/src/Pages/GlobalState.jsx
@@ -93,7 +93,8 @@ export const SETTINGS_STATE = {
ABOVE_PLATE: 'ABOVE_PLATE',
RESTING_CONFIGURATION: 'RESTING_CONFIGURATION',
STAGING_CONFIGURATION: 'STAGING_CONFIGURATION',
- STOW_CONFIGURATION: 'STOW_CONFIGURATION'
+ STOW_CONFIGURATION: 'STOW_CONFIGURATION',
+ PLANNING_SCENE: 'PLANNING_SCENE'
}
// The name of the default parameter namespace
diff --git a/feedingwebapp/src/Pages/Settings/Main.jsx b/feedingwebapp/src/Pages/Settings/Main.jsx
index 09c1022..1b91470 100644
--- a/feedingwebapp/src/Pages/Settings/Main.jsx
+++ b/feedingwebapp/src/Pages/Settings/Main.jsx
@@ -186,6 +186,11 @@ const Main = () => {
title: 'Stow Position',
icon: moveToStowConfigurationImage,
onClick: () => onClickSettingsPage(SETTINGS_STATE.STOW_CONFIGURATION)
+ },
+ {
+ title: 'Planning Scene',
+ icon: null,
+ onClick: () => onClickSettingsPage(SETTINGS_STATE.PLANNING_SCENE)
}
]
diff --git a/feedingwebapp/src/Pages/Settings/PlanningScene.jsx b/feedingwebapp/src/Pages/Settings/PlanningScene.jsx
new file mode 100644
index 0000000..069a90d
--- /dev/null
+++ b/feedingwebapp/src/Pages/Settings/PlanningScene.jsx
@@ -0,0 +1,125 @@
+// React imports
+import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'
+import { useMediaQuery } from 'react-responsive'
+import ButtonGroup from 'react-bootstrap/ButtonGroup'
+import Dropdown from 'react-bootstrap/Dropdown'
+import DropdownButton from 'react-bootstrap/DropdownButton'
+import { View } from 'react-native'
+
+// Local imports
+import { PLANNING_SCENE_PARAM, PLANNING_SCENE_GET_PARAMETERS_SERVICE_NAME, PLANNING_SCENE_GET_PARAMETERS_SERVICE_TYPE } from '../Constants'
+import { useGlobalState, SETTINGS_STATE } from '../GlobalState'
+import { useROS, createROSService, createROSServiceRequest, getValueFromParameter } from '../../ros/ros_helpers'
+import SettingsPageParent from './SettingsPageParent'
+
+/**
+ * The PlanningScene component allows users to change the planning scene that a particular
+ * settings namespace is configured with
+ */
+const PlanningScene = () => {
+ // Get relevant global state variables
+ const setSettingsState = useGlobalState((state) => state.setSettingsState)
+
+ // Flag to check if the current orientation is portrait
+ const isPortrait = useMediaQuery({ query: '(orientation: portrait)' })
+ // Indicator of how to arrange screen elements based on orientation
+ let dimension = isPortrait ? 'column' : 'row'
+ // Rendering variables
+ let textFontSize = '3.5vh'
+
+ // Configure the parameters for SettingsPageParent
+ const paramNames = useMemo(() => [PLANNING_SCENE_PARAM], [])
+ const [currentParams, setCurrentParams] = useState([null])
+
+ /**
+ * Connect to ROS, if not already connected. Put this in useRef to avoid
+ * re-connecting upon re-renders.
+ */
+ const ros = useRef(useROS().ros)
+
+ // Get the options for the planning scene
+ let getParametersService = useRef(
+ createROSService(ros.current, PLANNING_SCENE_GET_PARAMETERS_SERVICE_NAME, PLANNING_SCENE_GET_PARAMETERS_SERVICE_TYPE)
+ )
+ const [planningSceneNamespaces, setPlanningSceneNamespaces] = useState([])
+ useEffect(() => {
+ let service = getParametersService.current
+ let request = createROSServiceRequest({
+ names: ['namespaces']
+ })
+ service.callService(request, (response) => {
+ if (response.values.length > 0 && response.values[0].type === 9) {
+ setPlanningSceneNamespaces(getValueFromParameter(response.values[0]))
+ } else {
+ console.error('PlanningScene: Error getting planning scene namespaces')
+ }
+ })
+ }, [getParametersService, setPlanningSceneNamespaces])
+
+ // Render the settings for the planning scene
+ const renderPlanningSceneSettings = useCallback(() => {
+ if (currentParams.some((param) => param === null)) {
+ return (
+ <>
+
+ Loading...
+
+ >
+ )
+ } else {
+ return (
+
+
+ {planningSceneNamespaces.map((namespace) => (
+ setCurrentParams([namespace])} active={namespace === currentParams[0]}>
+ {namespace}
+
+ ))}
+
+
+ )
+ }
+ }, [currentParams, dimension, planningSceneNamespaces, setCurrentParams, textFontSize])
+
+ return (
+ setSettingsState(SETTINGS_STATE.MAIN)}
+ modalShow={false}
+ modalOnHide={null}
+ modalChildren={null}
+ paramNames={paramNames}
+ localParamValues={currentParams}
+ setLocalParamValues={setCurrentParams}
+ >
+ {renderPlanningSceneSettings()}
+
+ )
+}
+
+export default PlanningScene
diff --git a/feedingwebapp/src/Pages/Settings/Settings.jsx b/feedingwebapp/src/Pages/Settings/Settings.jsx
index b325b71..dcf30b1 100644
--- a/feedingwebapp/src/Pages/Settings/Settings.jsx
+++ b/feedingwebapp/src/Pages/Settings/Settings.jsx
@@ -22,6 +22,7 @@ import {
STAGING_PARAM_POSITION,
STOW_PARAM_JOINTS
} from '../Constants'
+import PlanningScene from './PlanningScene'
/**
* The Settings components displays the appropriate settings page based on the
@@ -138,6 +139,8 @@ const Settings = (props) => {
webrtcURL={props.webrtcURL}
/>
)
+ case SETTINGS_STATE.PLANNING_SCENE:
+ return
default:
console.log('Invalid settings state', settingsState)
return