User Tools

Site Tools


vrep:socket-com-with-robot

This is an old revision of the document!


Th socket communication allows for an external program to control the robot inside V-REP. The external program is a Python script. We will use for the socket a server/client communication. The server is written in Lua inside a threaded script in V-REP. The client is written in Python, It will :

  • connect to the server
  • send commands to the robot
  • read data from the robot (sensors, status, …)
  • disconnect from the server

On the server side of the socket, we use a threaded script in Lua as we want to listen to the client's commands synchronously with the V-REP simulation loop.

We will use a simple 3 wheels robot and we load it in V-REP.

The first thing to do is to add a threaded script to a object. We can choose to add it to the MainBody object but it can be any other object in the scene :

Right-Clic on the small icon on the left of MainBody and select Add→Associated child script→Threaded. After this a blue icon showing a text file should appear on the right of MainBody :

To edit, double-clic on this icon. You can edit directely in the V-REP script window. However, if you prefer using you preferred editor, you can remove all the Lua text code in the script and just type one line :

require ("simple_control_bot")

Then you will have to create a file called simple_robot_control.lua in the directory where your scene file (here myLittleBot.ttt) is stored.

The Lua code looks like this :

function hex(s)
   s=string.gsub(s,"(.)",function (x) return string.format("%02X",string.byte(x)) end)
   return s
end
 
require ("pack")
bpack=string.pack
bunpack=string.unpack
 
portNb = 33211
serverOn = false
connexionTimeout = 0.01
cntTimeout = 0
socket=require("socket")
srv = nil
clt1 = nil
nCharMessage = 10
 
function sysCall_threadmain()
   -- initialization
   -- get left and right motors handles
   leftMotor = sim.getObjectHandle("MotorLeft")
   rightMotor = sim.getObjectHandle("MotorRight")
   -- control loop
   while true do
      -- get simulation time at beginning of the loop
      simTime = sim.getSimulationTime()
      -- if server is not running, start it
      if not serverOn then
	 printToConsole ("not connected")
	 srv = assert(socket.bind('127.0.0.1',portNb))
	 if (srv==nil) then
	    printToConsole ("bad connect")
	 else
	    printToConsole ("get socket")
	    ip, port = srv:getsockname()
	    printToConsole ("server ok at "..ip.." on port "..port)
	    serverOn = true
	    printToConsole ("connexion granted !!! ")
	 end
      end
      -- if server is running, accept command and send back status
      if serverOn then
	 srv:settimeout(connexionTimeout)
	 clt1 = srv:accept()
	 if clt1 == nil then
	    cntTimeout = cntTimeout + 1
	 else
	    -- to prevent locks, a timeout is set
	    clt1:settimeout(connexionTimeout)
	    -- get the data (command) from the client
	    dataIn = clt1:receive(nCharMessage)
	    if dataIn ~= nil then
	       -- unpack the received data with following format :
	       --   char : first synchro char 'A' 
	       --   char : second synchro char 'Z' 
	       --   float : speed left
	       --   float : speed right
	       nrd1,ch1,ch2,speedLeft,speedRight = bunpack(dataIn,"AAff")
	       if ch1 ~= 'A' or ch2 ~= 'Z' then
		  print ("bad data from py client ...")
	       else
		  -- apply the command
		  sim.setJointTargetVelocity(leftMotor,speedLeft)
		  sim.setJointTargetVelocity(rightMotor,speedRight)
	       end
	       -- prepare the status to send back  the client :
	       -- simulation time and wheel angular position (radians)
	       wheelAngleLeft =  sim.getJointPosition(leftMotor)
	       wheelAngleRight = sim.getJointPosition(rightMotor)
	       ch1 = 'A' -- sync code 1
	       ch2 = 'Z' -- sync code 2
	       -- pack the status data
	       dataPacked = bpack("AAfff",ch1,ch2,simTime,wheelAngleLeft,wheelAngleRight)
	       -- Send the status data back to the client:
	       clt1:send(dataPacked)	 
	    else
	       printToConsole ("no data")
	    end
	    clt1:close()
	 end
      end
   end
end
 
function sysCall_cleanup()
    -- Put some clean-up code here
end

The socket transfers binary data, so we need to pack the data before sending them and unpack them at the reception. For Lua we use the lpack libary]. You can either download the code and recompile **the pack.so** shared library or get it [[https://www.ensta-bretagne.fr/zerr/filerepo/vrep/pack.so|already compiled here if you work on x86_64 linux computer. The file pack.so should be added in the main V-REP directory.

The socket is between processes on the same computer so the IP address is localhost or 127.0.0.1. The communication port is set to 33211. The port number is arbitrary, if this port is already used, we will get an error message. To get a list of used port, you can use lsof. Here we print only the ports used by V-REP:

sudo lsof -i -P -n | grep LISTEN | grep vrep
[sudo] password for user: 
vrep      13871          newubu   29u  IPv4 17679486      0t0  TCP *:19997 (LISTEN)
vrep      13871          newubu   38u  IPv4 20187130      0t0  TCP 127.0.0.1:33211 (LISTEN)
vrep/socket-com-with-robot.1584459401.txt.gz · Last modified: 2020/03/17 16:36 by admin