增加机器人奇异点检测

This commit is contained in:
zhangshun
2026-06-16 12:56:26 +08:00
parent a100e44ac0
commit 0c7dc9e05b
8 changed files with 327 additions and 15 deletions

View File

@@ -420,6 +420,9 @@
<div id="joint-controls"></div>
<div class="actions">
<button id="fk-btn" type="button">正解</button>
<button id="singularity-btn" class="secondary" type="button">
奇异点
</button>
<button id="target-current-btn" class="secondary" type="button">
取当前位姿
</button>
@@ -492,6 +495,10 @@
<span class="metric-label">关节数</span>
<span class="metric-value" id="joint-count-value">0</span>
</div>
<div class="metric">
<span class="metric-label">奇异风险</span>
<span class="metric-value" id="singularity-value">-</span>
</div>
<div class="metric">
<span class="metric-label">three.js</span>
<span class="metric-value">0.184.0</span>
@@ -546,11 +553,13 @@
targetQw: document.getElementById("target-qw"),
tcpValue: document.getElementById("tcp-value"),
jointCountValue: document.getElementById("joint-count-value"),
singularityValue: document.getElementById("singularity-value"),
toast: document.getElementById("toast"),
initBtn: document.getElementById("init-btn"),
registerUrdfBtn: document.getElementById("register-urdf-btn"),
resetBtn: document.getElementById("reset-btn"),
fkBtn: document.getElementById("fk-btn"),
singularityBtn: document.getElementById("singularity-btn"),
ikBtn: document.getElementById("ik-btn"),
applyIkBtn: document.getElementById("apply-ik-btn"),
targetCurrentBtn: document.getElementById("target-current-btn"),
@@ -731,6 +740,20 @@
};
}
// 生成奇异点检测请求。
function buildSingularityRequest() {
return {
msg: "threejs singularity check",
req_code: `THREE_SINGULARITY_${Date.now()}`,
req_from: "threejs_test",
req_cmd: "Cmd_Kinematics_check_singularity",
req_param: {
robot_uuid: elements.robotUuid.value.trim(),
joints_str: buildJointString(),
},
};
}
// 生成逆解请求。
function buildInverseRequest() {
const pose = [
@@ -883,6 +906,27 @@
}
}
// 执行奇异点检测并显示风险等级。
async function runSingularityCheck() {
await ensureInitialized();
setBusy(true, "奇异点检测中");
const request = buildSingularityRequest();
try {
renderJson(request, null);
const response = await api.processBusinessRequest(request);
renderJson(request, response);
updateSingularityMetric(response?.res_data);
const ok = response.success && response.res_data?.success;
setStatus(ok ? "奇异点检测完成" : "奇异点检测失败", Boolean(ok));
} catch (error) {
showError(error);
} finally {
setBusy(false);
}
}
// 执行逆解并保存待应用的关节解。
async function runInverseKinematics() {
await ensureInitialized();
@@ -1114,6 +1158,22 @@
}
}
// 更新奇异点风险指标。
function updateSingularityMetric(result) {
if (!result?.success) {
elements.singularityValue.textContent = "-";
return;
}
const riskText = {
normal: "正常",
warning: "接近",
singular: "奇异",
}[result.risk_level] ?? result.risk_level;
const minSv = Number(result.min_singular_value);
elements.singularityValue.textContent = `${riskText} / ${Number.isFinite(minSv) ? minSv.toExponential(2) : "-"}`;
}
// 设置按钮忙碌状态。
function setBusy(isBusy, label) {
[
@@ -1121,6 +1181,7 @@
elements.registerUrdfBtn,
elements.resetBtn,
elements.fkBtn,
elements.singularityBtn,
elements.ikBtn,
elements.targetCurrentBtn,
].forEach((button) => {
@@ -1188,6 +1249,7 @@
elements.registerUrdfBtn.addEventListener("click", registerUrdfFromFile);
elements.resetBtn.addEventListener("click", resetJoints);
elements.fkBtn.addEventListener("click", runForwardKinematics);
elements.singularityBtn.addEventListener("click", runSingularityCheck);
elements.ikBtn.addEventListener("click", runInverseKinematics);
elements.applyIkBtn.addEventListener("click", applyInverseSolution);
elements.targetCurrentBtn.addEventListener("click", updateTcpTargetFromCurrent);