VREP中可以添加力傳感器,用於剛性連接在兩個物體之間以測量這兩個物體之間的作用力或力矩。如下圖所示,力傳感器可以測量沿着X、Y、Z三個坐標軸的力和力矩:

[Forces and torques measured by a force sensor]
以下圖中的場景為例,紅色立方體為牆壁(設為靜態物體,否則可能會傾覆),藍色立方體為細長桿,長度0.4m,質量2Kg,用力傳感器將這兩個物體連接在一起。桿對牆壁會施加一個傾覆力矩,理論值為$T=\frac{1}{2}lmg=3.92N*m$,根據右手定則方向為負。

[Force sensor object (green) measuring the force and torque exerted by a beam (blue) anchored in a wall (red)]
添加Graph,並添加數據流記錄力傳感器的Z軸轉矩:

開始仿真,可以看到力傳感器數值穩定在-3.92附近,與理論計算一致:

力傳感器能剛性地連接兩個物體,但在仿真過程中當其受到的力/力矩超過閾值或某些用戶定義的條件發生時,這種剛性連接可以失效。Initially, a force sensor acts as a rigid link. During simulation, a force sensor can however be broken when a specified force/torque threshold is overshot or when some other user-defined conditions are met.
下面看看力傳感器的屬性對話框,Filter欄用於濾波減少數據抖動,Breaking settings欄用於設定力傳感器失效的閾值,Visual properties設置其外觀與尺寸:

- Filter: when force or torque data is acquired by the force sensor, then it is accumulated and can be filtered in order to obtain less jittery values.
- Sample size: the number of values that should be used for the filter. 1 will not filter values (raw output).
- Average value: if selected, then the force sensor will deliver average values (average of sample size values).
- Median value: if selected, then the force sensor will deliver median values (median of sample size values).
- Breaking settings: this section allows to set-up some automatic breaking conditions and behavior for a force sensor.
- Force threshold: the amplitude of the force vector that triggers a threshold violation.
- Torque threshold: the amplitude of the torque vector that triggers a threshold violation
- Consecutive threshold violations for breaking: the number of consecutive times the sensor is allowed to violate a threshold before breaking.
根據上面選項的描述,我們將力矩閾值設為1N*m(默認為10N*m),然后再進行仿真,一段時間(時間長短由Consecutive threshold violations for breaking控制:10*50ms=0.5s)后藍色的桿會從牆上掉下來。從曲線圖中也可以看出,超出一定時間后力傳感器的力矩讀數變為0:

VREP中力傳感器的一大用處就是用來測量機器人與外界環境交互時的接觸力,比如檢測機械手爪的夾持力或是機器人腳底的壓力分布等信息。通常需要將力傳感器添加在末端(手指或腳底板上)然后再連接一個接觸體。(Attach a force sensor at the tip of robot leg, then attach a contact shape to the force sensor (i.e. Tip --> forceSensor --> contactShape). Then you can read the force/torque in the force/torque sensor)
下面來進行一個測試,將兩個立方壘起來,上面的質量為10Kg,用力傳感器將其連接,如下圖所示:

開始仿真,可是會出現很奇怪的現象:用Bullet和ODE引擎時,力的測量結果總是不穩定,隨機地跳動。但切換到Vortex或Newton引擎時結果就很好,下圖是用Newton引擎的測量結果,正好為98N。

開始以為是哪些參數沒有設置好(比如物體質量、慣性矩等參數要合適,否則仿真會出現不穩定),后來在VREP官方論壇提問才知道是因為Bullet和ODE引擎在接觸邊界的時候也進行了碰撞的計算,跟物理引擎工作原理有關系。解決方法就是設置碰撞掩碼(mask),使其掩碼位錯開,不進行碰撞計算。
The two objects collide with each other slightly (it is a border condition and only some of the engines will register that collision). The solution: simply adjust the local respondable masks of your two bodies, so that they won't react to collision anymore. Then the sensor reading will be much better.
像下面這樣,讓力傳感器連接的兩個物體的碰撞掩碼位錯開不重合(這樣即使兩個物體相互穿透也不會產生碰撞力)


下面的一個例子模仿了稱重儀,按照上面所述設置好碰撞掩碼后可以在平台上添加不同質量的物體,用力傳感器測量其重量(平台和物體的重量)。如下圖所示,物體質量1Kg,平台質量0.1Kg,重力加速度設為10m/s2,則傳感器檢測出來的力應該是11N。可以減去平台的重量,消除這一固定偏差獲取真實物體重量。

有一點需要注意,有人會想如果將平台質量設的很小,比如0.00001Kg那么傳感器測量結果不就相當於真實值了(因為平台質量很小,忽略不計,就可以不用減去這個偏差...)。我開始也想這樣偷懶,不過仿真時出現了不穩定和跳動等問題,重物過一段時間后開始抖動甚至從平台上掉下來...
因為物體間的質量相差太大,進行動態仿真時要避免物體的質量或慣性矩過小。但奇葩的是即使質量很小,切換到Vortex或Newton引擎時結果也很穩定... Bullet和ODE主要用於游戲中,而Vortex專注於科學物理仿真,計算准確度以及穩定性肯定會比游戲物理引擎要好。所以VREP提供了4個物理引擎還是有道理的,要根據它們的長處來選擇合適的引擎進行仿真,不能總是用默認的Bullet。
Design consideration 7:
Keep masses similar and not too light. When linking two shapes with a dynamically enabled joint or a dynamically enabled force sensor, make sure the two shape's masses are not too different (m1<10*m2 and m2<10*m1), otherwise the joint or force sensor might be very soft and wobbly and present large positional/orientational errors (this effect can however also be used as a natural damping sometimes). Additionally, very low mass shapes should be avoided since they won't be able to exert very large forces onto other shapes (even if propelled by high force actuators!).
下面看一個稍微復雜一點的模型,機械手爪(夾持器)BaxterGripper,可以從模型瀏覽器的components——>grippers中找到。

這個模型的可動部分由rightFinger、leftFinger和closeJoint組成,closeJoint是一個移動關節用於控制手爪的張開和閉合。從層級關系圖中可以看出左右指上都裝有力傳感器,分別連接着Finger和Pad。
下面是手爪的控制代碼:
if (sim_call_type==sim_childscriptcall_initialization) then gripperHandle=simGetObjectHandle('BaxterGripper') objectName=simGetObjectName(gripperHandle) motorHandle=simGetObjectHandle('BaxterGripper_closeJoint') -- the 'BaxterGripper_centerJoint' is handled by a joint callback script (i.e. custom position controller) openedGap=simGetScriptSimulationParameter(sim_handle_self,'openedGap') closedGap=simGetScriptSimulationParameter(sim_handle_self,'closedGap') interval={0.0362-openedGap,openedGap-closedGap} simSetJointInterval(motorHandle,false,interval) end if (sim_call_type==sim_childscriptcall_cleanup) then end if (sim_call_type==sim_childscriptcall_actuation) then close=simGetIntegerSignal(objectName..'_close') if (close==1) then simSetJointTargetVelocity(motorHandle,0.005) else simSetJointTargetVelocity(motorHandle,-0.005) end end
當整數值信號'BaxterGripper_close'的值為1時手爪閉合,值為0時手爪張開。信號可以看成是一種全局變量,因此可以在其它腳本中設置該信號來控制手爪模型的張合:
-- simSetIntegerSignal(gripperName..'_close',1) -- close -- simSetIntegerSignal(gripperName..'_close',0) -- open
Signals can be seen as global variables. Three types of signals are currently supported: integer-type signals, floating-type signals and string-type signals. Signals can be defined, redefined, read and cleared. At simulation end, all signals created by the main script or any child script will be cleared.
設置整型信號的函數原型為:number result = simSetIntegerSignal(string signalName, number signalValue)
其中,參數signalName為信號名,是一個字符串變量;signalValue是要設置信號的整形數值。
獲取信號值的函數為:number signalValue=simGetIntegerSignal(string signalName)
參考:
