CoppeliaSim(VREP)和ROS Moveit的联合仿真


目标

完成一套多视觉和点云感知的机械臂场景,与Moveit实现联合仿真,通过ROS通信实现传感器数据的获取(视觉、点云、机械臂状态等)并实现对机器人的控制。

实现过程

环境配置

CoppeliaSim自带视觉传感器(VIsion sensor、Kinect、雷达、GPS等传感器)直接拖拽进入即可,要调整的是他们之间的位置关系,通过菜单栏的调整平移,调整旋转。

菜单

通过CoppeliaSim的URDF导入功能,直接可以完成机械臂的导入,这部分没有遇到难点,入口在Plugins的URDF导入按钮。

这部分没有太多的问题,主要难点都在如何给每个模块单元(机械臂、摄像头)等配置脚本,实现数据到ROS的通信转换上。

脚本

CoppeliaSim默认脚本采用Lua语言,而每个添加的元素都可以添加相应的脚本,选中左侧相关的元素邮件点击“add”-‘Associated child script”-“Non Threaded ”即可,之后就可以添加代码了。

搭建的机械臂场景

function sysCall_init()
    -- do some initialization here
end

function sysCall_actuation()
    -- put your actuation code here
end

function sysCall_sensing()
    -- put your sensing code here
end

function sysCall_cleanup()
    -- do some clean-up here
end

-- See the user manual or the available code snippets for additional callback functions and details

如上,默认脚本主要分为上述三个部分,我用到的就init和actutation部分,以及cleanup。

sysCall_init()就是C++里面的初始化函数,变量等都可以在这里面设置,这个函数只调用一次,比如ROS订阅、发布变量初始化定义;sysCall_actuation()是一个周期执行的函数,相当于一个循环,所以相关代码可以放置在这里,比如发布topic等。

CoppeliaSim所有函数基本在Sim里面,而ROS的在SimROS里面,

 机械臂脚本

如果要实现moveit的使用,需要两个部分,一个是把机械臂的状态通过topic发出,通常moveit默认接收的topic为

名称:/joint_states

定义:sensor_msgs/JointState

而发布的控制指令为:

名称:/move_group/fake_controller_joint_states

定义:sensor_msgs/JointState

所以我们只要按照这两个topic封装即可,

具体请看我写个脚本,大体思路和我们用C和python写发布和订阅差不多,但是会省去一些步骤,下面这个脚本就实现了每个关节信息的发布和控制指令的接收,也发布了tf。


function subscriber_callback(msg)
    -- This is the subscriber callback function
    for i=1,#msg.position,1 do
        sim.setJointPosition(jointHandles[i],msg.position[i])
    end
end

function getTransformStamped(objHandle,name,relTo,relToName)
    -- This function retrieves the stamped transform for a specific object
    t=sim.getSystemTime()
    p=sim.getObjectPosition(objHandle,relTo)
    o=sim.getObjectQuaternion(objHandle,relTo)
    return {
        header={
            stamp=t,
            frame_id=relToName
        },
        child_frame_id=name,
        transform={
            translation={x=p[1],y=p[2],z=p[3]},
            rotation={x=o[1],y=o[2],z=o[3],w=o[4]}
        }
    }
end

function getJointStates()
    for i=1,6,1 do
        p = sim.getJointPosition(jointHandles[i])
        jointPosition[i] = p
    end
end

function sysCall_init()
    -- do some initialization here

    jointHandles={-1,-1,-1,-1,-1,-1}
    jointNames = {'joint1','joint2','joint3','joint4','joint5','joint6'}
    jointPosition = {-1,-1,-1,-1,-1,-1}
    for i=1,6,1 do
        jointHandles[i]=sim.getObjectHandle('joint'..i)
    end
    
    -- The child script initialization
    rosInterfacePresent=simROS

    -- Prepare the float32 publisher and subscriber (we subscribe to the topic we advertise):
    if rosInterfacePresent then
        publisher=simROS.advertise('/joint_states','sensor_msgs/JointState')
        subscriber=simROS.subscribe('/move_group/fake_controller_joint_states','sensor_msgs/JointState','subscriber_callback')
        -- subscriber=simROS.subscribe('/joint_states','sensor_msgs/JointState','subscriber_callback')
    end
end

function sysCall_actuation()
    -- put your actuation code here
 
    -- Send an updated simulation time message, and send the transform of the object attached to this script:
    if rosInterfacePresent then
        getJointStates()
        simROS.publish(publisher,{header = {stamp =  sim.getSystemTime()} ,name = jointNames, position=jointPosition})
        for i=1, 6, 1 do 
            simROS.sendTransform(getTransformStamped(jointHandles[i],sim.getObjectName(jointHandles[i]),-1,'world'))
        end
            -- To send several transforms at once, use simROS.sendTransforms instead
    end
end

function sysCall_sensing()
    -- put your sensing code here
end


function sysCall_cleanup()
    -- Following not really needed in a simulation script (i.e. automatically shut down at simulation end):
    if rosInterfacePresent then
        simROS.shutdownPublisher(publisher)
        simROS.shutdownSubscriber(subscriber)
    end
end

传感器脚本

这部分卡在了一个是需要做句柄的获取,sim.getObjectHandle('Vision_sensor_ortho'),Vision_sensor_ortho就是添加元素的名字;另外一个卡在了如何不用循环把数据转换成sensor_msg/Image发布,我对lua不熟悉,这块用了很长时间,最后通过代码rgb_data = {string.byte(color_buf,1,img_width*img_height*3)}搞定。

这里需要对函数

    color_buf = sim.getVisionSensorImage(visionhandle,0,0,img_width,img_height,1)
说明,

1)最后一个参数如果为0,则返回长witdh*height*channel,值0-1的table,在ros image 值为0-255,所以直接用这个图像为黑色;如果参数设置为1,则返回一个string类型,值为0-255,长度也是witdh*height*channel。

而发布image的topic代码为,

simROS.publish(image_pub,{step=img_width*3,height=img_height, width=img_width, encoding='rgb8',data=rgb_data})

其中data部分需要说int值的table,因此需要进行string到table的转换,经过大量测试的调研,发现了string.byte(str,i,j)这个函数,i,j表示要截取的端,可以从1到最后,但是这部分我也是经过了很久才搞定,它的输出是多个变量,左侧必须设置width*height*channel个变量才可以,后来发现只要价格大括号即可, 也就是{string.byte(color_buf,1,img_width*img_height*3)}。

2)getVisionSensorImage这个函数有时候会报错,大概率是因为分辨率不对,CopperliaSim添加的VIsion Sensor都是有默认分辨率的,可以手动修改,这块必须和之前设置的一样,否则会报错。

查看方法可以通过函数

    resolution = sim.getVisionSensorResolution(visionhandle)

 然后打印获取,修改分辨率方法,选中元素点击按钮,跳出“Scene Object Properties”界面,修改即可,这个按钮对其他元素也适用。

传感器参数配置界面

function sysCall_init()
    -- The child script initialization
    visionhandle = sim.getObjectHandle('Vision_sensor_ortho')
    rosInterfacePresent=simROS
    if rosInterfacePresent then
        image_pub = simROS.advertise('vision_top','sensor_msgs/Image') 
    end
    img_width = 512
    img_height = 512
end

function sysCall_actuation()
    -- put your actuation code here
    resolution = sim.getVisionSensorResolution(visionhandle)
    color_buf = sim.getVisionSensorImage(visionhandle,0,0,img_width,img_height,1)
    if type(color_buf) == 'string' then
        -- k1,k2,k3 = string.byte("abcdef",1,3)
        -- print (k1,k2,k3)    --97    98    99
        rgb_data = {string.byte(color_buf,1,img_width*img_height*3)}
    end
    
    if rosInterfacePresent then
        simROS.publish(image_pub,{step=img_width*3,height=img_height, width=img_width, encoding='rgb8',data=rgb_data})
    end
end

function sysCall_sensing()
    -- put your sensing code here
    
end

function sysCall_cleanup()
    -- do some clean-up here
    if rosInterfacePresent then
        simROS.shutdownPublisher(image_pub)
        -- simROS.shutdownSubscriber(subscriber)
    end
end

  • 6
    点赞
  • 32
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值