使用Phantom omni力反馈设备控制机器人

  传统的工业机器人普遍采用电机 、齿轮减速器 、关节轴三者直接连接的传动机构,这种机构要求电机与减速器安装在机械臂关节附近,其缺点是对于多关节机械臂,下一级关节的电机与减速器等驱动装置成为上一级关节的额外负载 。这一额外负载带来的负面影响往往超过机械臂连杆等必要结构件,因此提高了对机械臂动力和驱动元件的要求,由此造成整体重量 、体积 、造价和内部消耗的增加,降低了机械臂对外做功的能力和效率。为了避免这一问题许多主动式医疗机器人采用绳驱动方式,使用柔性绳索远距离的传递运动和力矩。将驱动装置安装到远离相关关节的基座上,使得整个机械臂的结构紧凑在减轻机械臂整体重量的同时提高了对外做功的能力。下图所示的就是达芬奇手术机器人的末端夹子,采用绳驱动方式可以在较小的机械结构内实现多自由度的灵活运动:

  下面尝试在VREP中使用力反馈设备Phantom omni来控制医疗机器人的末端夹子。机构简图如下图所示,一共有5个自由度:其中移动自由度负责进给,一个整体旋转自由度,还有两个左右、上下弯曲的自由度,最后是控制夹子张合的自由度。

  删除Solidworks CAD模型中的一些不必要特征,比如倒角、内部孔、螺纹孔等,导出成STL文件,再导入到VREP中。然后还需要进行继续化简,减少网格数量,当网格数减少到不影响几何外观就可以了。接下来在相应的位置添加关节,设置关节运动范围(软件限位),并将其设为Inverse kinematics模式。

  设置Calculation Modules中的Inverse kinematics:

  搭建好模型后可以先用键盘进行测试,按方向键移动ikTarget,VREP会根据构型自动计算运动学逆解,然后将ikTip移动到ikTarget处(这样就会带着整个机构运动)。键盘控制的脚本代码如下:

if (sim_call_type==sim_childscriptcall_initialization) then-- Put some initialization code heretargetHandle = simGetObjectHandle('ikTarget')endif (sim_call_type==sim_childscriptcall_actuation) then-- Put your main ACTUATION code hereendif (sim_call_type==sim_childscriptcall_sensing) then-- Put your main SENSING code here-- Read the keyboard messages (make sure the focus is on the main window, scene view):message, auxiliaryData = simGetSimulatorMessage()if (message == sim_message_keypress) thenif (auxiliaryData[1]==119) then-- W keylocal p = simGetObjectPosition(targetHandle, -1)p[1] = p[1] - 0.001simSetObjectPosition(targetHandle, -1, p)endif (auxiliaryData[1]==115) then-- S keylocal p = simGetObjectPosition(targetHandle, -1)p[1] = p[1] + 0.001simSetObjectPosition(targetHandle, -1, p)endif (auxiliaryData[1]==2007) then-- up keylocal p = simGetObjectPosition(targetHandle, -1)p[3] = p[3] + 0.001simSetObjectPosition(targetHandle, -1, p)endif (auxiliaryData[1]==2008) then-- down keylocal p = simGetObjectPosition(targetHandle, -1)p[3] = p[3] - 0.001simSetObjectPosition(targetHandle, -1, p)endif (auxiliaryData[1]==2009) then-- left keylocal p = simGetObjectPosition(targetHandle, -1)p[2] = p[2] - 0.001simSetObjectPosition(targetHandle, -1, p)endif (auxiliaryData[1]==2010) then-- right keylocal p = simGetObjectPosition(targetHandle, -1)p[2] = p[2] + 0.001simSetObjectPosition(targetHandle, -1, p)endend
endif (sim_call_type==sim_childscriptcall_cleanup) then-- Put some restoration code hereend
View Code

  测试没问题后可以使用CHAI3D插件来连接力反馈设备。这里采用增量控制的模式,即计算当前时刻与前一时刻手柄位置在X、Y、Z方向上的差,然后控制VREP中的ikTarget控制点按相应的增量移动。注意在VREP中机器人向前运动是沿X轴负方向、向上运动是沿Z轴正方向、向右运动是沿Y轴正方向,这与CHAI3D中坐标系的定义一致(向前推手柄是沿着X轴负方向...),因此可以使用力反馈设备直观的控制机器人的运动。当然如果坐标系定义不一致,需要进行简单的转换才行。

  下面的代码在sensing探测部分会使用simExtCHAI3D_readPosition来读取当前操作手柄的位置和按钮状态。按照VREP默认设置,这部分代码会50ms执行一次,这里会出现一个问题:如果采样速率太快,会导致前后两次采集到的位置数据偏差为零(人手的操作频率没那么快,还来不及改变位置),那么输出的控制量就一直是零,这样就没办法用增量控制的方式来操控机器人。解决办法是延迟几个周期再采样,等到有足够大的偏差之后再生成控制量。还有一个问题是使用CHAI3D返回的数据以“米”为单位,而VREP世界中的单位有可能未知,那么使用增量控制时需要对控制量乘一个比例系数,避免因操作端微小的移动造成从动端运动量过大,超出关节限制(无法到达的逆解)。或者可以调节比例系数,用操作端的大位移来控制从动端的小位移,实现精细控制。

if (sim_call_type==sim_childscriptcall_initialization) then-- Check if the plugin is loaded:moduleName=0moduleVersion=0index=0pluginNotFound=truewhile moduleName domoduleName,moduleVersion=simGetModuleName(index)if (moduleName=='CHAI3D') thenpluginNotFound=falseendindex=index+1endif (pluginNotFound) thensimDisplayDialog('Error','CHAI3D plugin was not found, or was not correctly initialized (v_repExtCHAI3D.dll).',sim_dlgstyle_ok,false,nil,{0.8,0,0,0,0,0},{0.5,0,0,1,1,1})else-- Start the device:local toolRadius = 0.001 -- the radius of the toollocal workspaceRadius = 0.2 -- the workspace radiusif simExtCHAI3D_start(0, toolRadius,workspaceRadius) ~= 1 thensimDisplayDialog('Error','Device failed to initialize.',sim_dlgstyle_ok,false,nil,{0.8,0,0,0,0,0},{0.5,0,0,1,1,1})elseCHAI3DPluginInitialized = trueendendtargetHandle = simGetObjectHandle('ikTarget')deltaPos = {0, 0, 0}counter = 0ratio = 50endif (sim_call_type==sim_childscriptcall_actuation) thenif buttonState ==1 then  -- press the buttonlocal p = simGetObjectPosition(targetHandle, -1) -- get the target position-- add increment of the tool tipp[1] = p[1] + deltaPos[1] / ratio                  p[2] = p[2] + deltaPos[2] / ratiop[3] = p[3] + deltaPos[3] / ratiosimSetObjectPosition(targetHandle, -1, p)  -- move to the absolute positionend
endif (sim_call_type==sim_childscriptcall_sensing) thenif CHAI3DPluginInitialized then-- Read the current position of the cursor:local currentToolPosition = simExtCHAI3D_readPosition(0)-- Read the buttons of the device:buttonState = simExtCHAI3D_readButtons(0)counter = counter + 1      -- increase the counterif counter % 30 == 1 then  -- keep the valueprevToolPosition = currentToolPositionendif counter % 30 == 0 then  -- calculate tool tip incrementdeltaPos[1] = currentToolPosition[1] - prevToolPosition[1]  -- X-axis incrementdeltaPos[2] = currentToolPosition[2] - prevToolPosition[2]  -- Y-axis incrementdeltaPos[3] = currentToolPosition[3] - prevToolPosition[3]  -- Z-axis incrementcounter = 0  -- reset counterlocal info = string.format("CurrentPosition:%.2f,%.2f,%.2f  DeltaPosition:%.2f,%.2f,%.2f",currentToolPosition[1],currentToolPosition[2],currentToolPosition[3],deltaPos[1],deltaPos[2],deltaPos[3])simAddStatusbarMessage(info)endend
endif (sim_call_type==sim_childscriptcall_cleanup) thenif CHAI3DPluginInitialized then-- Disconnects all devices and removes all objects from the scene
        simExtCHAI3D_reset()end
end

   将力反馈设备手柄移动到合适的位置之后就可以按住按钮开始操控机器人,松开按钮会停止控制。如果在VREP虚拟场景中添加其它物体(比如障碍物),则还可以模拟环境中的力(接触力、重力、摩擦力、弹簧力等)让操控着“感觉”到。如果实际机器人上装有力传感器,则在用Phantom omni控制机器人的同时也能读取力的信息,反馈给操作者。

  下面是使用Phantom omni来控制机器人的动态图,黄色的轨迹为使用Graph记录的控制点的空间位置:

   对于该机构也可以自己实现运动学逆解的数值算法,下面给出伪逆矩阵法和阻尼最小二乘法的参考:

import math  
import numpy as np# link length
L1 = 1  
L2 = 1gamma = 1       # step size
lamda = 0.2     # damping constant (DLS-method)
stol = 1e-3     # tolerance
nm = 10         # initial error
count = 0       # iteration count
ilimit = 20     # maximum iteration# numerical method for inverse kinematics
method = 'Pseudo Inverse'  # 'Pseudo Inverse', 'DLS', ...# initial joint value
q = np.array([0, 0, math.pi/2, 0]) # [theta1, d1, theta2, theta3]# target position  
target_pos = np.array([1, 0, 2])   # [x,y,z]while True:if(nm > stol):# forward kinematics:x = np.array([math.cos(q[0])*math.cos(q[2])*(L1+L2*math.cos(q[3]))+L2*math.sin(q[0])*math.sin(q[3]),\math.cos(q[2])*math.sin(q[0])*(L1+L2*math.cos(q[3]))-L2*math.cos(q[0])*math.sin(q[3]),\q[1]+(L1+L2*math.cos(q[3]))*math.sin(q[2])])# compute errorerror = target_pos - x# compute JacobianJ11 = -math.sin(q[0])*math.cos(q[2])*(L1+L2*math.cos(q[3]))+L2*math.cos(q[0])*math.sin(q[3])J12 = 0J13 = -math.sin(q[2])*math.cos(q[0])*(L1+L2*math.cos(q[3]))J14 = L2*(math.sin(q[0])*math.cos(q[3])-math.cos(q[0])*math.cos(q[2])*math.sin(q[3]))J21 = math.cos(q[0])*math.cos(q[2])*(L1+L2*math.cos(q[3]))+L2*math.sin(q[0])*math.sin(q[3])J22 = 0J23 = -math.sin(q[0])*math.sin(q[2])*(L1+L2*math.cos(q[3]))J24 = -L2*(math.cos(q[0])*math.cos(q[3])+math.sin(q[0])*math.cos(q[2])*math.sin(q[3]))J31 = 0J32 = 1J33 = math.cos(q[2])*(L1+L2*math.cos(q[3]))J34 = -L2*math.sin(q[2])*math.sin(q[3])J = np.array([[J11,J12,J13,J14],[J21,J22,J23,J24],[J31,J32,J33,J34]])if method == 'Pseudo Inverse': # Pseudo Inverse MethodJ_pseudo = np.dot(J.transpose(), np.linalg.inv(J.dot(J.transpose()))) # compute pseudo inversedq = gamma * J_pseudo.dot(error)if method == 'DLS':# Damped Least Squares Methodf = np.linalg.solve(J.dot(J.transpose())+lamda**2*np.identity(3), error)dq = np.dot(J.transpose(), f)# update joint position   q = q + dqnm = np.linalg.norm(error)count = count + 1if count > ilimit:print "Solution wouldn't converge!"breakelse:# print resultprint 'theta1=' + str(q[0]*180/math.pi)+' d1='+str(q[1]) + ' theta2=' + str((q[2]-math.pi/2)*180/math.pi)+' theta3=' + str(q[3]*180/math.pi)print 'Current position: %.2f, %.2f, %.2f' %(x[0],x[1],x[2])    print str(count)+' iterations'+'  err:'+str(nm)break

 

 

参考:

OpenHaptics编程环境搭建

VREP中的力触觉设备接口(CHAI3D)

 “逆运动学”——从操作空间到关节空间(上篇)

转载于:https://www.cnblogs.com/21207-iHome/p/7338216.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/572132.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Go_配置系统环境MacOS(M1)

在MacOS下和JDK一样,配不配环境其实MacOS都是可以检测的到的,安装好以后直接输入go version是一样可以的,因为都是使用开发工具的,在开发工具里配置的话是样的,如果有习惯的话就配置一下吧 下载安装及配置环境&#xf…

Go_数据类型

数据类型: 计算机存储设备最小信息单位是位(bit),最小的存储单元是字节(byte),占用字节的不同,所表示能存储的数据长度不同。数据类型用来说明数据的数据的结构,便于后面…

HashMap之扰动函数和低位掩码

我们都知道,hashMap在实现的时候,为了寻找在数组上的位置,主要做了两件事 int hash hash(key); int i indexFor(key, table.length); 这个时候得到i才是数组上的位置。 这两个方法详解如下 JDK8对扰动函数的修改,只进行了一次移…

NE2018届校招内推笔试——数据挖掘

【单选题|2分/题】 1、在只有两类的情况下,二维特征向量通过共享相同的协方差矩阵的正态分布生成,其中协方差矩阵为: 均值向量分别为:,则根据贝叶斯分类,样本分类为:() A…

不满足依赖关系

今晚上脑残,替换了实体,把报错的也都替换完成了,但是运行报错: 大概的意思就是说不满足XXXXXX依赖关系,但是找了半天都没有找到,最后是mapper的实体类全路径替换的时候,脑残在后面加上了.java。…

Go_切片(初始化、遍历、截取、修改、append、copy、切片作为函数参数、切片求和、切片求最大值)

切片: 切片的长度是不固定的,可以追加数据,可以理解是一个动态数组,切片的底层是一个结构体切片类型(slice)本身并不是动态数组或数组指针。它内部通过指针引用底层数组,设定相关属性将操作限定…

阿里巴巴Java开发手册——速读记录

本随笔基于阿里巴巴Java开发手册V1.2,陆陆续续记录一些现阶段能理解的,有启发的内容,并将持续更新 最佳实践——插件使用已经发布为随笔!http://www.cnblogs.com/jiangbei/p/7668654.html 一、编程规范 1.命名规范 (1&…

Go_指针的使用、数组指针和指针数组、指针与切片、指针与结构体、多级指针

指针: 指针是一个特殊的变量,因为它存储的数据是另一个变量的内存地址,指针本身也是有内存地址的指针的数据类型有int、float、bool、string、数组、结构体指针的作用就是可以通过变量/对象的内存地址去操作变量/对象 注意: 取址运…

Go_面向对象(抽象、封装、继承)

抽象 抽象是一种编程思维方式,是从多个事物中提取共性 例:产品经理和程序员都有工作的方法,但是工作内容不同,可以把工作抽象出来定义为一个方法,具体细节由调用者补充 银行存取款案例: 账号结构体取款方法…

Discrete Logging POJ - 2417(BSGS)

Discrete Logging POJ - 2417 题意&#xff1a;给P&#xff0c;B&#xff0c;N&#xff0c;求最小的L使得 BL≡N (mod P)&#xff0c;其中P是素数。 Baby Step Giant Step 1 #include <cstdio>2 #include <cstring>3 #include <iostream>4 #include <cma…

js 根据固定位置获取经纬度--腾讯地图

1.首先引入jq 和 腾讯地图js <script src"../js/jQuery.js"></script> <script charset"utf-8" src"http://map.qq.com/api/js?v2.exp"></script> 2.html代码部分 <body onload"init()"><button ty…

Golang——string字符串常用函数(Contains、join、Index、Repeat、Replace、Split、Trim、Fields)

更多的还是去官方文档里去看&#xff1a;https://studygolang.com/pkgdoc Contains&#xff1a; 判断字符串中是否包含指定字符串 演示&#xff1a; func main() {str1 : "itzhuzhu"result : strings.Contains(str1, "zhu")fmt.Println(result) }join&a…

[flask 优化] 由flask-bootstrap,flask-moment引起的访问速度慢的原因及解决办法

一周时间快速阅读了400页的《javascript基础教程》&#xff0c;理解了主要概念。解决了一个很久之前的疑问。 我的网站是使用flask框架搭建的&#xff0c;介绍flask web的一本著名的书&#xff08;之前提到过&#xff09;作者搭建个人博客时&#xff0c;向读者推荐了flask-boot…

Go_关键字、编译、转义字符

关键字&#xff1a; 关键字是指被go语言赋予了特殊含义的单词&#xff0c;共25个&#xff0c;关键字不能用于自定义名字&#xff0c;只能在特定语法结构中使用。 breakdefaultfuncinterfaceselectcasedefergomapstructchanelsegotopackageswitchconstfallthroughifrangetypec…

并发编程概念、程序线程进程、线程同步、互斥量、读写锁、协程并发

多线程&#xff1a; 多线程就是同时执行多个应用程序&#xff0c;需要硬件的支持同时执行&#xff1a;不是某个时间段同时&#xff0c;cpu切换的比较快&#xff0c;所有用户会感觉是在同时运行 并发与并行&#xff1a; 并行(parallel)&#xff1a;指在同一时刻&#xff0c;有多…

第4阶段——制作根文件系统之分析init_post()如何启动第1个程序(1)

本章学习如何启动第一个应用程序 1.在前面的分析中我们了解到&#xff0c;在init进程中内核挂接到根文件系统之后&#xff0c;会开始启动第一个应用程序: kernel_init函数代码如下: static int __init kernel_init(void * unused) //进入init进程 …

Golang并发——并发技术Goroutine和channel的使用、定时器、生产者消费者、条件变量、select

Goroutine: goroutine是Go并行设计的核心。goroutine说到底其实就是协程&#xff0c;它比线程更小&#xff0c;十几个goroutine可能体现在底层就是五六个线程&#xff0c;Go语言内部帮你实现了这些goroutine之间的内存共享。执行goroutine只需极少的栈内存(大概是4~5KB)&#x…

Oozie协作框架

Oozie协作框架 一&#xff1a;概述 1.大数据协作框架 2.Hadoop的任务调度 3.Oozie的三大功能 Oozie Workflow jobs Oozie Coordinator jobs Oozie Bundle 4.Oozie的架构 控制流节点 起始&#xff0c;分支&#xff0c;并发&#xff0c;汇合&#xff0c;结束 动作节点action 5.O…

11.4 专利法与反不正当竞争法解读

第六条是对于职务作品的一个定性.它这个职务作品、职务发明创造和我们前面著作法所讲到的职务作品的处理方式基本一致.就是如果认定某一个作品它是属于职务作品、职务发明创造,那么这一个作品它的专利权应该是属于单位而不是个人.只有认定这个创造为非职务发明创造的时候,申请的…

一文入门网络编程:常见协议、通信过程、Socket、CS/BS、TCP/UDP

网络编程三要素&#xff1a;ip地址、端口、协议&#xff0c;在网络通信协议下&#xff0c;不同计算机上运行的程序&#xff0c;可以进行数据传输 常见协议&#xff1a; 传输层 常见协议有TCP/UDP协议。应用层 常见的协议有HTTP协议&#xff0c;FTP协议。网络层 常见协议有IP协议…