Skip to content

Commit 9460515

Browse files
committed
Joystick
1 parent f6763df commit 9460515

File tree

3 files changed

+66
-81
lines changed

3 files changed

+66
-81
lines changed

package.json

+1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
"dependencies": {
1414
"@quasar/extras": "^1.0.0",
1515
"core-js": "^3.6.5",
16+
"lodash": "^4.17.21",
1617
"nipplejs": "^0.9.0",
1718
"quasar": "^2.0.0"
1819
},

src/components/Joy.vue

+21-10
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,44 @@
11
<template lang="pug">
2-
div(ref="joyCon").fit.rounded-borders.joy-panel
2+
q-responsive(:ratio="1")
3+
div(ref='joyCon')
34
</template>
45

56
<script setup>
67
import { ref, onMounted } from 'vue'
8+
import { colors } from 'quasar'
79
import nipplejs from 'nipplejs';
810
11+
const emit = defineEmits(["event"])
12+
913
const joyCon = ref(null);
14+
var joystick;
15+
16+
function bindNipple () {
17+
joystick.on('start end dir:up dir:left dir:down dir:right', (evt, data) => {
18+
emit("event", evt.type)
19+
})
20+
}
1021
onMounted(() => {
1122
let options = {
1223
zone: joyCon.value,
13-
mode: 'dynamic',
14-
dynamicPage: true,
24+
mode: 'static',
25+
size: 200,
1526
position: { left: '50%', bottom: "50%" },
16-
color: '#c9c3b2',
27+
color: colors.getPaletteColor("white"),
1728
threshold: 0.25,
1829
fadeTime: 400,
19-
maxNumberOfNipples: 1
30+
maxNumberOfNipples: 1,
31+
dynamicPage: true,
2032
};
21-
const staticGamepad = nipplejs.create(options)
33+
joystick = nipplejs.create(options);
34+
bindNipple();
2235
});
2336
2437
</script>
2538

2639
<style lang="sass" scoped>
27-
2840
.joy-panel
29-
// border: 5px outset
30-
background-color: $primary
31-
min-height: 500px
41+
max-width: 500px
42+
// max-height: 500px
3243
</style>
3344

src/pages/Controller.vue

+44-71
Original file line numberDiff line numberDiff line change
@@ -1,98 +1,71 @@
11
<template lang="pug">
2-
q-page(padding).flex
3-
Joy
4-
q-btn-toggle(
5-
no-caps
6-
rounded
7-
unelevated
8-
toggle-color="primary"
9-
text-color="primary"
10-
v-model="controlMode"
11-
:options="[ \
12-
{ label: 'One', value: 'one' }, \
13-
{ label: 'Two', value: 'two' }, \
14-
{ label: 'Three', value: 'three' } \
15-
]")
2+
q-page(padding)
3+
.q-pa-lg.row.q-gutter-md.flex-center
4+
q-card(style='max-width: 500px').col
5+
q-card-section(:style='state.modeStyle' )
6+
Joy(@event="handleJoystick")
7+
//- q-card-section
8+
//- q-input(label="cmd_vel topic" v-model="state.cmdVelTopic")
9+
q-tabs(v-model="state.controlMode" )
10+
q-tab(label="Base" name="base").text-primary
11+
q-tab(label="Arm" name="arm").text-secondary
12+
q-separator(inset)
13+
q-card-actions(align="center")
14+
q-btn(round icon='remove')
15+
q-btn(round icon='add')
1616
</template>
1717

1818
<script setup>
19-
// import Joy from 'components/Joy.vue'
20-
import { rosInterface } from 'src/utils/RosUtils'
19+
import _ from 'lodash';
2120
import { toRefs, ref, reactive, watch, computed, onMounted } from 'vue'
22-
import DPad from 'src/components/DPad.vue';
21+
import { getCssVar } from 'quasar'
22+
23+
import { rosInterface } from 'src/utils/RosUtils'
24+
// import DPad from 'src/components/DPad.vue';
2325
import Joy from 'src/components/Joy.vue';
2426
25-
const controlMode = ref("one")
27+
const controlStyles = {
28+
base: getCssVar('primary'),
29+
arm: getCssVar('secondary')
30+
}
31+
2632
const state = reactive({
27-
info: null,
28-
panning: false,
29-
direction: "stop",
33+
controlMode: 'base',
34+
modeStyle: computed(() => "backgroundColor: " + controlStyles[state.controlMode]),
35+
touching: false,
36+
direction: null,
3037
cmdVelTopic: rosInterface.cmdVelTopic.name,
3138
velocity: 0.5,
32-
cmdVelMsg: computed(() => {
33-
var msg = {
34-
up: { linear: { x: state.velocity } },
35-
down: { linear: { x: -state.velocity } },
36-
left: { angular: { x: state.velocity } },
37-
right: { angular: { x: -state.velocity } },
38-
stop: { linear: { x: 0.0 }, angular: { x: 0.0 } }
39-
};
40-
return msg[state.direction];
41-
})
4239
})
4340
44-
function handlePan ({ evt, ...newInfo }) {
45-
state.info = newInfo
46-
47-
// native Javascript event
48-
// console.log(evt)
49-
50-
if (newInfo.isFirst) {
51-
state.panning = true
41+
function handleJoystick (event) {
42+
// console.log(event)
43+
if (event === "start") {
44+
state.touching = true;
45+
console.log("Touch start.");
5246
}
53-
else if (newInfo.isFinal) {
54-
state.panning = false
55-
state.direction = "stop"
47+
else if (event === "end") {
48+
state.touching = false;
49+
console.log("Touch end.");
50+
}
51+
else if (_.startsWith(event, "dir:")) {
52+
state.direction = _.split(event, ":")[1];
5653
}
57-
58-
state.direction = newInfo.direction
5954
}
6055
61-
// watch topic and change publisher on change
62-
watch(() => state.cmdVelTopic, (topic) => { rosInterface.cmdVelTopic.name = topic; })
6356
// Publish 10Hz
6457
onMounted(() => {
6558
setInterval(() => {
66-
if (state.panning) {
59+
if (state.touching) {
6760
// console.log("pub message")
68-
rosInterface.cmdVelTopic.publish(state.cmdVelMsg)
61+
// rosInterface.cmdVelTopic.publish(state.cmdVelMsg)
62+
console.log(state.direction)
6963
}
7064
}, 100)
7165
})
66+
// // watch topic and change publisher on change
67+
// watch(() => state.cmdVelTopic, (topic) => { rosInterface.cmdVelTopic.name = topic; })
7268
</script>
7369

7470
<style lang="sass" scoped>
75-
.custom-area
76-
width: 90%
77-
height: 550px
78-
border-radius: 3px
79-
padding: 0px
80-
81-
.touch-area
82-
height: 85%
83-
84-
.custom-info pre
85-
width: 180px
86-
font-size: 12px
87-
88-
.touch-signal
89-
position: absolute
90-
top: 16px
91-
right: 16px
92-
width: 35px
93-
height: 35px
94-
font-size: 25px
95-
border-radius: 50% !important
96-
text-align: center
97-
background: rgba(255, 255, 255, .2)
9871
</style>

0 commit comments

Comments
 (0)