【安信可雷达模组Rd-03_V2】网页距离监控
本文介绍了安信可 Rd-03 V2 雷达模组通过网页上位机实现距离监控的项目设计。
项目介绍
通过 Web 网页上位机接收和解析 Rd-03 V2 雷达测距信息、历史演化曲线、距离统计信息等,并优化显示界面,直观地反馈采集的数据,便于开发者在各种场景和环境条件下的快速应用。
硬件连接
使用 USB 转 TTL 工具连接雷达模块和电脑,接线方式如下
Rd-03 V2 序号(名称) |
USB 转 TTL 引脚 |
说明 |
1(3V3) |
3V3 |
供电 |
2(GND) |
GND |
接地 |
3(TXD) |
RXD |
数据发送端 |
4(RXD) |
TXD |
数据接收端 |
5(OT2) |
None |
检测结果(高低电平)输出 |
实物图

流程图
graph TD
A[启动网页] --> D[枚举串口列表]
D --> E[连接串口]
E --> I[启动读取循环]
I --> J{收到一行数据}
J --> L[解析距离值]
L --> M[更新当前距离]
M --> N[加入曲线缓冲区]
N --> O[绘制演化曲线]
O --> P[更新统计值]
P --> J
代码
新建 HTML 文件并添加如下代码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>雷达模块距离监控Web上位机</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.0/dist/chart.umd.min.js"></script>
<style>
:root {
--bg: linear-gradient(135deg, #1e3c72 0%, #2a5298 100%);
--glass: rgba(255, 255, 255, 0.1);
--accent: #4ade80;
}
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
font-family: Arial, sans-serif;
background: var(--bg);
color: #fff;
min-height: 100vh;
padding: 20px;
}
.container {
max-width: 1200px;
margin: auto;
background: var(--glass);
backdrop-filter: blur(10px);
border-radius: 20px;
padding: 30px;
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.37);
border: 1px solid rgba(255, 255, 255, 0.18);
}
h1 {
text-align: center;
margin-bottom: 20px;
font-size: 2.2em;
text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.3);
}
.controls {
display: flex;
gap: 20px;
flex-wrap: wrap;
justify-content: center;
margin-bottom: 20px;
}
.control-group {
display: flex;
flex-direction: column;
gap: 8px;
}
label {
font-size: 0.9em;
opacity: 0.9;
}
select, button {
padding: 8px 16px;
border: none;
border-radius: 6px;
background: rgba(255, 255, 255, 0.2);
color: #fff;
cursor: pointer;
transition: background 0.3s;
}
select:hover, button:hover {
background: rgba(255, 255, 255, 0.3);
}
button:disabled {
opacity: 0.5;
cursor: not-allowed;
}
.status {
text-align: center;
margin-bottom: 15px;
font-size: 1.1em;
}
.connected {
color: var(--accent);
}
.disconnected {
color: #f87171;
}
.panels {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 20px;
margin-bottom: 20px;
}
.panel {
background: rgba(0, 0, 0, 0.25);
border-radius: 12px;
padding: 15px;
}
.panel h2 {
font-size: 1.1em;
margin-bottom: 10px;
opacity: 0.9;
}
/* ===== 极简距离显示 ===== */
#distanceValue {
font-size: 5em;
font-weight: bold;
color: var(--accent);
text-align: center;
text-shadow: 0 0 12px var(--accent);
margin-top: 20px;
}
#curveCanvas {
max-height: 260px;
}
.stats {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
gap: 15px;
margin-bottom: 20px;
}
.stat-card {
background: var(--glass);
border-radius: 8px;
padding: 12px;
text-align: center;
}
.stat-label {
font-size: 0.85em;
opacity: 0.8;
margin-bottom: 4px;
}
.stat-value {
font-size: 1.4em;
font-weight: bold;
color: var(--accent);
}
.data-log {
background: rgba(0, 0, 0, 0.5);
border-radius: 10px;
padding: 15px;
height: 160px;
overflow-y: auto;
font-family: Courier New, monospace;
font-size: 0.85em;
}
.log-entry {
margin-bottom: 4px;
opacity: 0.8;
}
.log-entry.recent {
opacity: 1;
color: var(--accent);
}
@media (max-width: 900px) {
.panels {
grid-template-columns: 1fr;
}
}
</style>
</head>
<body>
<div class="container">
<h1>🛰️ 安信可 Rd-03 V2 雷达模块距离监控</h1>
<div class="controls">
<div class="control-group">
<label>波特率</label>
<select id="baudRate">
<option value="9600">9600</option>
<option value="19200">19200</option>
<option value="38400">38400</option>
<option value="57600">57600</option>
<option value="115200" selected>115200</option>
</select>
</div>
<div class="control-group">
<label> </label>
<button id="connectBtn" onclick="connectSerial()">连接串口</button>
</div>
<div class="control-group">
<label> </label>
<button id="disconnectBtn" onclick="disconnectSerial()" disabled>断开连接</button>
</div>
</div>
<div class="status disconnected" id="status">未连接</div>
<div class="panels">
<div class="panel">
<h2>当前距离</h2>
<div id="distanceValue">--</div>
</div>
<div class="panel">
<h2>距离演化曲线</h2>
<canvas id="curveCanvas"></canvas>
</div>
</div>
<div class="stats">
<div class="stat-card">
<div class="stat-label">平均距离</div>
<div class="stat-value" id="avgDistance">--</div>
</div>
<div class="stat-card">
<div class="stat-label">最大距离</div>
<div class="stat-value" id="maxDistance">--</div>
</div>
<div class="stat-card">
<div class="stat-label">最小距离</div>
<div class="stat-value" id="minDistance">--</div>
</div>
<div class="stat-card">
<div class="stat-label">数据计数</div>
<div class="stat-value" id="dataCount">0</div>
</div>
</div>
<div class="data-log" id="dataLog">
<div class="log-entry">等待数据…</div>
</div>
</div>
<script>
/* ================= 串口 & 业务逻辑 ================= */
let port = null, reader = null;
let dataHistory = [];
const maxLogEntries = 100;
const chartMaxPoints = 150;
function updateStatus(connected) {
const s = document.getElementById('status');
const connectBtn = document.getElementById('connectBtn');
const disconnectBtn = document.getElementById('disconnectBtn');
s.textContent = connected ? '已连接' : '未连接';
s.className = connected ? 'status connected' : 'status disconnected';
connectBtn.disabled = connected;
disconnectBtn.disabled = !connected;
}
function addLogEntry(msg, recent = false) {
const log = document.getElementById('dataLog');
const div = document.createElement('div');
div.className = recent ? 'log-entry recent' : 'log-entry';
div.textContent = `[${new Date().toLocaleTimeString()}] ${msg}`;
log.appendChild(div);
while (log.children.length > maxLogEntries) log.removeChild(log.firstChild);
log.scrollTop = log.scrollHeight;
}
function updateStats(dist) {
dataHistory.push(dist);
if (dataHistory.length > 300) dataHistory.shift();
const avg = dataHistory.reduce((a, b) => a + b, 0) / dataHistory.length;
document.getElementById('avgDistance').textContent = avg.toFixed(1) + ' mm';
document.getElementById('maxDistance').textContent = Math.max(...dataHistory) + ' mm';
document.getElementById('minDistance').textContent = Math.min(...dataHistory) + ' mm';
document.getElementById('dataCount').textContent = dataHistory.length;
}
/* ================= 曲线 ================= */
const ctx = document.getElementById('curveCanvas').getContext('2d');
const chart = new Chart(ctx, {
type: 'line',
data: {
labels: [],
datasets: [{
label: '距离 mm',
data: [],
borderColor: '#4ade80',
backgroundColor: 'rgba(74,222,128,0.15)',
tension: 0.25,
fill: true,
pointRadius: 0,
borderWidth: 2
}]
},
options: {
responsive: true,
maintainAspectRatio: false,
animation: false,
scales: {
x: { title: { display: false }, ticks: { color: '#fff' }, grid: { color: 'rgba(255,255,255,0.15)' } },
y: { title: { display: false }, ticks: { color: '#fff' }, grid: { color: 'rgba(255,255,255,0.15)' } }
},
plugins: { legend: { display: false } }
}
});
let sampleID = 0;
function addCurvePoint(dist) {
sampleID++;
chart.data.labels.push(sampleID);
chart.data.datasets[0].data.push(dist);
if (chart.data.labels.length > chartMaxPoints) {
chart.data.labels.shift();
chart.data.datasets[0].data.shift();
}
chart.update();
}
/* ================= 串口读写 ================= */
async function connectSerial() {
try {
port = await navigator.serial.requestPort();
const baud = parseInt(document.getElementById('baudRate').value);
await port.open({ baudRate: baud });
updateStatus(true);
addLogEntry(`串口已连接,波特率: ${baud}`);
readLoop();
} catch (e) {
addLogEntry(`连接失败: ${e.message}`);
}
}
async function disconnectSerial() {
if (reader) { await reader.cancel(); reader = null; }
if (port) { await port.close(); port = null; }
updateStatus(false);
addLogEntry('串口已断开');
}
async function readLoop() {
const decoder = new TextDecoderStream();
port.readable.pipeTo(decoder.writable);
reader = decoder.readable.getReader();
let buf = '';
while (true) {
const { value, done } = await reader.read();
if (done) break;
buf += value;
const lines = buf.split('\n');
buf = lines.pop();
for (const ln of lines) {
const str = ln.trim();
if (str.startsWith('distance:')) {
const dist = parseInt(str.substring(9));
if (!isNaN(dist)) {
document.getElementById('distanceValue').textContent = dist + ' mm';
updateStats(dist);
addCurvePoint(dist);
addLogEntry(`收到距离: ${dist} mm`, true);
}
}
}
}
reader.releaseLock();
}
/* ================= 串口枚举 ================= */
async function getPorts() {
if (!('serial' in navigator)) return;
const ports = await navigator.serial.getPorts();
const sel = document.getElementById('portSelect');
sel.innerHTML = '<option value="">请选择串口</option>';
ports.forEach((p, i) => {
const opt = document.createElement('option');
opt.value = i;
opt.textContent = `串口 ${i + 1}`;
sel.appendChild(opt);
});
}
window.addEventListener('load', () => {
getPorts();
setInterval(getPorts, 5000);
});
window.addEventListener('beforeunload', disconnectSerial);
</script>
</body>
</html>
效果
- 使用 USB 转 TTL 工具连接雷达模块和电脑;
- 点击网页上方的
连接串口
按钮,弹出设备端口选项窗口,选择目标设备并连接;


总结
本文介绍了安信可 Rd-03 V2 雷达模组通过网页上位机实现距离监控的项目设计,包括硬件连接、流程图、代码和效果演示等,为相关产品的开发设计和快速应用提供了参考。