Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion ateam_ui/src/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
"vue": "^3.3.2",
"vuetify": "^3.2.4",
"pixi.js": "^7.2.4",
"roslib": "^1.3.0"
"roslib": "^1.4.0"
},
"devDependencies": {
"@types/node": "^20.1.3",
Expand Down
15 changes: 11 additions & 4 deletions ateam_ui/src/src/App.vue
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,12 @@
<GameStatusComponent ref="refStatus"/>
<FieldComponent ref="mainField" class="ma-2 pa-2"/>
</v-col>
<v-col class="flex-grow-0 flex-shrink-0 justify-center" style="max-width:15vw; min-width:17em">
<v-col class="flex-grow-0 flex-shrink-0 justify-center" style="max-width:15vw; min-width:19em">
<v-card>
<v-tabs v-model="tab" show-arrows="false">
<v-tab value="data_tree">Data Tree</v-tab>
<v-tab value="play_book">Play List</v-tab>
<v-tab value="data_tree">Data<br/>Tree</v-tab>
<v-tab value="play_book">Play<br/>Book</v-tab>
<v-tab value="param_list">Param<br/>List</v-tab>
</v-tabs>

<v-card-text>
Expand All @@ -32,6 +33,10 @@
<v-window-item value="play_book">
<PlaybookComponent ref="Play Book"/>
</v-window-item>

<v-window-item value="param_list">
<ParamComponent ref="Param List"/>
</v-window-item>
</v-window>
</v-card-text>
</v-card>
Expand All @@ -51,6 +56,7 @@ import RefButtonsComponent from './components/RefButtonsComponent.vue'
import GameStatusComponent from './components/GameStatusComponent.vue'
import AIComponent from './components/AIComponent.vue'
import PlaybookComponent from './components/PlaybookComponent.vue'
import ParamComponent from './components/ParamComponent.vue'
import { provide } from 'vue'
import { defineComponent, toRaw } from 'vue'

Expand Down Expand Up @@ -106,7 +112,8 @@ export default {
RefButtonsComponent,
GameStatusComponent,
AIComponent,
PlaybookComponent
PlaybookComponent,
ParamComponent
}
}
</script>
120 changes: 120 additions & 0 deletions ateam_ui/src/src/components/ParamComponent.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
<template>
<v-container v-if="this.getPlaysWithParams.length == 0">
<v-col class="d-flex justify-center">
<v-progress-circular indeterminate class="mx-auto"/>
</v-col>
</v-container>
<div v-else>
<v-btn block @click.stop="getParamValues" variant="outlined"> Refresh </v-btn>

<!-- Some of the responsive sizing could be a lot better here -->
<div v-for="[play_name, play] of this.getPlaysWithParams">

<v-spacer class="pt-2"/>

<v-card :title="play.name" variant="outlined">
<v-container
v-for="[param_name, param] of Object.entries(play.params)"
class="flex-grow-1 flex-shrink-0"
>

<v-row justify="start" align="center" style="flex-wrap: nowrap;">
<v-spacer class="pr-2"/>
<div>{{ param_name + ": "}}</div>
<v-spacer class="pr-1"/>
<input type="text"
v-model="param.commanded_value"
class="flex-shrink-1"
style="
max-width: 4em;
background-color: rgb(44, 44, 44);
"
/>
<v-spacer class="pr-1"/>
<v-btn justify="end" density="compact" @click="updateParam(param)">
<v-icon icon="mdi-send" class="mx-0"/>
</v-btn>
</v-row>
</v-container>
</v-card>
</div>
</div>

</template>

<script lang="ts">
import { ref, inject } from "vue";
import { Param } from "@/param";
import '@mdi/font/css/materialdesignicons.css'


export default {
inject: ['state'],
data() {
return {
selectedPlay: []
}
},
mounted() {
this.getParamValues();

// TODO: This is bad but roslibjs doesn't seem to expose a way to
// wait for updates from the getParams functions
const self = this;
setTimeout(function(){ self.getParamValues() }, 3000);
},
methods: {
getParamValues: function() {
// Update list of params
this.state.getSTPParams();

// Get param values from ROS
for (const [play_name, play] of Object.entries(this.state.plays)) {
for (const [param_name, param] of Object.entries(play.params)) {
param.getValue();
}
}
},
updateParam(param: Param) {
param.setValue(param.commanded_value);
}
},
computed: {
getPlaysWithParams: function() {
const play_array = Object.entries(this.state.plays)
if (play_array) {
return play_array.filter(function(play_object_entry) {
const play = play_object_entry[1];
return Object.entries(play.params).length;
});
}

return [];
},
monitorParamValues: function() {
// This function is necessary to trigger rerendering when param values
// change
let param_values = {};
for (const [play_name, play] of Object.entries(this.state.plays)) {
for (const [param_name, param] of Object.entries(play.params)) {
param_values[param_name] = param.commanded_value;
}
}

return param_values;
}
},
watch: {
getPlaysWithParams: {
handler() {
},
deep: true
},
monitorParamValues: {
handler() {
},
deep: true
}
}
}
</script>
3 changes: 0 additions & 3 deletions ateam_ui/src/src/components/PlaybookComponent.vue
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,7 @@

<script lang="ts">
import { ref, inject } from "vue";
import { AIState } from "@/AI";
import { Play } from "@/play";
import { Referee, GameStage, GameCommand} from "@/referee";
import AIRecursiveComponent from "./AIRecursiveComponent.vue";

export default {
inject: ['state'],
Expand Down
47 changes: 47 additions & 0 deletions ateam_ui/src/src/param.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
// Types used for params

import ROSLIB from "roslib";

export class Param {
name: string; // Name of STP parameter (not the full ROS param path)
ros_param: ROSLIB.Param;
value: any = null;
commanded_value: any = null; // holds the input from the param ui component

constructor(name: string, ros_param: ROSLIB.Param) {
this.name = name;
this.ros_param = ros_param;
}

getValue() {
const self = this; // fix dumb javascript things

this.ros_param.get(
function(value){
self.value = value;
self.commanded_value = value;
});
}

setValue(value: any) {
const self = this; // fix dumb javascript things
this.ros_param.set(value, function(response) {
// For some reason roslibjs refuses to provide
// response information from parameter service calls
// if we ever fix it we can reenable this:
/*
if (response.success) {
self.value = value;
self.commanded_value = value;
} else {
console.log("Failed to set ", self.name, ": ", response);
self.commanded_value = self.value; // if failed reset the ui value
}
*/

// For now just assume success
self.value = value;
self.commanded_value = value;
});
}
}
5 changes: 3 additions & 2 deletions ateam_ui/src/src/play.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@
export class Play {
name: string;
score: number;
enabled: boolean = true; // Ideally we set this up to also get feedback from software about their status
enabled: boolean = true;
params = {};

constructor(name: string, enabled:boolean, score: number = NaN) {
constructor(name: string, enabled: boolean, score: number = NaN) {
this.name = name;
this.enabled = enabled;
this.score = score;
Expand Down
7 changes: 6 additions & 1 deletion ateam_ui/src/src/plugins/vuetify.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import 'vuetify/styles';
import { createVuetify } from 'vuetify';
import { aliases, mdi } from 'vuetify/iconsets/mdi'


export default createVuetify({
Expand All @@ -16,6 +17,10 @@ export default createVuetify({
}
},
icons: {
iconfont: 'mdi'
defaultSet: 'mdi',
aliases,
sets: {
mdi
}
}
});
58 changes: 52 additions & 6 deletions ateam_ui/src/src/state.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { Ball } from "@/ball"
import { Field, FieldDimensions, FieldSidedInfo } from "@/field"
import { AIState } from "@/AI"
import { Play } from "@/play"
import { Param } from "@/param"

export class RenderConfig {
angle: number = 0; // Rotation applied to the rendered field
Expand Down Expand Up @@ -57,6 +58,55 @@ export class AppState {
selected_play_name: string = null;
override_play_in_progress: string = null;

getSTPParams() {
const state = this; // fix dumb javascript things

this.ros.getParams(function(param_list) {
for (let name of param_list) {
// Check if the parameter is an stp param
if (name.includes("/kenobi_node:stp_parameters")) {

const substrings = name.split(".");

// /kenobi_node:stp_parameters.TestKickPlay.use_pivot_kick
// Make sure param has play name and stp param name
if (substrings.length < 3) {
continue;
}

// Expected format is: "/kenobi_node:stp_parameters.PlayName.ParamName"
const play_name = substrings[1];
const stp_param_name = substrings[2];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This appears to assume all parameters are at the play level. Parameters can be created anywhere in the STP tree, so in reality we might have something like this: stp_parameters.StopPlay.EasyMoveTo.MaxVelocity.
How hard would it be to show that full tree?


// Check if we already have play
if (!(play_name in state.plays)) {
// I think its better to ignore unkown plays
// Then try to create them here
continue;
}

// Create param if it doesn't already exist
if (!(stp_param_name in state.plays[play_name].params)) {
let ros_param = new ROSLIB.Param({
ros : state.ros,
name : name
});

// Not sure if we really need a list of these
// but I've been keeping track of all the other
// ROS objects so ¯\_(ツ)_/¯
state.params.push(ros_param);

state.plays[play_name].params[stp_param_name] = new Param(
stp_param_name,
ros_param
);
}
}
}
});
}

setGoalie(goalie_id: number) {
const request = new ROSLIB.ServiceRequest({
desired_keeper: goalie_id
Expand Down Expand Up @@ -276,21 +326,17 @@ export class AppState {
state.selected_play_name = state.override_play_in_progress;
}


if (msg.names.length > 0) {
state.plays = [];
for (let i = 0; i < msg.names.length; i++) {
if (msg.names[i] in state.plays) {
state.plays[msg.names[i]].enabled = msg.enableds[i]
state.plays[msg.names[i]].score = msg.scores[i]
} else {
let play = new Play(
state.plays[msg.names[i]] = new Play(
msg.names[i],
msg.enableds[i],
msg.scores[i]
)

state.plays[play.name] = play;
);
}
}
}
Expand Down
13 changes: 9 additions & 4 deletions ateam_ui/src/yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,11 @@
resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz#d7c6e6755c78567a951e04ab52ef0fd26de59f32"
integrity sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==

"@mdi/font@^7.4.47":
version "7.4.47"
resolved "https://registry.yarnpkg.com/@mdi/font/-/font-7.4.47.tgz#2ae522867da3a5c88b738d54b403eb91471903af"
integrity sha512-43MtGpd585SNzHZPcYowu/84Vz2a2g31TvPMTm9uTiCSWzaheQySUcSyUH/46fPnuPQWof2yd0pGBtzee/IQWw==

"@pixi/accessibility@7.2.4":
version "7.2.4"
resolved "https://registry.yarnpkg.com/@pixi/accessibility/-/accessibility-7.2.4.tgz#3198d0059c230c668b1179457346a3b5dcba6e64"
Expand Down Expand Up @@ -903,10 +908,10 @@ rollup@^3.21.0:
optionalDependencies:
fsevents "~2.3.2"

roslib@^1.3.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/roslib/-/roslib-1.3.0.tgz#8709626a9df92a100124b06e8dcc65e7cf986899"
integrity sha512-MqxHMW6bMpZbamgOonSOP9WJY4axCQncT5CJD1jXBjYMdp+79udwyDsD2RQXX2/Lokro8bT9LkXiW6wNn6Gxhg==
roslib@^1.4.0:
version "1.4.1"
resolved "https://registry.yarnpkg.com/roslib/-/roslib-1.4.1.tgz#ddf7c61e60d8e563d46ba8e2ea9ad90f9a1e5aa3"
integrity sha512-l3BOHqG99RHb73XROykj8o2rRaUqqYwN0E6C1EkH+R1GIfDjMaUGPaCNEoKKmsXT0Vu0EOyL1BudQtdVlMsgjA==
dependencies:
"@xmldom/xmldom" "^0.8.0"
cbor-js "^0.1.0"
Expand Down