news 2026/5/29 0:50:22

自创的机械臂新算法,因为是AI写的,暂时,并不智能,但目前支持任何段数

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
自创的机械臂新算法,因为是AI写的,暂时,并不智能,但目前支持任何段数

<!DOCTYPE html>

<html lang="zh-CN">

<head>

<meta charset="UTF-8">

<title>三段机械臂抓取演示</title>

<style>

body { margin: 0; display: flex; flex-direction: column; align-items: center; background: #f0f0f0; }

#canvas { background: #fff; border: 2px solid #333; }

.controls { margin: 10px 0; display: flex; gap: 10px; align-items: center; flex-wrap: wrap; }

.arm-config { display: flex; gap: 10px; align-items: center; margin-bottom: 5px; }

input { width: 80px; padding: 5px; }

button { padding: 5px 15px; cursor: pointer; }

#tip { color: red; margin-top: 5px; }

</style>

</head>

<body>

<canvas id="canvas" width="800" height="600"></canvas>

<!-- 新增机械臂配置控件 -->

<div class="arm-config">

<label>机械臂段数: <input type="number" id="armSegments" value="3" min="1" max="5" step="1"></label>

<label>角度最小值(弧度): <input type="number" id="angleMin" value="0" min="0" max="6.28" step="0.1"></label>

<label>角度最大值(弧度): <input type="number" id="angleMax" value="1.57" min="0" max="6.28" step="0.1"></label>

<button id="applyConfig">应用配置</button>

</div>

<div class="controls">

<label>缩臂速度: <input type="number" id="shrinkSpeed" value="0.1" min="0.1" max="2" step="0.1"></label>

<label>缓伸速度: <input type="number" id="extendSpeed" value="0.1" min="0.1" max="1" step="0.1"></label>

<button id="startBtn">开始抓取</button>

<button id="stopBtn">停止</button>

</div>

<div id="tip"></div>

<script>

const canvas = document.getElementById('canvas');

const ctx = canvas.getContext('2d');

const [W, H] = [canvas.width, canvas.height];

const center = { x: W/2, y: H/2 };

let target = null;

let isRunning = false;

let currentPhase = 'shrink';

let arm = {

len: [120, 100, 80],

angle: [Math.random()*Math.PI/2, Math.random()*Math.PI/2, Math.random()*Math.PI/2],

joint: [{}, {}, {}, {}]

};

// 原算法: 积分函数 o()

function F(x, k) { return 1 + Math.pow(x, k) + x; }

function o(eq, a, b, d=0.1, K=5) {

const g = new Function('x', `return ${eq};`);

let s = [[a, b]], r = 0.0;

while (s.length > 0) {

let n = [];

for (let [x0, x1] of s) {

const dx = x1 - x0;

if (dx < d) {

const m = (x0 + x1)/2;

const m_scaled = m/(2*Math.PI);

const f_values = Array.from({length:K}, (_,k) => F(m_scaled, k+1));

let W = 0.0, V = 0.0;

const g_m = g(m);

for (let k = 0; k < K; k++) {

const w = 1/(f_values[k] + 1e-12);

W += w; V += w * g_m;

}

r += dx * (W ? V/W : g_m);

continue;

}

const u = g(x0), v = g(x1), mid = (x0+x1)/2, mv = g(mid);

if (Math.abs(u-v) < 1e-8 && Math.abs(mv-u) < 1e-8) {

r += dx * mv; continue;

}

const h = dx/10;

for (let i = 0; i < 10; i++) n.push([x0+i*h, x0+(i+1)*h]);

}

s = n;

}

return r;

}

// 原算法: 排序函数 f()

function c(seg) { let cnt = 0; for (let i=0;i<seg.length;i++) for(let j=i+1;j<seg.length;j++) if(seg[i]>seg[j]) cnt++; return cnt; }

function w(arr, wa) {

let a = [...arr], n = a.length;

if (n <=1) return a;

const exp_wa = Array.from({length:n}, (_,i) => Math.pow(wa, i+1));

for (let i=0;i<n;i++) {

let swapped = false;

for (let j=0;j<n-i-1;j++) {

const v1 = a[j]*(1 + wa + exp_wa[j]);

const v2 = a[j+1]*(1 + wa + exp_wa[j+1]);

if (Math.abs(v1-v2) <1e-8) {

const eq = `${a[j]}*x - ${a[j+1]}*x`;

const r = o(eq, 0, 1);

if (r>0) { [a[j],a[j+1]] = [a[j+1],a[j]]; swapped=true; }

} else if (v1>v2) { [a[j],a[j+1]] = [a[j+1],a[j]]; swapped=true; }

}

if (!swapped) break;

}

return a;

}

function f(arr) {

let n = arr.length;

if (n<=1) return [...arr];

let segs = [], i=0;

while (i < n) {

let l=1;

while (i+l <n && arr[i+l]>=arr[i+l-1]) l++;

const s = arr.slice(i, i+l);

const r = l>1 ? c(s)/(l-1) : 0;

segs.push({s, r});

i += l;

}

let n_segs = [];

for (let {s, r} of segs) {

if (r>0 && s.length>1) {

const avg = s.reduce((a,b)=>a+b)/s.length;

const wa_sum = Array.from({length:20}, (_,k) => 1/(F(avg, k+1)+1e-12)).reduce((a,b)=>a+b);

n_segs.push({s:w(s, wa_sum), r: c(w(s, wa_sum))/(s.length-1)});

} else n_segs.push({s, r});

}

return n_segs.flatMap(item => item.s);

}

// 机械臂关节坐标计算 - 适配任意段数

function updateArmJoint() {

let [x, y] = [center.x, center.y];

arm.joint = [];

arm.joint.push({x, y});

for (let i=0; i<arm.len.length; i++) {

x += arm.len[i] * Math.cos(arm.angle[i]);

y += arm.len[i] * Math.sin(arm.angle[i]);

arm.joint.push({x, y});

}

}

// 速度归一化

function normalizeSpeed(speed) {

return Math.max(0.1, Math.min(speed, 2)) * 0.01;

}

// 缩臂阶段

function shrinkArm() {

if (!target) return false;

const end = arm.joint[arm.joint.length - 1];

const dx = target.x - end.x;

const dy = target.y - end.y;

const dist = Math.hypot(dx, dy);

if (dist < 5) { currentPhase = 'extend'; return true; }

const eq = `Math.hypot(x*Math.cos(${arm.angle[arm.angle.length-1]}) - ${dx}, x*Math.sin(${arm.angle[arm.angle.length-1]}) - ${dy})`;

const delta = o(eq, -0.5, 0.5);

const speed = normalizeSpeed(Number(document.getElementById('shrinkSpeed').value));

// 差异化角度更新 - 适配任意段数

arm.angle = arm.angle.map((ang, idx) => {

const ratio = idx === 0 ? 1.2 : idx === arm.angle.length-1 ? 1 : 0.8;

return ang + delta * speed * ratio;

});

return dist > 20;

}

// 缓伸阶段

function extendArm() {

if (!target) return false;

const end = arm.joint[arm.joint.length - 1];

const points = Array.from({length:10}, (_,i) => Math.hypot(end.x - target.x + i, end.y - target.y + i));

const sortedPoints = f(points);

const avgDist = sortedPoints.reduce((a,b)=>a+b)/sortedPoints.length;

const speed = normalizeSpeed(Number(document.getElementById('extendSpeed').value));

// 杆长和角度更新 - 适配任意段数

arm.len = arm.len.map(l => l + (avgDist < 10 ? -speed*2 : speed));

arm.angle = arm.angle.map(ang => ang + speed * 0.5);

return Math.hypot(end.x - target.x, end.y - target.y) > 3;

}

// 绘制 - 适配任意段数

function draw() {

ctx.clearRect(0, 0, W, H);

if (target) {

ctx.fillStyle = 'blue';

ctx.beginPath();

ctx.arc(target.x, target.y, 10, 0, 2*Math.PI);

ctx.fill();

}

updateArmJoint();

ctx.strokeStyle = '#333';

ctx.lineWidth = 8;

for (let i=0; i<arm.joint.length-1; i++) {

const p1 = arm.joint[i];

const p2 = arm.joint[i+1];

ctx.beginPath();

ctx.moveTo(p1.x, p1.y);

ctx.lineTo(p2.x, p2.y);

ctx.stroke();

}

ctx.fillStyle = 'red';

ctx.beginPath();

ctx.arc(arm.joint[arm.joint.length-1].x, arm.joint[arm.joint.length-1].y, 5, 0, 2*Math.PI);

ctx.fill();

}

// 动画循环

function animate() {

if (!isRunning) return;

let keepRunning = true;

if (currentPhase === 'shrink') {

keepRunning = shrinkArm();

} else if (currentPhase === 'extend') {

keepRunning = extendArm();

}

if (!keepRunning) {

isRunning = false;

document.getElementById('tip').textContent = keepRunning ? '' : '抓取完成/未抓到目标,请重新放置';

}

draw();

requestAnimationFrame(animate);

}

// 应用机械臂配置

function applyArmConfig() {

const segments = parseInt(document.getElementById('armSegments').value);

const angleMin = parseFloat(document.getElementById('angleMin').value);

const angleMax = parseFloat(document.getElementById('angleMax').value);

if (angleMin >= angleMax) {

document.getElementById('tip').textContent = '角度最小值必须小于最大值';

return;

}

// 生成对应段数的长度和角度

arm.len = Array.from({length: segments}, (_, i) => 120 - i*20);

arm.angle = Array.from({length: segments}, () => angleMin + Math.random()*(angleMax - angleMin));

document.getElementById('tip').textContent = '';

draw();

}

// 事件监听

canvas.addEventListener('click', (e) => {

const rect = canvas.getBoundingClientRect();

target = {

x: e.clientX - rect.left,

y: e.clientY - rect.top

};

document.getElementById('tip').textContent = '';

draw();

});

document.getElementById('startBtn').addEventListener('click', () => {

if (!target) {

document.getElementById('tip').textContent = '请先点击画布放置目标物体';

return;

}

isRunning = true;

currentPhase = 'shrink';

animate();

});

document.getElementById('stopBtn').addEventListener('click', () => {

isRunning = false;

document.getElementById('tip').textContent = '已停止';

});

document.getElementById('applyConfig').addEventListener('click', applyArmConfig);

// 初始绘制

updateArmJoint();

draw();

</script>

</body>

</html>

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/28 13:21:56

USB转串口驱动安装新手教程:从下载到配置全流程

从零搞定USB转串口通信&#xff1a;CH340与CP2102驱动安装全解析 你有没有遇到过这样的场景&#xff1f;手里的开发板插上电脑后&#xff0c;设备管理器里只显示“未知设备”&#xff0c;串口助手打不开COM口&#xff0c;调试信息出不来——明明线都接对了&#xff0c;却卡在第…

作者头像 李华
网站建设 2026/5/28 23:09:58

基于Python+大数据+SSM新能源汽车数据分析系统(源码+LW+调试文档+讲解等)/新能源车数据平台/电动汽车数据分析/新能源车辆数据系统/新能源汽车数据研究/新能源车辆信息分析系统

博主介绍 &#x1f497;博主介绍&#xff1a;✌全栈领域优质创作者&#xff0c;专注于Java、小程序、Python技术领域和计算机毕业项目实战✌&#x1f497; &#x1f447;&#x1f3fb; 精彩专栏 推荐订阅&#x1f447;&#x1f3fb; 2025-2026年最新1000个热门Java毕业设计选题…

作者头像 李华
网站建设 2026/5/28 19:56:19

LangFlow养生食谱个性化推荐引擎

LangFlow养生食谱个性化推荐引擎 在健康管理日益智能化的今天&#xff0c;用户不再满足于千篇一律的饮食建议。他们希望获得真正“懂自己”的营养指导——比如根据体质、节气甚至情绪状态&#xff0c;推荐一道温补又不燥热的汤品。然而&#xff0c;构建这样一套融合中医理论与大…

作者头像 李华
网站建设 2026/5/28 0:20:18

ESP32 IDF Wi-Fi连接+HTTP请求完整示例

从零开始&#xff1a;用 ESP-IDF 实现 ESP32 的 Wi-Fi 联网与 HTTP 数据交互 你有没有遇到过这样的场景&#xff1f;手头有一块 ESP32&#xff0c;想让它把传感器数据上传到云端 API&#xff0c;却发现连最基本的“连上 Wi-Fi 发个 HTTP 请求”都卡住了——不是连不上网络&…

作者头像 李华
网站建设 2026/5/28 12:44:56

【API 设计之道】08 流量与配额:构建基于 Redis 的分布式限流器

大家好&#xff0c;我是Tony Bai。欢迎来到我们的专栏 《API 设计之道&#xff1a;从设计模式到 Gin 工程化实现》的第八讲。在上一讲中&#xff0c;我们给 API 穿上了“防弹衣”&#xff0c;通过幂等性设计防止了重复请求的数据污染。今天&#xff0c;我们要给 API 装上“红绿…

作者头像 李华
网站建设 2026/5/27 18:13:23

LangFlow灯谜创作助手实现过程

LangFlow灯谜创作助手实现过程 在人工智能加速渗透创意领域的今天&#xff0c;一个有趣的问题浮现出来&#xff1a;我们能否让大模型不仅“会答题”&#xff0c;还能“出题”&#xff1f;比如&#xff0c;让它像古人一样&#xff0c;为“中秋赏月”拟一则意境悠远的灯谜&#x…

作者头像 李华