Ai
1 Star 0 Fork 0

九点软件/websocket-command-server

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
该仓库未声明开源许可证文件(LICENSE),使用请关注具体项目描述及其代码上游依赖。
克隆/下载
index.html 13.57 KB
一键复制 编辑 原始数据 按行查看 历史
Meatball 提交于 2025-05-29 16:48 +08:00 . 提交
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>ROS2机器人控制面板</title>
<style>
:root {
--primary: #4CAF50;
--secondary: #2196F3;
--danger: #f44336;
--gold: #FFD700;
--dark: #333;
--light: #f4f4f4;
--turquoise4: #00868B;
}
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
background: linear-gradient(135deg, #1a2a6c, #b21f1f, #1a2a6c);
color: white;
min-height: 100vh;
padding: 20px;
}
.container {
max-width: 1200px;
margin: 0 auto;
padding: 20px;
}
header {
text-align: center;
margin-bottom: 30px;
padding: 20px;
background: rgba(0, 0, 0, 0.3);
border-radius: 15px;
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.2);
}
h1 {
font-size: 2.5rem;
margin-bottom: 10px;
text-shadow: 0 2px 4px rgba(0, 0, 0, 0.5);
}
.status-panel {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 30px;
background: rgba(0, 0, 0, 0.4);
padding: 20px;
border-radius: 15px;
}
.status-indicator {
display: flex;
align-items: center;
}
.status-circle {
width: 20px;
height: 20px;
border-radius: 50%;
margin-right: 10px;
}
.status-connected { background: var(--primary); }
.status-disconnected { background: var(--danger); }
.connection-form {
display: flex;
gap: 10px;
}
input, button {
padding: 10px 15px;
border: none;
border-radius: 5px;
font-size: 1rem;
}
input {
flex-grow: 1;
background: rgba(255, 255, 255, 0.9);
}
button {
background: var(--secondary);
color: white;
cursor: pointer;
transition: all 0.3s;
font-weight: bold;
}
button:hover {
transform: translateY(-2px);
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.3);
}
.control-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 20px;
margin-bottom: 30px;
}
.control-card {
background: rgba(0, 0, 0, 0.4);
border-radius: 15px;
padding: 20px;
text-align: center;
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.2);
transition: transform 0.3s;
}
.control-card:hover {
transform: translateY(-5px);
}
.control-card h2 {
margin-bottom: 15px;
color: var(--secondary);
}
.btn-group {
display: flex;
flex-wrap: wrap;
gap: 10px;
justify-content: center;
}
.btn-group button {
flex: 1 1 120px;
}
.btn-primary { background: var(--primary); }
.btn-danger { background: var(--danger); }
.btn-secondary { background: var(--secondary); }
.btn-gold { background: var(--gold); }
.btn-turquoise4 { background: var(--turquoise4); }
.custom-command {
background: rgba(0, 0, 0, 0.4);
border-radius: 15px;
padding: 20px;
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.2);
}
.custom-command h2 {
margin-bottom: 15px;
text-align: center;
color: var(--secondary);
}
.custom-form {
display: flex;
gap: 10px;
}
.custom-form input {
background: rgba(255, 255, 255, 0.9);
}
.log-panel {
background: rgba(0, 0, 0, 0.4);
border-radius: 15px;
padding: 20px;
margin-top: 30px;
height: 200px;
overflow-y: auto;
}
.log-panel h2 {
margin-bottom: 15px;
color: var(--secondary);
}
.log-content {
font-family: monospace;
background: rgba(0, 0, 0, 0.3);
padding: 15px;
border-radius: 8px;
height: calc(100% - 40px);
overflow-y: auto;
}
.log-entry {
margin-bottom: 5px;
padding-bottom: 5px;
border-bottom: 1px solid rgba(255, 255, 255, 0.1);
}
.log-timestamp {
color: #aaa;
margin-right: 10px;
}
@media (max-width: 768px) {
.connection-form {
flex-direction: column;
}
.custom-form {
flex-direction: column;
}
@media (max-width: 380px) {
.status-panel {
flex-direction: column;
/* align-items: flex-start; */
gap: 12px;
}
.status-indicator {
justify-content: flex-start;
margin-bottom: 8px;
}
}
}
</style>
</head>
<body>
<div class="container">
<header>
<h1>ROS2机器人控制面板</h1>
<p>通过Web界面控制机器人执行指令</p>
</header>
<div class="status-panel">
<div class="status-indicator">
<div class="status-circle" id="statusCircle"></div>
<span id="statusText">未连接</span>
</div>
<div class="connection-form">
<input type="text" id="serverAddress" placeholder="ws://IP地址:9090" value="ws://localhost:9090">
<button id="connectBtn">连接</button>
<button id="disconnectBtn" disabled>断开</button>
</div>
</div>
<div class="control-grid">
<div class="control-card">
<h2>基础控制</h2>
<div class="btn-group">
<button class="btn-turquoise4" data-command="auto">自动</button>
<button class="btn-gold" data-command="manual">手动</button>
<button class="btn-primary" data-command="start">启动</button>
<button class="btn-danger" data-command="stop">停止</button>
<button class="btn-secondary" data-command="RESET">复位</button>
</div>
</div>
<div class="control-card">
<h2>运动控制</h2>
<div class="btn-group">
<button class="btn-primary" data-command="forward">前进</button>
<button class="btn-primary" data-command="backward">后退</button>
<button class="btn-primary" data-command="rotate_left">左转</button>
<button class="btn-primary" data-command="rotate_right">右转</button>
<button class="btn-primary" data-command="left">左移</button>
<button class="btn-primary" data-command="right">右移</button>
</div>
</div>
<div class="control-card">
<h2>任务指令</h2>
<div class="btn-group">
<button class="btn-secondary" data-command="MAPPING">建图模式</button>
<button class="btn-secondary" data-command="NAVIGATION">导航模式</button>
<button class="btn-secondary" data-command="CLEAN">清洁任务</button>
</div>
</div>
</div>
<div class="custom-command">
<h2>自定义指令</h2>
<div class="custom-form">
<input type="text" id="customCommand" placeholder="输入指令...">
<button class="btn-secondary" id="sendCustom">发送</button>
</div>
</div>
<div class="log-panel">
<h2>系统日志</h2>
<div class="log-content" id="logContent"></div>
</div>
</div>
<script>
// DOM元素
const connectBtn = document.getElementById('connectBtn');
const disconnectBtn = document.getElementById('disconnectBtn');
const serverAddress = document.getElementById('serverAddress');
const statusText = document.getElementById('statusText');
const statusCircle = document.getElementById('statusCircle');
const logContent = document.getElementById('logContent');
const customCommand = document.getElementById('customCommand');
const sendCustomBtn = document.getElementById('sendCustom');
let websocket = null;
// 添加日志
function addLog(message, type = 'info') {
const now = new Date();
const timestamp = now.toTimeString().split(' ')[0];
const logEntry = document.createElement('div');
logEntry.className = `log-entry log-${type}`;
logEntry.innerHTML = `<span class="log-timestamp">${timestamp}</span>${message}`;
logContent.appendChild(logEntry);
logContent.scrollTop = logContent.scrollHeight;
}
// 更新连接状态
function updateConnectionStatus(connected) {
if (connected) {
statusText.textContent = '已连接';
statusCircle.className = 'status-circle status-connected';
connectBtn.disabled = true;
disconnectBtn.disabled = false;
} else {
statusText.textContent = '未连接';
statusCircle.className = 'status-circle status-disconnected';
connectBtn.disabled = false;
disconnectBtn.disabled = true;
}
}
// 连接WebSocket
function connectWebSocket() {
const address = serverAddress.value.trim();
if (!address) {
alert('请输入WebSocket服务器地址');
return;
}
websocket = new WebSocket(address);
websocket.onopen = () => {
addLog('已连接到WebSocket服务器', 'success');
updateConnectionStatus(true);
};
websocket.onclose = () => {
addLog('WebSocket连接已关闭', 'warning');
updateConnectionStatus(false);
};
websocket.onerror = (error) => {
addLog(`WebSocket错误: ${error}`, 'error');
updateConnectionStatus(false);
};
websocket.onmessage = (event) => {
try {
const data = JSON.parse(event.data);
if (data.type === 'status') {
addLog(`机器人状态更新: ${data.data}`, 'info');
}
} catch (e) {
addLog(`收到消息: ${event.data}`, 'info');
}
};
}
// 断开WebSocket
function disconnectWebSocket() {
if (websocket) {
websocket.close();
websocket = null;
}
}
// 发送命令
function sendCommand(command) {
if (!websocket || websocket.readyState !== WebSocket.OPEN) {
alert('未连接到WebSocket服务器');
return;
}
const message = JSON.stringify({
type: 'command',
data: command
});
websocket.send(message);
addLog(`发送指令: ${command}`, 'command');
}
// 事件监听
connectBtn.addEventListener('click', connectWebSocket);
disconnectBtn.addEventListener('click', disconnectWebSocket);
// 为所有命令按钮添加事件
document.querySelectorAll('button[data-command]').forEach(button => {
button.addEventListener('click', (e) => {
const command = e.target.getAttribute('data-command');
sendCommand(command);
});
});
// 发送自定义命令
sendCustomBtn.addEventListener('click', () => {
const command = customCommand.value.trim();
if (command) {
sendCommand(command);
customCommand.value = '';
} else {
alert('请输入指令内容');
}
});
// 按回车发送自定义命令
customCommand.addEventListener('keypress', (e) => {
if (e.key === 'Enter') {
sendCustomBtn.click();
}
});
// 初始化日志
addLog('系统已启动,请连接WebSocket服务器');
</script>
</body>
</html>
Loading...
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
1
https://gitee.com/nine-point-software/websocket-command-server.git
git@gitee.com:nine-point-software/websocket-command-server.git
nine-point-software
websocket-command-server
websocket-command-server
main

搜索帮助