Skip to content

Commit 72c8389

Browse files
committed
Allow users to customize planning scene from settings
1 parent 0fccb97 commit 72c8389

File tree

5 files changed

+139
-2
lines changed

5 files changed

+139
-2
lines changed

feedingwebapp/src/Pages/Constants.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,18 +122,21 @@ export const GET_PARAMETERS_SERVICE_NAME = 'ada_feeding_action_servers/get_param
122122
export const GET_PARAMETERS_SERVICE_TYPE = 'rcl_interfaces/srv/GetParameters'
123123
export const SET_PARAMETERS_SERVICE_NAME = 'ada_feeding_action_servers/set_parameters_atomically'
124124
export const SET_PARAMETERS_SERVICE_TYPE = 'rcl_interfaces/srv/SetParametersAtomically'
125+
export const PLANNING_SCENE_GET_PARAMETERS_SERVICE_NAME = 'ada_feeding_action_servers/get_parameters'
126+
export const PLANNING_SCENE_GET_PARAMETERS_SERVICE_TYPE = 'rcl_interfaces/srv/GetParameters'
125127

126128
// The names of parameters users can change in the settings menu
127129
export const DISTANCE_TO_MOUTH_PARAM = 'MoveToMouth.tree_kwargs.plan_distance_from_mouth'
128130
export const MOVE_TO_MOUTH_SPEED_PARAM = 'MoveToMouth.tree_kwargs.max_linear_speed'
129131
export const MOVE_TO_MOUTH_SPEED_NEAR_MOUTH_PARAM = 'MoveToMouth.tree_kwargs.linear_speed_near_mouth'
130132
export const MOVE_FROM_MOUTH_SPEED_PARAM = 'MoveFromMouth.tree_kwargs.max_linear_speed_to_staging_configuration'
131133
export const MOVE_FROM_MOUTH_SPEED_NEAR_MOUTH_PARAM = 'MoveFromMouth.tree_kwargs.linear_speed_near_mouth'
134+
export const PLANNING_SCENE_PARAM = 'planning_scene_namespace_to_use'
132135
export const ABOVE_PLATE_PARAM_JOINTS = 'MoveAbovePlate.tree_kwargs.joint_positions'
133136
export const STAGING_PARAM_JOINTS = 'MoveToStagingConfiguration.tree_kwargs.goal_configuration'
134137
export const STAGING_PARAM_POSITION = 'MoveFromMouth.tree_kwargs.staging_configuration_position'
135138
export const STAGING_PARAM_ORIENTATION = 'MoveFromMouth.tree_kwargs.staging_configuration_quat_xyzw'
136-
// TODO: Eventually, we should break AcquireFood into two actionss to avoid these
139+
// TODO: Eventually, we should break AcquireFood into two actions to avoid these
137140
// two different resting parameters.
138141
export const RESTING_PARAM_JOINTS_1 = 'AcquireFood.tree_kwargs.resting_joint_positions'
139142
// TODO: We may need to remove the orientation constraint from the below action.

feedingwebapp/src/Pages/GlobalState.jsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,8 @@ export const SETTINGS_STATE = {
9393
ABOVE_PLATE: 'ABOVE_PLATE',
9494
RESTING_CONFIGURATION: 'RESTING_CONFIGURATION',
9595
STAGING_CONFIGURATION: 'STAGING_CONFIGURATION',
96-
STOW_CONFIGURATION: 'STOW_CONFIGURATION'
96+
STOW_CONFIGURATION: 'STOW_CONFIGURATION',
97+
PLANNING_SCENE: 'PLANNING_SCENE'
9798
}
9899

99100
// The name of the default parameter namespace

feedingwebapp/src/Pages/Settings/Main.jsx

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,11 @@ const Main = () => {
186186
title: 'Stow Position',
187187
icon: moveToStowConfigurationImage,
188188
onClick: () => onClickSettingsPage(SETTINGS_STATE.STOW_CONFIGURATION)
189+
},
190+
{
191+
title: 'Planning Scene',
192+
icon: null,
193+
onClick: () => onClickSettingsPage(SETTINGS_STATE.PLANNING_SCENE)
189194
}
190195
]
191196

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
// React imports
2+
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'
3+
import { useMediaQuery } from 'react-responsive'
4+
import ButtonGroup from 'react-bootstrap/ButtonGroup'
5+
import Dropdown from 'react-bootstrap/Dropdown'
6+
import DropdownButton from 'react-bootstrap/DropdownButton'
7+
import { View } from 'react-native'
8+
9+
// Local imports
10+
import { PLANNING_SCENE_PARAM, PLANNING_SCENE_GET_PARAMETERS_SERVICE_NAME, PLANNING_SCENE_GET_PARAMETERS_SERVICE_TYPE } from '../Constants'
11+
import { useGlobalState, SETTINGS_STATE } from '../GlobalState'
12+
import { useROS, createROSService, createROSServiceRequest, getValueFromParameter } from '../../ros/ros_helpers'
13+
import SettingsPageParent from './SettingsPageParent'
14+
15+
/**
16+
* The PlanningScene component allows users to change the planning scene that a particular
17+
* settings namespace is configured with
18+
*/
19+
const PlanningScene = () => {
20+
// Get relevant global state variables
21+
const setSettingsState = useGlobalState((state) => state.setSettingsState)
22+
23+
// Flag to check if the current orientation is portrait
24+
const isPortrait = useMediaQuery({ query: '(orientation: portrait)' })
25+
// Indicator of how to arrange screen elements based on orientation
26+
let dimension = isPortrait ? 'column' : 'row'
27+
// Rendering variables
28+
let textFontSize = '3.5vh'
29+
30+
// Configure the parameters for SettingsPageParent
31+
const paramNames = useMemo(() => [PLANNING_SCENE_PARAM], [])
32+
const [currentParams, setCurrentParams] = useState([null])
33+
34+
/**
35+
* Connect to ROS, if not already connected. Put this in useRef to avoid
36+
* re-connecting upon re-renders.
37+
*/
38+
const ros = useRef(useROS().ros)
39+
40+
// Get the options for the planning scene
41+
let getParametersService = useRef(
42+
createROSService(ros.current, PLANNING_SCENE_GET_PARAMETERS_SERVICE_NAME, PLANNING_SCENE_GET_PARAMETERS_SERVICE_TYPE)
43+
)
44+
const [planningSceneNamespaces, setPlanningSceneNamespaces] = useState([])
45+
useEffect(() => {
46+
let service = getParametersService.current
47+
let request = createROSServiceRequest({
48+
names: ['namespaces']
49+
})
50+
service.callService(request, (response) => {
51+
if (response.values.length > 0 && response.values[0].type === 9) {
52+
setPlanningSceneNamespaces(getValueFromParameter(response.values[0]))
53+
} else {
54+
console.error('PlanningScene: Error getting planning scene namespaces')
55+
}
56+
})
57+
}, [getParametersService, setPlanningSceneNamespaces])
58+
59+
// Render the settings for the planning scene
60+
const renderPlanningSceneSettings = useCallback(() => {
61+
if (currentParams.some((param) => param === null)) {
62+
return (
63+
<>
64+
<View
65+
style={{
66+
flex: 1,
67+
flexDirection: 'column',
68+
justifyContent: 'center',
69+
alignItems: 'center',
70+
width: '100%'
71+
}}
72+
>
73+
<h5 style={{ textAlign: 'center', fontSize: textFontSize }}>Loading...</h5>
74+
</View>
75+
</>
76+
)
77+
} else {
78+
return (
79+
<View
80+
style={{
81+
flex: 1,
82+
flexDirection: dimension,
83+
justifyContent: 'center',
84+
alignItems: 'center',
85+
width: '100%',
86+
height: '100%'
87+
}}
88+
>
89+
<DropdownButton
90+
as={ButtonGroup}
91+
key='planningSceneOptions'
92+
id={`dropdown-button-drop-down`}
93+
drop='down'
94+
variant='secondary'
95+
title={currentParams[0]}
96+
size='lg'
97+
>
98+
{planningSceneNamespaces.map((namespace) => (
99+
<Dropdown.Item key={namespace} onClick={() => setCurrentParams([namespace])} active={namespace === currentParams[0]}>
100+
{namespace}
101+
</Dropdown.Item>
102+
))}
103+
</DropdownButton>
104+
</View>
105+
)
106+
}
107+
}, [currentParams, dimension, planningSceneNamespaces, setCurrentParams, textFontSize])
108+
109+
return (
110+
<SettingsPageParent
111+
title='Planning Scene &#9881;'
112+
doneCallback={() => setSettingsState(SETTINGS_STATE.MAIN)}
113+
modalShow={false}
114+
modalOnHide={null}
115+
modalChildren={null}
116+
paramNames={paramNames}
117+
localParamValues={currentParams}
118+
setLocalParamValues={setCurrentParams}
119+
>
120+
{renderPlanningSceneSettings()}
121+
</SettingsPageParent>
122+
)
123+
}
124+
125+
export default PlanningScene

feedingwebapp/src/Pages/Settings/Settings.jsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import {
2222
STAGING_PARAM_POSITION,
2323
STOW_PARAM_JOINTS
2424
} from '../Constants'
25+
import PlanningScene from './PlanningScene'
2526

2627
/**
2728
* The Settings components displays the appropriate settings page based on the
@@ -138,6 +139,8 @@ const Settings = (props) => {
138139
webrtcURL={props.webrtcURL}
139140
/>
140141
)
142+
case SETTINGS_STATE.PLANNING_SCENE:
143+
return <PlanningScene />
141144
default:
142145
console.log('Invalid settings state', settingsState)
143146
return <Main />

0 commit comments

Comments
 (0)