好久没玩机械了,斯坦福大学的开源四足机器人项目“Stanford Doggo”成功地引起了我的兴趣。它的腿部结构有别于传统的开链结构,这激发了小瓦进一步探索的欲望。 ——聪明的瓦肯人
说大胆把玩 当然是要强迫她 按照我的意思 摆出我喜欢的体位 走出我侧目的步调 扭出我满意的身姿
so LET‘S GOOOO! 1 我们先来看看这只四足是怎么回事 作为一款开源作品 自然是被我找到了模型 总体样子就如封面所示
再来看看复杂的动力源部分
用了两条同步齿形带 两个原动机 还有一个三角支架 用来抵抗皮带张紧力带来的弯矩 在张紧力的方向 类似于将悬臂梁转为简支梁 保持了皮带张力
分解之后零件倒是不少 不过很多都是螺钉螺母
总体来说 机械结构并不复杂 腿部机构是 双曲柄五连杆机构 铰链连接 单腿自由度为2 这个五连杆很特殊 团队使用了同轴结构 这也是整个机器最复杂部分
巧妙的同轴结构使结构更紧凑 更一般的五连杆应该是下面这样
实际上 斯坦福团队在doggo的介绍视频中 有一个天大的笑话
enmmmmm 这位小姐姐一定是斯坦福的宣传委员 这字幕可不是乱加的哦! 难道美国人对连杆机构的定义 与咱中国人不一样?
2 逼叨完了 是时候开干了 团队小哥Nathan Kau 最引以为豪的事 就是该项目没有做任何仿真 一切都在现实环境下调试 不得不说
把开源模型以STP格式导入UG 我的陈年老电脑花了 6、7分钟才加载完毕 之后又是一顿猛删 去除不必要零件后 又以STL格式导出 再将STL模型导入V-rep 在V-rep中又是一顿实体化 添加关节 设置动力学参数 最后还搭建了单腿结构场景 用于单腿实验
就这么慢慢地的实验 夹杂着之前对切比雪夫四足的理解 最后有所成功 切比雪夫机构就是曲柄摇杆机构 基于切比雪夫机构的四足之前我就做过
话不多说 最后就来献丑了 先来看看doggo的表现
原地跳跃
听说能达到60cm nice! 我也稍微做了一个仿真
最开始想通过python脚本远程控制 奈何V-rep与python总是通信失败 只好使用自带的Lua脚本语言了 这又花了一段时间自学了Lua 不过好歹最后成功了 你或许发现了机身的旋转 若是细看 这是左右腿结构不对称导致的 Doggo团队建装配图的小哥怕是睡着了 送上代码
代码语言:javascript复制require "math"
if (sim_call_type==sim_childscriptcall_initialization) then
motorHandle=simGetObjectHandle("Revolute_joint") --取得关节句柄
motorHandle0=simGetObjectHandle("Revolute_joint0")
motorHandle1=simGetObjectHandle("Revolute_joint1")
motorHandle2=simGetObjectHandle("Revolute_joint2")
motorHandle3=simGetObjectHandle("Revolute_joint3")
motorHandle4=simGetObjectHandle("Revolute_joint4")
motorHandle5=simGetObjectHandle("Revolute_joint5")
motorHandle6=simGetObjectHandle("Revolute_joint6")
targetPosition1=simGetJointPosition(motorHandle1) --获取关节位置
targetPosition2=simGetJointPosition(motorHandle2)
if (math.abs(targetPosition2)<0.01 and math.abs(targetPosition1)<0.01) then
simSetJointTargetPosition(motorHandle1,-1.5) --设置关节位置
simSetJointTargetPosition(motorHandle2,1.1)
simSetJointTargetPosition(motorHandle5,1.1)
simSetJointTargetPosition(motorHandle6,-1.5)
simSetJointTargetPosition(motorHandle0,0.9)
simSetJointTargetPosition(motorHandle3,0.9)
simSetJointTargetPosition(motorHandle,-1.7)
simSetJointTargetPosition(motorHandle4,-1.7)
end
end
if (sim_call_type==sim_childscriptcall_actuation) then
targetPosition=simGetJointPosition(motorHandle)
targetPosition0=simGetJointPosition(motorHandle0)
targetPosition1=simGetJointPosition(motorHandle1)
targetPosition2=simGetJointPosition(motorHandle2)
targetPosition3=simGetJointPosition(motorHandle3)
targetPosition4=simGetJointPosition(motorHandle4)
targetPosition5=simGetJointPosition(motorHandle5)
targetPosition6=simGetJointPosition(motorHandle6)
if (math.abs(targetPosition1 1.5)<0.01 and math.abs(targetPosition4 1.7)<0.01) then
simSetJointTargetPosition(motorHandle1,0.5)
simSetJointTargetPosition(motorHandle2,-0.9)
simSetJointTargetPosition(motorHandle5,-0.9)
simSetJointTargetPosition(motorHandle6,0.5)
simSetJointTargetPosition(motorHandle0,-1.1)
simSetJointTargetPosition(motorHandle3,-1.1)
simSetJointTargetPosition(motorHandle,0.3)
simSetJointTargetPosition(motorHandle4,0.3)
end
if (math.abs(targetPosition1-0.5)<0.01 and math.abs(targetPosition4-0.3)<0.01) then
simSetJointTargetPosition(motorHandle1,-0.5)
simSetJointTargetPosition(motorHandle2,0.1)
simSetJointTargetPosition(motorHandle5,0.1)
simSetJointTargetPosition(motorHandle6,-0.5)
simSetJointTargetPosition(motorHandle0,-0.1)
simSetJointTargetPosition(motorHandle3,-0.1)
simSetJointTargetPosition(motorHandle,-0.7)
simSetJointTargetPosition(motorHandle4,-0.7)
end
end
if (sim_call_type==sim_childscriptcall_sensing) then
-- Put your main SENSING code here
end
if (sim_call_type==sim_childscriptcall_cleanup) then
-- Put some restoration code here
end
这就是子程序代码
非常的easy 都是在调用函数 实际上程序内联PID程序 这里不显示 如果想更改速度 就去改比例控制参数P即可 OK!下一个!
对角线步态行走 没问题
显而易见 对角线步态 有一个静不安定过程 在不添加IMU测姿的情况下 要想尽可能保持平稳 就得合理分配质量 说白了机身的重心要与 触地四点对角线中心重合 除此之外 处理好追求速度与步态幅度的关系 过长的对角线双腿滞空时间 给机身倾斜带来了机会 其结果就是小碎步 当腿在“工进”的时候 也就是推动机身往前时 2个触地点距离机身的位置尽量变化小 这样机身摆动幅度较小 这个准则几乎所有足类机器通用 就如下面的Jansen Walker连杆机构的轨迹
当然 如果加装了IMU测姿反馈 自然就可以控制电机带动机身平衡 代码如下
代码语言:javascript复制require "math"
if (sim_call_type==sim_childscriptcall_initialization) then
motorHandle=simGetObjectHandle("Revolute_joint")
motorHandle0=simGetObjectHandle("Revolute_joint0")
motorHandle1=simGetObjectHandle("Revolute_joint1")
motorHandle2=simGetObjectHandle("Revolute_joint2")
motorHandle3=simGetObjectHandle("Revolute_joint3")
motorHandle4=simGetObjectHandle("Revolute_joint4")
motorHandle5=simGetObjectHandle("Revolute_joint5")
motorHandle6=simGetObjectHandle("Revolute_joint6")
targetPosition1=simGetJointPosition(motorHandle1)
targetPosition2=simGetJointPosition(motorHandle2)
if (math.abs(targetPosition2)<0.01 and math.abs(targetPosition1)<0.01) then
simSetJointTargetPosition(motorHandle1,-0.5)
simSetJointTargetPosition(motorHandle2,0.1)
simSetJointTargetPosition(motorHandle5,0.1)
simSetJointTargetPosition(motorHandle6,-0.5)
simSetJointTargetPosition(motorHandle0,-0.1)
simSetJointTargetPosition(motorHandle3,-0.1)
simSetJointTargetPosition(motorHandle,-0.7)
simSetJointTargetPosition(motorHandle4,-0.7)
end
end
if (sim_call_type==sim_childscriptcall_actuation) then
targetPosition=simGetJointPosition(motorHandle)
targetPosition0=simGetJointPosition(motorHandle0)
targetPosition1=simGetJointPosition(motorHandle1)
targetPosition2=simGetJointPosition(motorHandle2)
targetPosition3=simGetJointPosition(motorHandle3)
targetPosition4=simGetJointPosition(motorHandle4)
targetPosition5=simGetJointPosition(motorHandle5)
targetPosition6=simGetJointPosition(motorHandle6)
if (math.abs(targetPosition1 0.5)<0.01 and math.abs(targetPosition4 0.7)<0.01) then
simSetJointTargetPosition(motorHandle0,0.8)
simSetJointTargetPosition(motorHandle5,0.6)
simSetJointTargetPosition(motorHandle,-0.5)
simSetJointTargetPosition(motorHandle6,-0.4)
simSetJointTargetPosition(motorHandle1,-0.8)
simSetJointTargetPosition(motorHandle2,-0.3)
simSetJointTargetPosition(motorHandle3,-0.4)
simSetJointTargetPosition(motorHandle4,-0.8)
end
if (math.abs(0.4 targetPosition6)<0.01 and math.abs(0.8-targetPosition0)<0.01) then
simSetJointTargetPosition(motorHandle0,-0.1)
simSetJointTargetPosition(motorHandle5,0.1)
simSetJointTargetPosition(motorHandle,-0.7)
simSetJointTargetPosition(motorHandle6,-0.5)
end
if (math.abs(targetPosition0 0.1)<0.01 and math.abs(targetPosition 0.7)<0.01) then
simSetJointTargetPosition(motorHandle0,-0.4)
simSetJointTargetPosition(motorHandle,-0.8)
simSetJointTargetPosition(motorHandle5,-0.3)
simSetJointTargetPosition(motorHandle6,-0.8)
simSetJointTargetPosition(motorHandle2,0.4)
simSetJointTargetPosition(motorHandle3,1.1)
simSetJointTargetPosition(motorHandle1,-0.5)
simSetJointTargetPosition(motorHandle4,-0.3)
end
if (math.abs(targetPosition4 0.3)<0.01 and math.abs(0.4-targetPosition2)<0.01) then
simSetJointTargetPosition(motorHandle2,0.1)
simSetJointTargetPosition(motorHandle3,-0.1)
simSetJointTargetPosition(motorHandle1,-0.5)
simSetJointTargetPosition(motorHandle4,-0.7)
end
end
if (sim_call_type==sim_childscriptcall_sensing) then
-- Put your main SENSING code here
end
if (sim_call_type==sim_childscriptcall_cleanup) then
-- Put some restoration code here
end
Next!
大家或许发现 这似乎不是Doggo 是的,这不是 这是Ghost Robotics的Minitaur 其腿部结构与Doggo类似 所以我也做了立定跳远
跳远向前的力 主要由蹬腿带来 同时 蹬腿之前腿向后摞 底面摩擦力提供了初始向前加速度 理论上应该是静摩擦 实际上由于摩擦力不足 最终变成了动摩擦 而且触地时间,距离极短
立定跳远高度为12.75cm 跳远距离为51.64cm 差不多一个身位
一样的,也将放上代码
代码语言:javascript复制require "math"
if (sim_call_type==sim_childscriptcall_initialization) then
motorHandle=simGetObjectHandle("Revolute_joint")
motorHandle0=simGetObjectHandle("Revolute_joint0")
motorHandle1=simGetObjectHandle("Revolute_joint1")
motorHandle2=simGetObjectHandle("Revolute_joint2")
motorHandle3=simGetObjectHandle("Revolute_joint3")
motorHandle4=simGetObjectHandle("Revolute_joint4")
motorHandle5=simGetObjectHandle("Revolute_joint5")
motorHandle6=simGetObjectHandle("Revolute_joint6")
targetPosition1=simGetJointPosition(motorHandle1)
targetPosition2=simGetJointPosition(motorHandle2)
if (math.abs(targetPosition2)<0.01 and math.abs(targetPosition1)<0.01) then
simSetJointTargetPosition(motorHandle1,-1.9)
simSetJointTargetPosition(motorHandle2,0.7)
simSetJointTargetPosition(motorHandle5,0.7)
simSetJointTargetPosition(motorHandle6,-1.9)
simSetJointTargetPosition(motorHandle0,0.6)
simSetJointTargetPosition(motorHandle3,0.6)
simSetJointTargetPosition(motorHandle,-1.9)
simSetJointTargetPosition(motorHandle4,-1.9)
end
end
if (sim_call_type==sim_childscriptcall_actuation) then
targetPosition=simGetJointPosition(motorHandle)
targetPosition0=simGetJointPosition(motorHandle0)
targetPosition1=simGetJointPosition(motorHandle1)
targetPosition2=simGetJointPosition(motorHandle2)
targetPosition3=simGetJointPosition(motorHandle3)
targetPosition4=simGetJointPosition(motorHandle4)
targetPosition5=simGetJointPosition(motorHandle5)
targetPosition6=simGetJointPosition(motorHandle6)
if (math.abs(targetPosition2-0.7)<0.01 and math.abs(targetPosition1 1.9)<0.01) then
simSetJointTargetPosition(motorHandle1,-0.9)
simSetJointTargetPosition(motorHandle2,1.7)
simSetJointTargetPosition(motorHandle5,1.7)
simSetJointTargetPosition(motorHandle6,-0.9)
simSetJointTargetPosition(motorHandle0,1.6)
simSetJointTargetPosition(motorHandle3,1.6)
simSetJointTargetPosition(motorHandle,-0.9)
simSetJointTargetPosition(motorHandle4,-0.9)
end
if (math.abs(targetPosition1 0.9)<0.01 and math.abs(targetPosition4 0.9)<0.01) then
simSetJointTargetPosition(motorHandle1,1.2)
simSetJointTargetPosition(motorHandle2,-0.4)
simSetJointTargetPosition(motorHandle5,-0.4)
simSetJointTargetPosition(motorHandle6,1.2)
simSetJointTargetPosition(motorHandle0,-0.7)
simSetJointTargetPosition(motorHandle3,-0.7)
simSetJointTargetPosition(motorHandle,1.1)
simSetJointTargetPosition(motorHandle4,1.1)
end
if (math.abs(targetPosition1-1.2)<0.01 and math.abs(targetPosition4-1.1)<0.01) then
simSetJointTargetPosition(motorHandle1,-0.4)
simSetJointTargetPosition(motorHandle2,0)
simSetJointTargetPosition(motorHandle5,0)
simSetJointTargetPosition(motorHandle6,-0.4)
simSetJointTargetPosition(motorHandle0,0)
simSetJointTargetPosition(motorHandle3,0)
simSetJointTargetPosition(motorHandle,0)
simSetJointTargetPosition(motorHandle4,0)
end
end
if (sim_call_type==sim_childscriptcall_sensing) then
-- Put your main SENSING code here
end
if (sim_call_type==sim_childscriptcall_cleanup) then
-- Put some restoration code here
end
实际上 Doggo还会后空翻
最开始我认为这不是事儿 后来我仿真过才知道 根本不是那么回事儿 当然 也有可能是我V-rep用的不好导致失败 下一次可能会带给大家 奔跑、后空翻、侧空翻 Bye~Bye~ 咦~~ 不对呀 开源项目 我怎么蠢到不去看看源代码的算法 我被我的愚蠢所震惊
Doggo团队说,自己DIY一只大概要3000美元,我就呵呵了,在我们大中国,有某宝坐镇,我信你个鬼! ——聪明的瓦肯人