Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 04fecf33f8 | |||
| acf4efde4c |
@@ -0,0 +1,77 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import { onMount } from "svelte";
|
||||||
|
import { lidar, type LidarPoint } from '$lib/stores/lidar'
|
||||||
|
|
||||||
|
function getIntersection(angle:number, size:number):number {
|
||||||
|
const sinAngle = Math.sin(angle);
|
||||||
|
const cosAngle = Math.cos(angle);
|
||||||
|
|
||||||
|
let x, y;
|
||||||
|
if (Math.abs(cosAngle) > Math.abs(sinAngle)) {
|
||||||
|
x = size * Math.sign(cosAngle);
|
||||||
|
y = x * sinAngle / cosAngle;
|
||||||
|
} else {
|
||||||
|
y = size * Math.sign(sinAngle);
|
||||||
|
x = y * cosAngle / sinAngle;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Math.sqrt(x**2 + y**2);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
let canvas:HTMLCanvasElement
|
||||||
|
let ctx
|
||||||
|
|
||||||
|
const DEG2RAD = 0.017453292519943;
|
||||||
|
|
||||||
|
onMount(() => {
|
||||||
|
ctx = canvas.getContext("2d")
|
||||||
|
resize()
|
||||||
|
lidar.subscribe(lidar => {
|
||||||
|
draw(lidar.points)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
const draw = (points:LidarPoint[]) => {
|
||||||
|
if(!points) return
|
||||||
|
const centerX = canvas.width / 2
|
||||||
|
const centerY = canvas.height / 2
|
||||||
|
|
||||||
|
const scale = 0.01//Math.max(centerX, centerY) / Math.max(...points.map((point) => point.distance))
|
||||||
|
|
||||||
|
if (!ctx) return
|
||||||
|
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
||||||
|
for (let i = 0; i < points.length; i++){
|
||||||
|
const angle = points[i].angle
|
||||||
|
const distance = points[i].distance
|
||||||
|
const quality = points[i].quality
|
||||||
|
|
||||||
|
const endX = centerX + (distance * scale) * Math.cos(angle * DEG2RAD);
|
||||||
|
const endY = centerY - (distance * scale) * Math.sin(angle * DEG2RAD);
|
||||||
|
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.moveTo(centerX, centerY);
|
||||||
|
ctx.lineTo(endX, endY);
|
||||||
|
ctx.strokeStyle = "grey"
|
||||||
|
ctx.stroke();
|
||||||
|
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.arc(endX, endY, 3, 0, Math.PI * 2);
|
||||||
|
ctx.fillStyle = "#1bfc06"
|
||||||
|
ctx.fill();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const resize = () => {
|
||||||
|
const parentElement = canvas.parentElement;
|
||||||
|
if (parentElement) {
|
||||||
|
canvas.width = parentElement.clientWidth
|
||||||
|
canvas.height = parentElement.clientHeight
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<svelte:window on:resize={resize}></svelte:window>
|
||||||
|
|
||||||
|
<canvas bind:this={canvas} class="w-full h-full"></canvas>
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
import { writable } from 'svelte/store';
|
||||||
|
|
||||||
|
export type LidarPoint = {
|
||||||
|
distance: number;
|
||||||
|
angle: number;
|
||||||
|
quality: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
let lidar_data = {
|
||||||
|
points: <LidarPoint[]>[]
|
||||||
|
};
|
||||||
|
|
||||||
|
const maxLidarData = 600;
|
||||||
|
|
||||||
|
function createLidar() {
|
||||||
|
const { subscribe, update } = writable(lidar_data);
|
||||||
|
|
||||||
|
return {
|
||||||
|
subscribe,
|
||||||
|
addData: (lidarPoint: LidarPoint) => {
|
||||||
|
update((lidar_data) => ({
|
||||||
|
...lidar_data,
|
||||||
|
points: [...lidar_data.points, lidarPoint].slice(-maxLidarData)
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export const lidar = createLidar();
|
||||||
@@ -1,9 +1,15 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import Visualization from "$lib/components/Visualization.svelte";
|
import Visualization from "$lib/components/Visualization.svelte";
|
||||||
|
import Lidar from "$lib/components/Lidar.svelte";
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="grow flex">
|
<div class="grow flex">
|
||||||
<div class="absolute h-screen w-full top-0">
|
<div class="absolute h-screen w-full top-0 flex">
|
||||||
<Visualization debug />
|
<div class="flex-1 overflow-hidden">
|
||||||
|
<Visualization debug />
|
||||||
|
</div>
|
||||||
|
<div class="flex-1">
|
||||||
|
<Lidar />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -8,6 +8,7 @@
|
|||||||
import Devices from '~icons/mdi/devices'
|
import Devices from '~icons/mdi/devices'
|
||||||
import Camera from '~icons/mdi/camera-outline';
|
import Camera from '~icons/mdi/camera-outline';
|
||||||
import Rotate3d from '~icons/mdi/rotate-3d';
|
import Rotate3d from '~icons/mdi/rotate-3d';
|
||||||
|
import MdiLandslideOutline from '~icons/mdi/landslide-outline';
|
||||||
import MotorOutline from '~icons/mdi/motor-outline';
|
import MotorOutline from '~icons/mdi/motor-outline';
|
||||||
import Health from '~icons/mdi/stethoscope';
|
import Health from '~icons/mdi/stethoscope';
|
||||||
import Folder from '~icons/mdi/folder-outline';
|
import Folder from '~icons/mdi/folder-outline';
|
||||||
@@ -83,6 +84,12 @@
|
|||||||
icon: Rotate3d,
|
icon: Rotate3d,
|
||||||
href: '/peripherals/imu',
|
href: '/peripherals/imu',
|
||||||
feature: $page.data.features.imu || $page.data.features.mag || $page.data.features.bmp,
|
feature: $page.data.features.imu || $page.data.features.mag || $page.data.features.bmp,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Lidar',
|
||||||
|
icon: MdiLandslideOutline,
|
||||||
|
href: '/peripherals/lidar',
|
||||||
|
feature: true//$page.data.features.lidar,
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -0,0 +1,7 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import Lidar from './lidar.svelte';
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="mx-0 my-1 flex flex-col space-y-4 sm:mx-8 sm:my-8">
|
||||||
|
<Lidar />
|
||||||
|
</div>
|
||||||
@@ -0,0 +1,95 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import Lidar from "$lib/components/Lidar.svelte";
|
||||||
|
import SettingsCard from "$lib/components/SettingsCard.svelte";
|
||||||
|
import { lidar } from "$lib/stores/lidar";
|
||||||
|
import { onMount } from "svelte";
|
||||||
|
import { writable } from "svelte/store";
|
||||||
|
import { distance } from "three/examples/jsm/nodes/Nodes.js";
|
||||||
|
|
||||||
|
let port;
|
||||||
|
let reader;
|
||||||
|
let inputDone;
|
||||||
|
let inputStream;
|
||||||
|
let isConnected = false;
|
||||||
|
let buffer = '';
|
||||||
|
let lastLine = ""
|
||||||
|
|
||||||
|
onMount(() => {
|
||||||
|
navigator.serial.addEventListener("connect", (e) => {
|
||||||
|
console.log("Connected");
|
||||||
|
});
|
||||||
|
|
||||||
|
navigator.serial.addEventListener("disconnect", (e) => {
|
||||||
|
console.log("Disconnected");
|
||||||
|
});
|
||||||
|
|
||||||
|
navigator.serial.getPorts().then((ports) => {
|
||||||
|
// Initialize the list of available ports with `ports` on page load.
|
||||||
|
});
|
||||||
|
})
|
||||||
|
|
||||||
|
const connect = async () => {
|
||||||
|
try {
|
||||||
|
port = await navigator.serial.requestPort();
|
||||||
|
await port.open({ baudRate: 115200 });
|
||||||
|
const decoder = new TextDecoderStream();
|
||||||
|
inputDone = port.readable.pipeTo(decoder.writable);
|
||||||
|
inputStream = decoder.readable.pipeThrough(new TransformStream(new LineBreakTransformer()));
|
||||||
|
reader = inputStream.getReader();
|
||||||
|
readLoop();
|
||||||
|
} catch (err) {
|
||||||
|
console.error('Failed to open serial port:', err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function readLoop() {
|
||||||
|
while (true) {
|
||||||
|
const { value, done } = await reader.read();
|
||||||
|
if (done) {
|
||||||
|
console.log('[readLoop] DONE', done);
|
||||||
|
reader.releaseLock();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (value.split(",").length !== 3) continue
|
||||||
|
|
||||||
|
const [distance, angle, quality] = value.split(",").map((val:string) => parseFloat(val))
|
||||||
|
const lidarData = { distance, angle, quality }
|
||||||
|
|
||||||
|
if (distance <1000 || distance > 40000 || quality < 40) continue
|
||||||
|
lidar.addData(lidarData)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class LineBreakTransformer {
|
||||||
|
container: string;
|
||||||
|
constructor() {
|
||||||
|
this.container = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
transform(chunk: any, controller: { enqueue: (arg0: any) => any; }) {
|
||||||
|
let re = /\r\n|\n|\r/gm;
|
||||||
|
this.container += chunk;
|
||||||
|
const lines = this.container.split(re);
|
||||||
|
this.container = lines.pop() || "";
|
||||||
|
lines.forEach(line => controller.enqueue(line));
|
||||||
|
}
|
||||||
|
|
||||||
|
flush(controller: { enqueue: (arg0: string) => void; }) {
|
||||||
|
controller.enqueue(this.container);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<SettingsCard collapsible={false}>
|
||||||
|
<!-- <MdiConnection slot="icon" class="lex-shrink-0 mr-2 h-6 w-6 self-end" /> -->
|
||||||
|
<span slot="title">Lidar</span>
|
||||||
|
<div>
|
||||||
|
<button on:click={connect} class="btn">Connect</button>
|
||||||
|
</div>
|
||||||
|
</SettingsCard>
|
||||||
|
|
||||||
|
<div class="h-96 w-96">
|
||||||
|
<div class="w-full h-full">
|
||||||
|
<Lidar />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
Reference in New Issue
Block a user