- Ubuntu 14.04 上安裝V-rep 3.4.0
進入VREP官網下載Linux版本的V-rep(注意V-rep 3.4.0只有64位的版本,因此操作系統也要與之對應,Ubuntu 32位系統就無法運行V-rep 3.4。如果想使用以前的V-rep版本,可以進入這個網址下載)
將下載的壓縮文件解壓后放到合適的位置,進入該目錄下,執行sh腳本文件打開V-rep程序:
./vrep.sh
VREP與ROS的連接主要有三種方法:
- The RosInterface: RosInterface是V-rep官方推薦的用來跟ROS通信的插件(We highly recommend you to first try your hands on the RosInterface, since this is the most flexible and natural approach)
- The ROS plugin skeleton: 可以讓用戶實現特定功能的ROS插件框架(This represents a skeleton project that can be used to create a new ROS plugin for V-REP / create your own specific ROS plugin for V-REP. e.g. to support ROS messages for a specific robot)
- ROS interfaces developed by others: 其他非V-rep官方支持的通信接口,比如V-REP ROS bridge.
RosInterface
將VREP安裝路徑下的compiledRosPlugins文件夾中的libv_repExtRosInterface.so或libv_repExtRosSkeleton.so庫復制到上層目錄(VREP安裝目錄)中:
然后在終端中運行roscore開啟ROS master,接着執行vrep.sh腳本打開VREP,打開過程中會導入插件。可以看到RosInterface插件已經成功加載:
開啟一個新終端,輸入rosnode list查看運行的ros節點。可以看到除了ros master以外vrep_ros_interface也成功運行:
如果插件沒能成功導入(我使用的ROS Indigo版本沒遇到這種情況,但是ROS Kinetic會出錯),則需要自己重新編譯庫文件。編譯所需的幾個package位於VREP安裝目錄的programming/ros_packages下,將其復制到自己的catkin_ws/src中,用catkin工具進行編譯。具體步驟可以參照幫助文件中的ROS tutorial - Indigo頁面或者文件夾中的ros_vrep_rosinterface_install_guide.txt安裝說明。編譯成功后將生成的.so庫文件復制到V-rep安裝目錄中即可。
下面看一個簡單的例子。在場景中選擇一個物體添加一個non-threaded腳本,這個腳本會發布仿真時間然后自己訂閱它,並且還會發布坐標變換消息:

function subscriber_callback(msg) -- This is the subscriber callback function simAddStatusbarMessage('subscriber receiver following Float32: '..msg.data) end function getTransformStamped(objHandle,name,relTo,relToName) -- This function retrieves the stamped transform for a specific object t=simGetSystemTime() p=simGetObjectPosition(objHandle,relTo) o=simGetObjectQuaternion(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 if (sim_call_type==sim_childscriptcall_initialization) then -- The child script initialization objectHandle=simGetObjectAssociatedWithScript(sim_handle_self) objectName=simGetObjectName(objectHandle) -- Check if the required RosInterface is there: moduleName=0 index=0 rosInterfacePresent=false while moduleName do moduleName=simGetModuleName(index) if (moduleName=='RosInterface') then rosInterfacePresent=true end index=index+1 end -- Prepare the float32 publisher and subscriber (we subscribe to the topic we advertise): if rosInterfacePresent then publisher=simExtRosInterface_advertise('/simulationTime','std_msgs/Float32') subscriber=simExtRosInterface_subscribe('/simulationTime','std_msgs/Float32','subscriber_callback') end end if (sim_call_type==sim_childscriptcall_actuation) then -- Send an updated simulation time message, and send the transform of the object attached to this script: if rosInterfacePresent then simExtRosInterface_publish(publisher,{data=simGetSimulationTime()}) simExtRosInterface_sendTransform(getTransformStamped(objectHandle,objectName,-1,'world')) -- To send several transforms at once, use simExtRosInterface_sendTransforms instead end end if (sim_call_type==sim_childscriptcall_cleanup) then -- Following not really needed in a simulation script (i.e. automatically shut down at simulation end): if rosInterfacePresent then simExtRosInterface_shutdownPublisher(publisher) simExtRosInterface_shutdownSubscriber(subscriber) end end
終端中輸入rostopic list指令查看話題:
為了查看消息的內容,可以輸入:
$ rostopic echo /simulationTime
腳本中主要用到下面幾個函數:
- simExtRosInterface_advertise
- simExtRosInterface_subscribe
- simExtRosInterface_publish
- simExtRosInterface_sendTransform
rosInterfaceTopicPublisherAndSubscriber
在V-rep自帶的例子中還有一個場景模型"rosInterfaceTopicPublisherAndSubscriber.ttt",腳本代碼中會發布視覺傳感器捕獲的圖像信息到/image話題上,同時會自己訂閱這個信息並顯示出來。

-- This illustrates how to publish and subscribe to an image using the ROS Interface. -- An alternate version using image transport can be created with following functions: -- -- simExtRosInterface_imageTransportAdvertise -- simExtRosInterface_imageTransportPublish -- simExtRosInterface_imageTransportShutdownPublisher -- simExtRosInterface_imageTransportShutdownSubscriber -- simExtRosInterface_imageTransportSubscribe function imageMessage_callback(msg) -- Apply the received image to the passive vision sensor that acts as an image container simSetVisionSensorCharImage(passiveVisionSensor,msg.data) end if (sim_call_type==sim_childscriptcall_initialization) then -- Get some handles: activeVisionSensor=simGetObjectHandle('Vision_sensor') passiveVisionSensor=simGetObjectHandle('PassiveVision_sensor') -- Enable an image publisher and subscriber: pub=simExtRosInterface_advertise('/image', 'sensor_msgs/Image') --After calling this function, this publisher will treat uint8 arrays as string. Using strings should be in general much faster that using int arrays in Lua. simExtRosInterface_publisherTreatUInt8ArrayAsString(pub) -- treat uint8 arrays as strings (much faster, tables/arrays are kind of slow in Lua) sub=simExtRosInterface_subscribe('/image', 'sensor_msgs/Image', 'imageMessage_callback') simExtRosInterface_subscriberTreatUInt8ArrayAsString(sub) -- treat uint8 arrays as strings (much faster, tables/arrays are kind of slow in Lua) end if (sim_call_type==sim_childscriptcall_sensing) then -- Publish the image of the active vision sensor: local data,w,h=simGetVisionSensorCharImage(activeVisionSensor) d={} d['header']={seq=0,stamp=simExtRosInterface_getTime(), frame_id="a"} d['height']=h d['width']=w d['encoding']='rgb8' d['is_bigendian']=1 d['step']=w*3 d['data']=data simExtRosInterface_publish(pub,d) end if (sim_call_type==sim_childscriptcall_cleanup) then -- Shut down publisher and subscriber. Not really needed from a simulation script (automatic shutdown) simExtRosInterface_shutdownPublisher(pub) simExtRosInterface_shutdownSubscriber(sub) end
可以在終端中輸入下面的命令來顯示/image話題的圖像:
$ rosrun image_view image_view image:=/image
在rviz中添加Image,將話題選為/image也可以查看圖像信息:
controlTypeExamples
還有一個例子是controlTypeExamples.ttt,V-rep中的腳本負責發布接近傳感器的信息以及仿真時間並訂閱左右輪驅動的話題。外部的ros程序rosBubbleRob2根據接收到的傳感器信息生成左右輪速度指令,並發布出去,V-rep中訂閱后在回調函數里控制左右輪關節轉動。
V-rep中腳本代碼如下:

function setLeftMotorVelocity_cb(msg) -- Left motor speed subscriber callback simSetJointTargetVelocity(leftMotor,msg.data) end function setRightMotorVelocity_cb(msg) -- Right motor speed subscriber callback simSetJointTargetVelocity(rightMotor,msg.data) end function getTransformStamped(objHandle,name,relTo,relToName) t=simGetSystemTime() p=simGetObjectPosition(objHandle,relTo) o=simGetObjectQuaternion(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 if (sim_call_type==sim_childscriptcall_initialization) then robotHandle=simGetObjectAssociatedWithScript(sim_handle_self) leftMotor=simGetObjectHandle("rosInterfaceControlledBubbleRobLeftMotor") -- Handle of the left motor rightMotor=simGetObjectHandle("rosInterfaceControlledBubbleRobRightMotor") -- Handle of the right motor noseSensor=simGetObjectHandle("rosInterfaceControlledBubbleRobSensingNose") -- Handle of the proximity sensor -- Check if the required ROS plugin is there: moduleName=0 moduleVersion=0 index=0 pluginNotFound=true while moduleName do moduleName,moduleVersion=simGetModuleName(index) if (moduleName=='RosInterface') then pluginNotFound=false end index=index+1 end -- Add a banner: if (pluginNotFound) then bannerText="I cannot run! (I couldn't find my RosInterface plugin)" else bannerText="I am controlled via a ROS node and the RosInterface! ('rosBubbleRob2' controlls me)" end black={0,0,0,0,0,0,0,0,0,0,0,0} red={0,0,0,0,0,0,0,0,0,1,0.2,0.2} simAddBanner(bannerText,0,sim_banner_bitmapfont+sim_banner_overlay,nil,simGetObjectAssociatedWithScript(sim_handle_self),black,red) -- Ok now launch the ROS client application: if (not pluginNotFound) then local sysTime=simGetSystemTimeInMs(-1) local leftMotorTopicName='leftMotorSpeed'..sysTime -- we add a random component so that we can have several instances of this robot running local rightMotorTopicName='rightMotorSpeed'..sysTime -- we add a random component so that we can have several instances of this robot running local sensorTopicName='sensorTrigger'..sysTime -- we add a random component so that we can have several instances of this robot running local simulationTimeTopicName='simTime'..sysTime -- we add a random component so that we can have several instances of this robot running -- Prepare the sensor publisher and the motor speed subscribers: sensorPub=simExtRosInterface_advertise('/'..sensorTopicName,'std_msgs/Bool') simTimePub=simExtRosInterface_advertise('/'..simulationTimeTopicName,'std_msgs/Float32') leftMotorSub=simExtRosInterface_subscribe('/'..leftMotorTopicName,'std_msgs/Float32','setLeftMotorVelocity_cb') rightMotorSub=simExtRosInterface_subscribe('/'..rightMotorTopicName,'std_msgs/Float32','setRightMotorVelocity_cb') -- Now we start the client application: result=simLaunchExecutable('rosBubbleRob2',leftMotorTopicName.." "..rightMotorTopicName.." "..sensorTopicName.." "..simulationTimeTopicName,0) end end if (sim_call_type==sim_childscriptcall_actuation) then -- Send an updated sensor and simulation time message, and send the transform of the robot: if not pluginNotFound then local result=simReadProximitySensor(noseSensor) local detectionTrigger={} detectionTrigger['data']=result>0 simExtRosInterface_publish(sensorPub,detectionTrigger) simExtRosInterface_publish(simTimePub,{data=simGetSimulationTime()}) -- Send the robot's transform: simExtRosInterface_sendTransform(getTransformStamped(robotHandle,'rosInterfaceControlledBubbleRob',-1,'world')) -- To send several transforms at once, use simExtRosInterface_sendTransforms instead end end if (sim_call_type==sim_childscriptcall_cleanup) then if not pluginNotFound then -- Following not really needed in a simulation script (i.e. automatically shut down at simulation end): simExtRosInterface_shutdownPublisher(sensorPub) simExtRosInterface_shutdownSubscriber(leftMotorSub) simExtRosInterface_shutdownSubscriber(rightMotorSub) end end
rosInterface helper tool
在模型瀏覽器的tools文件夾中有一個RosInterface的幫助工具,將其拖入場景中可以方便實現一些控制功能。
主要有下面一些功能:
- startSimulation topic: can be used to start a simulation by publishing on this topic a std_msgs::Bool message.
- pauseSimulation topic: can be used to pause a simulation by publishing on this topic a std_msgs::Bool message.
- stopSimulation topic: can be used to stop a simulation by publishing on this topic a std_msgs::Bool message.
- enableSyncMode topic: by publishing a std_msgs::Bool message on this topic, you can enable/disable the synchronous simulation mode.
- triggerNextStep topic: by publishing a std_msgs::Bool message on this topic, you can trigger the next simulation step, while in the synchronous simulation mode.
- simulationStepDone topic: a message of type std_msgs::Bool will be published at the end of each simulation pass.
- simulationState topic: messages of type std_msgs::Int32 will be published on a regular basis. 0 indicates that the simulation is stopped, 1 that it is running and 2 that it is paused.
- simulationTime topic: messages of type std_msgs::Float32 will be published on a regular basis, indicating the current simulation time.
可以在終端中輸入下面的一些命令進行測試:
$ rostopic pub /startSimulation std_msgs/Bool true --once
$ rostopic pub /pauseSimulation std_msgs/Bool true --once
$ rostopic pub /stopSimulation std_msgs/Bool true --once
$ rostopic pub /enableSyncMode std_msgs/Bool true --once $ rostopic pub /triggerNextStep std_msgs/Bool true --once
比如在終端中輸入:rostopic pub /startSimulation std_msgs/Bool true --once, 就可以開始仿真,跟手動點擊仿真按鈕效果一樣。
參考: