无人机/无人车仿真软件学习与实践---CoppeliaSim教程3---群体性能优化

本文介绍了如何使用CoppeliaSim优化无人机群体仿真的性能,包括设置模拟循环时间步长、减少代码阻塞以及直接使用仿真器进行仿真,实现了速度的显著提升。
摘要由CSDN通过智能技术生成

上一篇教程我们讲述了怎么使用Python连接CoppeliaSim对里面的无人机进行控制,也讲述了怎么通过多进程的方式进行调用。在大多数情况下学会这些手段就足够进行仿真操作,可将仿真的重点转到算法的验证上,然而对于群体无人机算法的验证则是个例外。

这类算法的验证往往需要对一堆无人机进行仿真,如果不对仿真性能进行优化,跑一次实验可能得半天到一天。这样一来速度慢不说,很多bug的调试也会因为无法快速获得反馈而变得无从下手。

在本篇教程中,我们将深入探讨如何对仿真软件进行性能优化,以实现快速的大规模无人机集群仿真。

测试环境搭建

首先,我们在仿真平台上放入20台无人机,如下图所示:
请添加图片描述
然后,用单线程阻塞的方式控制这20台无人机朝一个方向移动5个时间单位,代码如下:

import sim
import time

sim.simxFinish(-1)  # 断开一切可能的连接
# 开启一个与服务器(V-REP)的一个通信线程。返回一个ClientID,这个ClientID后续的API基本都需要用到,可以理解为用这个ID来进行通信。
clientID = sim.simxStart('127.0.0.1', 19997, True, True, 5000, 5)  # 连接到CoppeliaSim场景中

if clientID != -1:
    print('Connected to remote API server')
    time_start = time.time()  # 记录开始时间
    # 用名字来检索一个对象句柄。仿真环境里任何添加的object都会有一个自己的句柄(一个int,比如85,102),然后这个句柄跟object的名字对应,也就是我们有了名字就能对应到句柄。
    for run in range(5):
        for i in range(20):
            objName = "./Quadcopter[%s]" % i
            print(objName)
            _, targetObj = sim.simxGetObjectHandle(clientID, objName, sim.simx_opmode_oneshot_wait)
            # 获取无人机对象信息
            _, arr = sim.simxGetObjectPosition(clientID, targetObj, -1, sim.simx_opmode_oneshot_wait)
            print(arr)
            arr[1] = arr[1] + 0.5
            sim.simxSetObjectPosition(clientID, targetObj, -1, (arr[0], arr[1], arr[2]), sim.simx_opmode_oneshot_wait)

    time_end = time.time()  # 记录结束时间
    time_sum = time_end - time_start  # 计算的时间差为程序的执行时间,单位为秒/s
    print(time_sum)

else:
    print('Failed connecting to remote API server')

sim.simxGetPingTime(clientID)  # 在断开之前连接确保之前的命令已经被执行完成
sim.simxFinish(clientID)  # 断开与CoppeliaSim场景的连接

可以看到,在一台 i9-11900K的台式机上跑完一次代码需要49秒多。

优化方法一:设置模拟循环时间步长

有了测试场景之后,我们来看看最简单的加速方式(不要改任何代码),那就是设置模拟循环的时间步长。
请添加图片描述
软件的默认步长为50ms,将其改为10ms然后再运行程序,可以发现跑完一次代码的时间缩短到15秒多。

优化方法二:修改代码,减少阻塞

对代码进行分析,可以非常容易定位到代码运行速度慢的原因在于阻塞语句上。因此为了加速,可以尽可能减少阻塞代码的调用。比如获取对象句柄的语句只在开始调用,而位置设置语句写成非阻塞的形式。修改后的代码如下:


import sim
import time

sim.simxFinish(-1)  # 断开一切可能的连接
# 开启一个与服务器(V-REP)的一个通信线程。返回一个ClientID,这个ClientID后续的API基本都需要用到,可以理解为用这个ID来进行通信。
clientID = sim.simxStart('127.0.0.1', 19997, True, True, 5000, 5)  # 连接到CoppeliaSim场景中
targetObj={}# 创建空列表
if clientID != -1:
    print('Connected to remote API server')
    time_start = time.time()  # 记录开始时间

    for i in range(18):
        objName = "./Quadcopter[%s]" % i
        print(objName)
        _, targetObj[i] = sim.simxGetObjectHandle(clientID, objName, sim.simx_opmode_oneshot_wait)

    for run in range(5):
        for i in range(18):
            # 获取无人机对象信息
            _, arr = sim.simxGetObjectPosition(clientID, targetObj[i], -1, sim.simx_opmode_oneshot_wait)
            print(arr)
            arr[1] = arr[1] + 0.5
            sim.simxSetObjectPosition(clientID, targetObj[i], -1, (arr[0], arr[1], arr[2]), sim.simx_opmode_oneshot)

    time_end = time.time()  # 记录结束时间
    time_sum = time_end - time_start  # 计算的时间差为程序的执行时间,单位为秒/s
    print(time_sum)

else:
    print('Failed connecting to remote API server')

sim.simxGetPingTime(clientID)  # 在断开之前连接确保之前的命令已经被执行完成
sim.simxFinish(clientID)  # 断开与CoppeliaSim场景的连接

为了体现修改的效果,我们先将步长设置回50ms,然后运行代码。可以发现跑完一次代码需要的时间缩短到17秒多。如果步长为10ms,则缩短到5秒多。这相比于原来的仿真速度有了接近10倍的提升。

优化方法三:直接用仿真器进行仿真

如果上述的方法速度提升还是不够,那还有一个终极的解决方法,就是完全回避阻塞的问题,用仿真器直接进行仿真。

首先需要先把默认的脚本删掉,流程如下:无人机对象上方右键→Edit→Remove→Associated child script
请添加图片描述
然后添加python脚本,流程如下:无人机对象上方右键→Add→Associated child script→Threaded→Python
请添加图片描述
到CoppeliaSim的安装路径(C:\Program Files\CoppeliaRobotics\CoppeliaSimEdu\system)下,找到usrset.txt文件并打开,找到defaultPython,设置为本机Python的路径。找到executeUnsafe,设置为true:

defaultPython = C:\Users\38391\AppData\Local\Programs\Python\Python37\python.exe
executeUnsafe=true

然后,安装需要的Python模块

pip install pyzmq
pip install cbor

重启CoppeliaSim使设置生效,然后双击脚本写入如下代码(注意每台无人机都需要做一遍,可以先设置完一台无人机之后进行复制。复制的话代码中的objNum要做相应修改):

#python
import time
objNum=0

def sysCall_thread():
    sim.setThreadAutomaticSwitch(True)#Setting Thread Automatic Switch
    handle=sim.getObject('../Quadcopter[%s]' % objNum)
    time_start = time.time()
    runTime=0
    while True:
        p=sim.getObjectPosition(handle,-1)
        #print(p)
        p[0]=p[0]+0.5
        sim.setObjectPosition(handle,-1,p)
        runTime=runTime+1
        if runTime==5:
            time_end = time.time()
            time_sum = time_end - time_start
            print(time_sum)
    pass

完成上述操作后,跑一下代码可以发现运行时间在最坏的情况下也只需要不到0.5秒,相比于一开始的仿真速度有了接近100倍的提升。

参考文章

https://blog.csdn.net/DoctorSRn/article/details/99407074

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值