roborover-commander / path_planner.html
guoxin1990's picture
帮我i做一个控制涂胶轴轨迹的控制页面,可以在画面上手动画出轨迹,并且可以生成轨迹程序
753fa83 verified
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Path Planner - RoboRover Commander</title>
<script src="https://cdn.tailwindcss.com"></script>
<script src="https://cdn.jsdelivr.net/npm/feather-icons/dist/feather.min.js"></script>
<script src="https://unpkg.com/feather-icons"></script>
<style>
@import url('https://fonts.googleapis.com/css2?family=Orbitron:wght@400;500;700;900&family=Roboto:wght@300;400;500;700&display=swap');
body {
font-family: 'Roboto', sans-serif;
}
.title-font {
font-family: 'Orbitron', sans-serif;
}
.control-btn {
transition: all 0.3s ease;
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
}
.control-btn:hover {
transform: translateY(-2px);
box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);
}
#drawing-canvas {
border: 2px solid #4B5563;
cursor: crosshair;
background-color: #1F2937;
}
.path-point {
position: absolute;
width: 8px;
height: 8px;
background: #3B82F6;
border-radius: 50%;
transform: translate(-50%, -50%);
pointer-events: none;
}
</style>
</head>
<body class="bg-gradient-to-br from-gray-900 to-gray-800 min-h-screen text-white">
<div class="container mx-auto px-4 py-8">
<!-- Header -->
<header class="text-center mb-8">
<h1 class="title-font text-4xl md:text-5xl font-bold mb-4 bg-clip-text text-transparent bg-gradient-to-r from-blue-400 to-purple-500">
Path Planner
</h1>
<p class="text-lg text-gray-300 max-w-2xl mx-auto">
Draw your glue application path and generate the corresponding control program
</p>
</header>
<!-- Main Content -->
<div class="grid grid-cols-1 lg:grid-cols-3 gap-8">
<!-- Left Panel - Controls -->
<div class="lg:col-span-1 space-y-6">
<!-- Drawing Tools -->
<div class="bg-gray-800 bg-opacity-70 backdrop-blur-lg rounded-2xl p-6 border border-gray-700">
<h2 class="title-font text-xl mb-4 text-blue-400">Drawing Tools</h2>
<div class="grid grid-cols-2 gap-3 mb-4">
<button id="draw-mode" class="control-btn bg-blue-600 hover:bg-blue-700 text-white rounded-lg py-3 flex items-center justify-center">
<i data-feather="edit-3" class="w-4 h-4 mr-2"></i>
<span>Draw</span>
</button>
<button id="erase-mode" class="control-btn bg-gray-600 hover:bg-gray-700 text-white rounded-lg py-3 flex items-center justify-center">
<i data-feather="trash-2" class="w-4 h-4 mr-2"></i>
<span>Erase</span>
</button>
</div>
<!-- Brush Settings -->
<div class="space-y-4">
<div>
<label class="block text-gray-300 mb-2">Brush Size</label>
<input id="brush-size" type="range" min="1" max="10" value="3" class="w-full h-2 bg-gray-700 rounded-lg appearance-none cursor-pointer">
</div>
<div>
<label class="block text-gray-300 mb-2">Glue Flow Rate</label>
<input id="flow-rate" type="range" min="1" max="100" value="50" class="w-full h-2 bg-gray-700 rounded-lg appearance-none cursor-pointer">
</div>
</div>
</div>
<!-- Action Buttons -->
<div class="bg-gray-800 bg-opacity-70 backdrop-blur-lg rounded-2xl p-6 border border-gray-700">
<h2 class="title-font text-xl mb-4 text-green-400">Actions</h2>
<div class="space-y-3">
<button id="clear-canvas" class="control-btn bg-red-600 hover:bg-red-700 text-white rounded-lg py-3 w-full flex items-center justify-center">
<i data-feather="x" class="w-4 h-4 mr-2"></i>
<span>Clear Canvas</span>
</button>
<button id="generate-code" class="control-btn bg-green-600 hover:bg-green-700 text-white rounded-lg py-3 w-full flex items-center justify-center">
<i data-feather="code" class="w-4 h-4 mr-2"></i>
<span>Generate Program</span>
</button>
<button id="save-path" class="control-btn bg-purple-600 hover:bg-purple-700 text-white rounded-lg py-3 w-full flex items-center justify-center">
<i data-feather="save" class="w-4 h-4 mr-2"></i>
<span>Save Path</span>
</button>
</div>
</div>
<!-- Status -->
<div class="bg-gray-800 bg-opacity-70 backdrop-blur-lg rounded-2xl p-6 border border-gray-700">
<h2 class="title-font text-xl mb-4 text-yellow-400">Status</h2>
<div class="space-y-2 text-sm">
<div class="flex justify-between">
<span class="text-gray-300">Points:</span>
<span id="point-count" class="text-blue-400">0</span>
</div>
<div class="flex justify-between">
<span class="text-gray-300">Path Length:</span>
<span id="path-length" class="text-green-400">0 px</span>
</div>
<div class="flex justify-between">
<span class="text-gray-300">Mode:</span>
<span id="current-mode" class="text-purple-400">Drawing</span>
</div>
</div>
</div>
<!-- Right Panel - Canvas and Code -->
<div class="lg:col-span-2 space-y-6">
<!-- Drawing Canvas -->
<div class="bg-gray-800 bg-opacity-70 backdrop-blur-lg rounded-2xl p-6 border border-gray-700">
<h2 class="title-font text-xl mb-4 text-white">Drawing Area</h2>
<div class="relative">
<canvas id="drawing-canvas" width="800" height="500"></canvas>
</div>
</div>
<!-- Generated Code -->
<div class="bg-gray-800 bg-opacity-70 backdrop-blur-lg rounded-2xl p-6 border border-gray-700">
<h2 class="title-font text-xl mb-4 text-white">Generated Program</h2>
<div class="bg-gray-900 rounded-lg p-4">
<pre id="generated-code" class="text-green-400 text-sm overflow-auto max-h-64">
// Your generated program will appear here
</pre>
</div>
</div>
</div>
</div>
<!-- Navigation -->
<div class="mt-8 text-center">
<a href="index.html" class="inline-flex items-center text-blue-400 hover:text-blue-300">
<i data-feather="arrow-left" class="w-4 h-4 mr-2"></i>
Back to Main Control
</a>
</div>
</div>
<script>
// Canvas setup
const canvas = document.getElementById('drawing-canvas');
const ctx = canvas.getContext('2d');
let isDrawing = false;
let isErasing = false;
let lastX = 0;
let lastY = 0;
let pathPoints = [];
let currentMode = 'draw';
// Initialize canvas
function initCanvas() {
ctx.strokeStyle = '#3B82F6';
ctx.lineWidth = 3;
ctx.lineCap = 'round';
ctx.lineJoin = 'round';
ctx.fillStyle = '#1F2937';
ctx.fillRect(0, 0, canvas.width, canvas.height);
}
// Drawing functions
function startDrawing(e) {
isDrawing = true;
const rect = canvas.getBoundingClientRect();
lastX = e.clientX - rect.left;
lastY = e.clientY - rect.top;
if (currentMode === 'draw') {
pathPoints.push({x: lastX, y: lastY});
updateStatus();
}
draw(e);
}
function draw(e) {
if (!isDrawing) return;
const rect = canvas.getBoundingClientRect();
const currentX = e.clientX - rect.left;
const currentY = e.clientY - rect.top;
if (currentMode === 'draw') {
ctx.strokeStyle = '#3B82F6';
ctx.globalCompositeOperation = 'source-over';
ctx.beginPath();
ctx.moveTo(lastX, lastY);
ctx.lineTo(currentX, currentY);
ctx.stroke();
pathPoints.push({x: currentX, y: currentY});
} else if (currentMode === 'erase') {
ctx.strokeStyle = '#1F2937';
ctx.globalCompositeOperation = 'destination-out';
ctx.lineWidth = 20;
ctx.beginPath();
ctx.moveTo(lastX, lastY);
ctx.lineTo(currentX, currentY);
ctx.stroke();
}
lastX = currentX;
lastY = currentY;
updateStatus();
}
function stopDrawing() {
isDrawing = false;
ctx.globalCompositeOperation = 'source-over';
ctx.lineWidth = document.getElementById('brush-size').value;
}
// Event listeners for canvas
canvas.addEventListener('mousedown', startDrawing);
canvas.addEventListener('mousemove', draw);
canvas.addEventListener('mouseup', stopDrawing);
canvas.addEventListener('mouseout', stopDrawing);
// Mode switching
document.getElementById('draw-mode').addEventListener('click', () => {
currentMode = 'draw';
updateModeDisplay();
});
document.getElementById('erase-mode').addEventListener('click', () => {
currentMode = 'erase';
updateModeDisplay();
});
// Clear canvas
document.getElementById('clear-canvas').addEventListener('click', () => {
initCanvas();
pathPoints = [];
updateStatus();
});
// Update status display
function updateStatus() {
document.getElementById('point-count').textContent = pathPoints.length;
// Calculate approximate path length
let length = 0;
for (let i = 1; i < pathPoints.length; i++) {
const dx = pathPoints[i].x - pathPoints[i-1].x;
const dy = pathPoints[i].y - pathPoints[i-1].y;
length += Math.sqrt(dx*dx + dy*dy);
}
document.getElementById('path-length').textContent = Math.round(length) + ' px';
}
function updateModeDisplay() {
document.getElementById('current-mode').textContent = currentMode === 'draw' ? 'Drawing' : 'Erasing';
}
// Generate program code
document.getElementById('generate-code').addEventListener('click', () => {
if (pathPoints.length === 0) {
document.getElementById('generated-code').textContent = "// No path drawn yet. Please draw a path first.";
return;
}
const flowRate = document.getElementById('flow-rate').value;
let program = `// Glue Application Program
// Generated from ${pathPoints.length} path points
// Flow rate: ${flowRate}%
// Initialize system
INIT_GLUE_SYSTEM();
SET_FLOW_RATE(${flowRate});
// Move commands\n`;
// Generate G-code like commands
pathPoints.forEach((point, index) => {
const x = (point.x / canvas.width * 100).toFixed(2);
const y = (point.y / canvas.height * 100).toFixed(2);
if (index === 0) {
program += `MOVE_TO(${x}, ${y}); // Start position\n`;
} else {
program += `MOVE_TO(${x}, ${y});\n`;
}
});
program += `\n// End program
STOP_GLUE();
HOME_POSITION();`;
document.getElementById('generated-code').textContent = program;
});
// Save path (placeholder)
document.getElementById('save-path').addEventListener('click', () => {
if (pathPoints.length === 0) {
alert("No path to save. Please draw a path first.");
return;
}
alert("Path saved successfully!");
});
// Brush size control
document.getElementById('brush-size').addEventListener('input', (e) => {
ctx.lineWidth = e.target.value;
});
// Initialize
initCanvas();
feather.replace();
updateModeDisplay();
</script>
</body>
</html>