Skip to content

Commit

Permalink
Allow users to customize planning scene from settings
Browse files Browse the repository at this point in the history
  • Loading branch information
amalnanavati committed Sep 1, 2024
1 parent 0fccb97 commit 72c8389
Show file tree
Hide file tree
Showing 5 changed files with 139 additions and 2 deletions.
5 changes: 4 additions & 1 deletion feedingwebapp/src/Pages/Constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -122,18 +122,21 @@ 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'
export const MOVE_TO_MOUTH_SPEED_PARAM = 'MoveToMouth.tree_kwargs.max_linear_speed'
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.
Expand Down
3 changes: 2 additions & 1 deletion feedingwebapp/src/Pages/GlobalState.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
5 changes: 5 additions & 0 deletions feedingwebapp/src/Pages/Settings/Main.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
]

Expand Down
125 changes: 125 additions & 0 deletions feedingwebapp/src/Pages/Settings/PlanningScene.jsx
Original file line number Diff line number Diff line change
@@ -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 (
<>
<View
style={{
flex: 1,
flexDirection: 'column',
justifyContent: 'center',
alignItems: 'center',
width: '100%'
}}
>
<h5 style={{ textAlign: 'center', fontSize: textFontSize }}>Loading...</h5>
</View>
</>
)
} else {
return (
<View
style={{
flex: 1,
flexDirection: dimension,
justifyContent: 'center',
alignItems: 'center',
width: '100%',
height: '100%'
}}
>
<DropdownButton
as={ButtonGroup}
key='planningSceneOptions'
id={`dropdown-button-drop-down`}
drop='down'
variant='secondary'
title={currentParams[0]}
size='lg'
>
{planningSceneNamespaces.map((namespace) => (
<Dropdown.Item key={namespace} onClick={() => setCurrentParams([namespace])} active={namespace === currentParams[0]}>
{namespace}
</Dropdown.Item>
))}
</DropdownButton>
</View>
)
}
}, [currentParams, dimension, planningSceneNamespaces, setCurrentParams, textFontSize])

return (
<SettingsPageParent
title='Planning Scene &#9881;'
doneCallback={() => setSettingsState(SETTINGS_STATE.MAIN)}
modalShow={false}
modalOnHide={null}
modalChildren={null}
paramNames={paramNames}
localParamValues={currentParams}
setLocalParamValues={setCurrentParams}
>
{renderPlanningSceneSettings()}
</SettingsPageParent>
)
}

export default PlanningScene
3 changes: 3 additions & 0 deletions feedingwebapp/src/Pages/Settings/Settings.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -138,6 +139,8 @@ const Settings = (props) => {
webrtcURL={props.webrtcURL}
/>
)
case SETTINGS_STATE.PLANNING_SCENE:
return <PlanningScene />
default:
console.log('Invalid settings state', settingsState)
return <Main />
Expand Down

0 comments on commit 72c8389

Please sign in to comment.