用javascript写了一个机械臂数据仿真效果
前言:
前段时间在网上看到网友用单片机制作了一个写字机器人,我想了想应该不太难,于是就有了这个。
先上效果图:
机械臂的运动空间(初等数学计算):
如图所示,是一个平面的机械臂实现,以机械臂的原点建立笛卡尔直角坐标系,那么机械臂的末端执行机构的坐标就可以用下列两个方程组来表示:
此方程可以实现通过电机的运转角度来得到末端执行机构的精确位置坐标 。
但在实际情况下这个方程组的运用场景十分有限。因为往往对于机械臂的角度没有太大的要求和限制其运动空间。
实际运用往往都是驱动步进电机的步进角度来实现控制机械臂的输出位移,利用这组公式就得通过映射的办法来查询,
所以我就把他求了个逆向解,将角度1和角度2显化,结果得到一对4次方程组,显化过程也比较复杂。下面是显化结果。
这个公式是比较复杂的,本来想把它像上面的函数一样把它可视化显示出来的,但是没找到好的工具。
代码实现:
本例采用了html5的canvas画布来一帧一帧的绘制,基于h5的游戏几乎都是采用这种方法来搞的,
编写了一些函数来方便绘图:
画圆:
画线:
循环(vue 框架双向数据绑定):
本例是没有编写循环函数的,利用了vue框架的双向数据绑定特性,把canvas上绘图所需要的数据放在vue里面,当数据改变时,canvas就会自动重绘。
源码:
1 var app = new Vue({ 2 el: '#app', 3 data: { 4 x: 10, 5 y: 10, 6 t1: 0, 7 t2: 0, 8 x1: 0, 9 y1: 0, 10 x2: 0, 11 y2: 0, 12 li: [] 13 }, 14 mounted: function () { 15 this.run() 16 }, 17 18 methods: { 19 run: function () { 20 //绘图s 21 function ctx_Write(X = X, Y = Y, R = R, colour = "#FF0000") { 22 ctx.beginPath() 23 ctx.fillStyle = colour; 24 ctx.arc(X, Y, R, 0, 360); 25 ctx.fill() 26 ctx.closePath() 27 } 28 29 function lin_Write(x = x, y = y, X = X, Y = Y, b = b, colour = "#FF0000") { 30 ctx.beginPath() 31 ctx.moveTo(x, y); //设置起点状态 32 ctx.lineTo(X, Y); //设置末端状态 33 ctx.lineWidth = b; //设置线宽状态 34 ctx.strokeStyle = colour; //设置线的颜色状态 35 ctx.stroke(); 36 ctx.closePath() 37 38 } 39 qx = 100 40 qy = 100 41 l1 = 150; 42 l2 = 150; 43 //数学表达式,四次方程组 44 t1 = Math.asin((l2 * Math.sin(2 * Math.atan((2 * l2 * this.y - Math.sqrt(-1 * l1 ** 4 + 2 * l1 ** 2 * l2 ** 2 + 2 * l1 ** 2 * this.x ** 2 + 2 * l1 ** 2 * this.y ** 2 - l2 ** 4 + 2 * l2 ** 2 * this.x ** 2 + 2 * l2 ** 2 * this.y ** 2 - this.x ** 4 - 2 * this.x ** 2 * this.y ** 2 - this.y ** 4)) / (-1 * l1 ** 2 + l2 ** 2 + 2 * l2 * this.x + this.x ** 2 + this.y ** 2))) - this.y) / l1) + 3.1415926; 45 t2 = 2 * Math.atan((2 * l2 * this.y - Math.sqrt(-1 * l1 ** 4 + 2 * l1 ** 2 * l2 ** 2 + 2 * l1 ** 2 * this.x ** 2 + 2 * l1 ** 2 * this.y ** 2 - l2 ** 4 + 2 * l2 ** 2 * this.x ** 2 + 2 * l2 ** 2 * this.y ** 2 - this.x ** 4 - 2 * this.x ** 2 * this.y ** 2 - this.y ** 4)) / (-1 * l1 ** 2 + l2 ** 2 + 2 * l2 * this.x + this.x ** 2 + this.y ** 2)); 46 47 this.t1 = t1 48 this.t2 = t2 49 //console.log("..............") 50 //console.log(t1) 51 //console.log(t2) 52 var canvas = document.getElementById("myCanvas"); 53 var ctx = canvas.getContext("2d"); 54 canvas.width = 400; 55 canvas.height = 400; 56 canvas.style = "border:5px solid #000000;"; 57 // //console.log(this.x) 58 // 画第一臂 59 x1 = l1 * Math.cos(t1) + qx 60 y1 = l1 * Math.sin(t1) + qy 61 this.x1 = x1 62 this.y1 = y1 63 //console.log(x1, y1) 64 65 lin_Write(0, qx, 500, qy, 1)//画x轴 66 67 lin_Write(qx, 0, qy, 500, 1, " #0000FF")//画y轴 68 69 lin_Write(100, 100, x1, y1, 5, " #FFFF00") 70 // 画第1臂 71 72 x2 = l2 * Math.cos(t2) + x1 73 y2 = l2 * Math.sin(t2) + y1 74 this.li.push([x2, y2]) 75 if (this.li.length > 500) { 76 this.li.splice(0, 1) 77 } 78 //console.log(this.li) 79 for (var o = 0; o < this.li.length; o++) { 80 ctx_Write(X = this.li[o][0], Y = this.li[o][1], R = 1, colour = "#FF0000") 81 //画轨迹 82 } 83 84 this.x2 = x2 85 this.y2 = y2 86 87 lin_Write(x1, y1, x2, y2, 5, " #000000")//画关节臂 88 89 //console.log() 90 91 ctx_Write(x1, y1, 10, "#FF0000")//画第一关节点 92 93 ctx_Write(100, 100, 10, "#FF0000")//画起点 94 95 ctx_Write(x2, y2, 10, "#FF0000")//画第二关节点 96 } 97 } 98 99 })
我的github地址:
https://github.com/1019157263