Skip to content

Commit

Permalink
Merge pull request #2 from nobleo/HARVEY2-501-send-param-request-comp…
Browse files Browse the repository at this point in the history
…lete

HARVEY2-501 Fix by always sending complete parameters service request
  • Loading branch information
MCFurry authored Jan 6, 2025
2 parents 715c08a + 42e63e7 commit f7a29e9
Show file tree
Hide file tree
Showing 4 changed files with 92 additions and 53 deletions.
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
# param_ext version history

## 0.0.03

- Fix issue with empty parameters

## 0.0.2

- Alphabetize nodes

## 0.0.1

- Alpha testing
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"description": "Interact with Parameters in ROS2",
"publisher": "Daniel Clapp",
"homepage": "https://github.com/danclapp4/ros2-parameter-extension",
"version": "0.0.1",
"version": "0.0.3",
"license": "MIT",
"main": "./dist/extension.js",
"keywords": [],
Expand Down
133 changes: 82 additions & 51 deletions src/ExamplePanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,9 @@ function ExamplePanel({ context }: { context: PanelExtensionContext }): JSX.Elem

useLayoutEffect( () => {

context.onRender = (renderState: RenderState, done) => {
context.onRender = (renderState: RenderState, done) => {

setRenderDone(() => done);
setRenderDone(() => done);
updateNodeList();

//Manage some styling for light and dark theme
Expand All @@ -53,7 +53,7 @@ function ExamplePanel({ context }: { context: PanelExtensionContext }): JSX.Elem
}, []);

// invoke the done callback once the render is complete
useEffect(() => {
useEffect(() => {
renderDone?.();
}, [renderDone]);

Expand All @@ -72,7 +72,7 @@ function ExamplePanel({ context }: { context: PanelExtensionContext }): JSX.Elem

/**
* determines if a string[] contains exlusively booleans
* @param strArr string[] to check
* @param strArr string[] to check
* @returns true if strArr only contains booleans, false otherwise
*/
const isBooleanArr = (strArr: string[]) => {
Expand Down Expand Up @@ -114,13 +114,13 @@ function ExamplePanel({ context }: { context: PanelExtensionContext }): JSX.Elem
const updateNodeList = () => {
setStatus("retreiving nodes...")
context.callService?.("/rosapi/nodes", {})
.then((_values: unknown) =>{
.then((_values: unknown) =>{
setNodeList(((_values as any).nodes as string[]).sort());
setStatus("nodes retreived");
setStatus("nodes retreived");
})
.catch((_error: Error) => { setStatus(_error.toString()); });
}

/**
* Retrieves a list of all parameters for the current node and their values
*/
Expand All @@ -138,7 +138,7 @@ function ExamplePanel({ context }: { context: PanelExtensionContext }): JSX.Elem
for (let i = 0; i < paramNameList.length; i++) {
tempList.push({name: paramNameList[i]!, value: paramValList[i]!});
}
if(tempList.length > 0)
if(tempList.length > 0)
setParamList(tempList);

if(paramNameList !== undefined) {
Expand Down Expand Up @@ -193,7 +193,7 @@ function ExamplePanel({ context }: { context: PanelExtensionContext }): JSX.Elem
}

/**
* Update the list of Parameters with new values to be set
* Update the list of Parameters with new values to be set
* @param val The new value to be set
* @param name The name of the parameter that will be set to 'val'
*/
Expand All @@ -206,28 +206,51 @@ function ExamplePanel({ context }: { context: PanelExtensionContext }): JSX.Elem
const emptyP: SetSrvParam = {};
tempList[idx] = emptyP;
} else {
let ssp: SetSrvParam = {};
// Set default ssp to complete parameter structure (https://github.com/foxglove/ros-foxglove-bridge/issues/333)
let ssp: SetSrvParam = {
name: "",
value: {
type: 0,
bool_value: false,
integer_value: 0,
double_value: 0.0,
string_value: "",
byte_array_value: [],
bool_array_value: [],
integer_array_value: [],
double_array_value: [],
string_array_value: [],
},
};
let valStrArr: string[] = [];
switch (paramList![idx]?.value.type!) {
case 1:
ssp = { name: name, value: { type: 1, bool_value: stringToBoolean(val) }};
case 1:
ssp.name = name;
ssp.value!.type = 1;
ssp.value!.bool_value = stringToBoolean(val);
break;

case 2:
ssp = { name: name, value: { type: 2, integer_value: +val }};
case 2:
ssp.name = name;
ssp.value!.type = 2;
ssp.value!.integer_value = +val;
break;

case 3:
ssp = { name: name, value: { type: 3, double_value: +val }};
case 3:
ssp.name = name;
ssp.value!.type = 3;
ssp.value!.double_value = +val;
break;

case 4:
ssp = { name: name, value: { type: 4, string_value: val }};
case 4:
ssp.name = name;
ssp.value!.type = 4;
ssp.value!.string_value = val;
break;

// TODO: Implement format for byte arrays
case 5:
//ssp = { name: name, value: { type: 5, byte_array_value: val as unknown as number[] }};
case 5:
//ssp = { name: name, value: { type: 5, byte_array_value: val as unknown as number[] }};
break;

case 6:
Expand All @@ -238,26 +261,34 @@ function ExamplePanel({ context }: { context: PanelExtensionContext }): JSX.Elem
return true;
return false;
});
ssp = { name: name, value: { type: 6, bool_array_value: valBoolArr}};
ssp.name = name;
ssp.value!.type = 6;
ssp.value!.bool_array_value = valBoolArr;
}
break;

case 7:
valStrArr = val.replace(" ", "").replace("[", "").replace("]", "").split(",");
ssp = { name: name, value: { type: 7, integer_array_value: valStrArr.map(Number) }};
case 7:
valStrArr = val.replace(" ", "").replace("[", "").replace("]", "").split(",");
ssp.name = name;
ssp.value!.type = 7;
ssp.value!.integer_array_value = valStrArr.map(Number);
break;

case 8:
valStrArr = val.replace(" ", "").replace("[", "").replace("]", "").split(",");
ssp = { name: name, value: { type: 8, double_array_value: valStrArr.map(Number) }};
ssp.name = name;
ssp.value!.type = 8;
ssp.value!.double_array_value = valStrArr.map(Number);
break;

case 9:
val.replace(" ", "");
if(val.charAt(0) == '[' && val.charAt(val.length - 1) == ']')
if(val.charAt(0) == '[' && val.charAt(val.length - 1) == ']')
val = val.substring(1, val.length - 1);
valStrArr = val.split(",");
ssp = { name: name, value: { type: 9, string_array_value: valStrArr }};
ssp.name = name;
ssp.value!.type = 9;
ssp.value!.string_array_value = valStrArr;
break;

default: ssp = {}; break;
Expand All @@ -270,7 +301,7 @@ function ExamplePanel({ context }: { context: PanelExtensionContext }): JSX.Elem
tempValList.push(getParameterValue(element));
});
}

/**
* Creates a dropdown input box if param is a boolean, creates a text input box otherwise
* @param param The parameter that an input box is being created for
Expand All @@ -290,7 +321,7 @@ function ExamplePanel({ context }: { context: PanelExtensionContext }): JSX.Elem
);
}
return(
<input style={inputStyle} placeholder={getParameterValue(param.value)} onChange={(event) => { updateSrvParamList(param.name, event.target.value) }}/>
<input style={inputStyle} placeholder={getParameterValue(param.value)} onChange={(event) => { updateSrvParamList(param.name, event.target.value) }}/>
);
}

Expand All @@ -299,10 +330,10 @@ function ExamplePanel({ context }: { context: PanelExtensionContext }): JSX.Elem
* loads parameter values from a YAML file and sets all new values
* @param files the YAML file to be uploaded
*/
const loadFile = (files: FileList | null) => {
const loadFile = (files: FileList | null) => {
if(files !== null) {
files[0]?.text()
.then((value: string) => {
.then((value: string) => {
value = value.replaceAll(/[^\S\r\n]/gi, "");
value = value.replace(node + ":\n", "");
value = value.replace("ros__parameters:\n", "");
Expand Down Expand Up @@ -435,7 +466,7 @@ function ExamplePanel({ context }: { context: PanelExtensionContext }): JSX.Elem
borderRadius: "3px",

};

inputStyle = {

fontSize: "1rem",
Expand All @@ -458,7 +489,7 @@ function ExamplePanel({ context }: { context: PanelExtensionContext }): JSX.Elem
}

const statusStyle = {
fontSize: "0.8rem",
fontSize: "0.8rem",
padding: "5px",
borderTop: "0.5px solid",
}
Expand All @@ -475,18 +506,18 @@ function ExamplePanel({ context }: { context: PanelExtensionContext }): JSX.Elem
width: "100%"
};
footerStyle;

///////////////////////////////////////////////////////////////////

///////////////////////// HTML PANEL //////////////////////////////

return (
<body>
<div style={{ padding: "1rem",
scrollBehavior: "smooth",
maxHeight:"calc(100% - 25px)",
<div style={{ padding: "1rem",
scrollBehavior: "smooth",
maxHeight:"calc(100% - 25px)",
overflowY: "scroll",
fontFamily: "helvetica",
fontFamily: "helvetica",
fontSize: "1rem",
}}>
<h1>ROS2 Parameter Extension</h1>
Expand All @@ -503,19 +534,19 @@ function ExamplePanel({ context }: { context: PanelExtensionContext }): JSX.Elem
</select>

<form>
<button
style={setButtonStyle}
onMouseEnter={() => setBgColor("#8f8f8f")}
onMouseLeave={() => colorScheme == "dark" ? setBgColor("#4d4d4d"): setBgColor("#d6d6d6")}
onClick={setParam}
<button
style={setButtonStyle}
onMouseEnter={() => setBgColor("#8f8f8f")}
onMouseLeave={() => colorScheme == "dark" ? setBgColor("#4d4d4d"): setBgColor("#d6d6d6")}
onClick={setParam}
type="reset">
Set Parameters
</button>

<label
style={loadButtonStyle}
onMouseEnter={() => setLoadButtonBgColor("#8f8f8f")}
onMouseLeave={() => colorScheme == "dark" ? setLoadButtonBgColor("#4d4d4d"): setLoadButtonBgColor("#d6d6d6")}
<label
style={loadButtonStyle}
onMouseEnter={() => setLoadButtonBgColor("#8f8f8f")}
onMouseLeave={() => colorScheme == "dark" ? setLoadButtonBgColor("#4d4d4d"): setLoadButtonBgColor("#d6d6d6")}
>
<input type="file" style={{display: "none"}} onChange={(event) => {loadFile(event.target.files)}}/>
Load
Expand All @@ -532,15 +563,15 @@ function ExamplePanel({ context }: { context: PanelExtensionContext }): JSX.Elem
<b style={{ borderBottom: "1px solid", padding: "2px", marginBottom: "3px" }}>Type</b>
<b style={{ borderBottom: "1px solid", padding: "2px", marginBottom: "3px" }}>Value</b>
<b style={{ borderBottom: "1px solid", padding: "2px", marginBottom: "3px" }}>New Value</b>

{(paramList ?? []).map((result) => (
<>
<div style={{margin: "0px 4px 0px 4px"}} key={result.name}>{result.name}:</div>
<div style={{margin: "0px 4px 0px 4px"}}>{getType(result.value)}</div>
<div style={{margin: "0px 4px 0px 4px"}}>{getParameterValue(result.value)}</div>
<div style={{margin: "0px 4px 0px 4px"}}>
<div style={{margin: "0px 4px 0px 4px"}}>
{createInputBox(result)}
</div>
</div>
</>
))}
</div>
Expand Down
2 changes: 1 addition & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { ExtensionContext } from "@foxglove/studio";
import { initParamsPanel } from "./ExamplePanel";

export function activate(extensionContext: ExtensionContext) {
extensionContext.registerPanel({ name: "Custom Parameters Extenstion", initPanel: initParamsPanel });
extensionContext.registerPanel({ name: "Custom Parameters Extension", initPanel: initParamsPanel });
}


0 comments on commit f7a29e9

Please sign in to comment.