commit all stuff

master
conky 2022-07-14 20:35:49 +03:00
parent d0b99de71c
commit 8f60511606
4 changed files with 268 additions and 71 deletions

View File

@ -9,6 +9,7 @@
},
"dependencies": {
"core-js": "^3.8.3",
"lodash": "^4.17.21",
"vue": "^3.2.13"
},
"devDependencies": {

View File

@ -1,26 +1,153 @@
<template>
<img alt="Vue logo" src="./assets/logo.png">
<HelloWorld msg="Welcome to Your Vue.js App"/>
<div id="main">
<form id="connection" @submit.prevent="connectionFormSubmit">
<input type="text" v-model="host">
<input type="submit" :value="isConnected ? 'Disconnect' : 'Connect'">
</form>
<div id="camera-view" v-if="isConnected" style="float:left;">
<img v-if="camera_image_src !== null" :src="camera_image_src" alt="Camera View">
</div>
<div id="controls" v-if="isConnected" style="float: right">
<input type="range" v-model="driveThrottle">
<JoyStick @change="joystickChanged" />
</div>
</div>
</template>
<script>
import HelloWorld from './components/HelloWorld.vue'
import JoyStick from "@/components/JoyStick";
const _ = require('lodash');
export default {
name: 'App',
components: {
HelloWorld
components: {JoyStick},
data () {
return {
connection: null,
host: 'rc-car-esp32.local',
camera_image_src: null,
stickData: {
x: 0,
y: 0,
speed: 0,
angle: 0
},
steerValue: 'straight',
driveSide: 'stop',
driveThrottle: 0,
}
},
computed: {
isConnected() {
return this.connection instanceof WebSocket;
},
command_str() {
return `${this.driveSide}|${this.driveThrottle}|${this.steerValue}`;
}
},
methods: {
connectionFormSubmit() {
if (!this.isConnected) {
this.connection = new WebSocket(`ws://${this.host}`)
this.connection.onmessage = _.throttle((event) => {
if (event.data instanceof Blob) {
this.camera_image_src = URL.createObjectURL(event.data);
}
}, 10);
this.connection.onopen = () => {
console.log("Successfully connected to the websocket server.");
};
this.connection.onclose = () => {
console.log("Connection to the websocket server closed.");
};
}
else {
this.connection.close();
this.connection = null;
}
},
joystickChanged: _.throttle(function (data) {
this.stickData = data;
}, 100),
scale(number, fromLeft, fromRight, toLeft, toRight) {
return toLeft + (number - fromLeft) / (fromRight - fromLeft) * (toRight - toLeft);
},
handleKeyDown: function (e) {
const keyCode = String(e.keyCode || e.code || e.keyIdentifier);
if (keyCode === "37") {
this.steerValue = 'left';
}
if (keyCode === "39") {
this.steerValue = 'right';
}
if (keyCode === "38") {
this.driveSide = 'forward';
}
if (keyCode === "40") {
this.driveSide = 'backward';
}
},
handleKeyUp: function (e) {
const keyCode = String(e.keyCode || e.code || e.keyIdentifier);
if (keyCode === "37" || keyCode === "39") {
this.steerValue = 'straight';
}
if (keyCode === "38" || keyCode === "40") {
this.driveSide = 'stop';
}
}
},
watch: {
stickData(newValues) {
const xDeadzone = 5;
const yDeadzone = 5;
const true_values = {
x: this.scale(newValues.x, -96, 96, 0, 100),
y: this.scale(newValues.y, 96, -96, 0, 100)
};
if (_.inRange(true_values.x, 50 - xDeadzone, 50 + xDeadzone)) {
this.steerValue = 'straight';
}
else if (true_values.x > 50) {
this.steerValue = 'right';
}
else if (true_values.x < 50) {
this.steerValue = 'left';
}
if (_.inRange(true_values.y, 50 - yDeadzone, 50 + yDeadzone)) {
this.driveSide = 'stop';
this.driveThrottle = 0;
}
else if (_.inRange(true_values.y, 50 - yDeadzone, 0)) {
this.driveThrottle = this.scale(true_values.y, 50, 0, 0, 100);
this.driveSide = 'backward';
}
if (_.inRange(true_values.y, 50 + yDeadzone, 100)) {
this.driveThrottle = this.scale(true_values.y, 50, 100, 0, 100);
this.driveSide = 'forward';
}
},
command_str(newCmd) {
if (this.isConnected && this.connection.readyState === WebSocket.OPEN) {
this.connection.send(newCmd);
}
}
},
mounted() {
window.addEventListener('keydown', this.handleKeyDown);
window.addEventListener('keyup', this.handleKeyUp);
}
}
</script>
<style>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
</style>

View File

@ -1,58 +0,0 @@
<template>
<div class="hello">
<h1>{{ msg }}</h1>
<p>
For a guide and recipes on how to configure / customize this project,<br>
check out the
<a href="https://cli.vuejs.org" target="_blank" rel="noopener">vue-cli documentation</a>.
</p>
<h3>Installed CLI Plugins</h3>
<ul>
<li><a href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-babel" target="_blank" rel="noopener">babel</a></li>
<li><a href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-eslint" target="_blank" rel="noopener">eslint</a></li>
</ul>
<h3>Essential Links</h3>
<ul>
<li><a href="https://vuejs.org" target="_blank" rel="noopener">Core Docs</a></li>
<li><a href="https://forum.vuejs.org" target="_blank" rel="noopener">Forum</a></li>
<li><a href="https://chat.vuejs.org" target="_blank" rel="noopener">Community Chat</a></li>
<li><a href="https://twitter.com/vuejs" target="_blank" rel="noopener">Twitter</a></li>
<li><a href="https://news.vuejs.org" target="_blank" rel="noopener">News</a></li>
</ul>
<h3>Ecosystem</h3>
<ul>
<li><a href="https://router.vuejs.org" target="_blank" rel="noopener">vue-router</a></li>
<li><a href="https://vuex.vuejs.org" target="_blank" rel="noopener">vuex</a></li>
<li><a href="https://github.com/vuejs/vue-devtools#vue-devtools" target="_blank" rel="noopener">vue-devtools</a></li>
<li><a href="https://vue-loader.vuejs.org" target="_blank" rel="noopener">vue-loader</a></li>
<li><a href="https://github.com/vuejs/awesome-vue" target="_blank" rel="noopener">awesome-vue</a></li>
</ul>
</div>
</template>
<script>
export default {
name: 'HelloWorld',
props: {
msg: String
}
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
h3 {
margin: 40px 0 0;
}
ul {
list-style-type: none;
padding: 0;
}
li {
display: inline-block;
margin: 0 10px;
}
a {
color: #42b983;
}
</style>

View File

@ -0,0 +1,127 @@
<style>
.vue-joystick {
display: inline-block;
background: white;
height: 256px;
width: 256px;
border-radius: 50%;
position: relative;
border: solid 4px var(--color);
}
.vue-joystick::before,
.vue-joystick::after {
content: "";
position: absolute;
}
.vue-joystick::before {
left: 0;
right: 0;
margin: -32px;
background: var(--color);
height: 64px;
width: 64px;
border-radius: 50%;
transform: translateX(var(--x)) translateY(var(--y));
}
.vue-joystick::after {
left: 126px;
bottom: 128px;
border-radius: 10px;
width: 4px;
background: var(--color);
transform: rotate(var(--angle));
transform-origin: bottom center;
height: var(--speed);
}
</style>
<template>
<div
class="vue-joystick"
:style="style"
@touchmove="handleTouch"
@mousemove="handleMove"
@mousedown="handleStart"
@mouseup="handleRelease"
@touchend="handleRelease"
></div>
</template>
<script>
export default {
props: {
color: {
type: String,
default: "#25B"
}
},
data() {
return {
x: 0,
y: 0,
angle: 0,
speed: 0,
isMouseDown: false
};
},
computed: {
style() {
return {
"--x": `${this.x + 128}px`,
"--y": `${this.y + 128}px`,
"--speed": `${this.speed}px`,
"--angle": `${this.angle}deg`,
"--color": `${this.color}`
};
}
},
methods: {
handleStart() {
this.isMouseDown = true;
},
handleTouch({ touches: [touch] }) {
const { clientX, clientY } = touch;
const { offsetLeft, offsetTop } = this.$el;
const x = Math.round(clientX - offsetLeft - 128);
const y = Math.round(clientY - offsetTop - 128);
this.updatePosition(x, y);
},
handleMove({ clientX, clientY }) {
if (!this.isMouseDown) {
return;
}
const { offsetLeft, offsetTop } = this.$el;
const x = Math.round(clientX - offsetLeft - 128);
const y = Math.round(clientY - offsetTop - 128);
this.updatePosition(x, y);
},
handleRelease() {
this.emitAll("release");
this.isMouseDown = false;
this.updatePosition(0, 0);
},
updatePosition(x, y) {
const offset = 128 - 32;
const radians = Math.atan2(y, x);
const angle = Math.round((radians * 180) / Math.PI, 4);
this.angle = angle + (angle > 90 ? -270 : 90);
this.speed = Math.min(
Math.round(Math.sqrt(Math.pow(y, 2) + Math.pow(x, 2))),
128
);
this.x = this.speed > offset ? Math.cos(radians) * offset : x;
this.y = this.speed >= offset ? Math.sin(radians) * offset : y;
this.emitAll();
},
emitAll(name = "change") {
this.$emit(name, {
x: this.x,
y: this.y,
speed: this.speed,
angle: this.angle
});
}
},
mounted() {
this.emitAll();
}
};
</script>