@Project : CoppeliasimType
@Author :Lucio.YipengLi@outlook.com
@Date :2025/02/12
@CoppeliaSim Version: 4.9.0
Python下ZeroMQ remote API 没有代码提示的问题
1.问题背景
本人在机缘巧合下开始接触CoppeliaSim这个软件(因为目前开发的这个产品给的URDF太烂了,模型一堆错就不说了,在其他仿真软件根本识别不出来!)为了更好的接入其他库以及提升代码体验,遂采用官方推荐的ZeroMQ remote API进行异平台开发,简而言之就是将代码流程放在Pycharm中编辑,不采用CoppeliaSim本身的代码编辑器。
在开发过程中发现官方提供的这个coppeliasim-zmqremoteapi-client库根本不支持sim函数的代码提示,也即每一次调用函数你都必须返回Regular API reference(RAR)进行查询,这样会大大降低我们的开发效率。
2.问题分析
在coppeliasim-zmqremoteapi-client库中没有对RemoteAPIClient返回类型的定义以及代码提示,在Pycharm中我们可以另外写一个类文件,将所有的函数定义到这个类,再将返回类型指定为这个类,就达到了我们需要代码提示的初衷。此外我们还可以通过写函数的注释来完善调用时代码提示。
3.解决方案
询问论坛后得知原来RAR中还有getApiFunc和getApiInfo这两神器,通过这个函数可以获得所有指定的sim函数以及相关的信息,我们可以通过这两个函数得到所有我们想到代码提示的函数。话不多说,开造!
一、提取所有的sim函数
注:本文不会涉及完整实现,仅仅提供思路,懒得整的同学可以邮件联系我或者去我github里自取首先最重要的是理解getApiFunc和getApiInfo这俩到底能返回什么鬼东西。getApiFunc其实是关于查询的函数,也即可以查询任意你想要的sim函数,并根据关键词返回一个str list,而getApiInfo是关于解析的函数,将你填入的特定sim函数进行解析并返回相关的信息。由于coppeliaSim每一个版本都有很多不一样,例如4.7.0和4.9.0在RAR上就有挺多不一样的地方,所以这个地方根据你所用的版本不同自行查询在RAR中的解释。
from coppeliasim_zmqremoteapi_client import RemoteAPIClient
# 引入 RemoteAPI
client = RemoteAPIClient()
mainApp = client.require('sim')
mainApp.setStepping(True)
mainApp.startSimulation()
#工作流程 ......
mainApp.stopSimulation()
例如我现在先试着查询所有前缀是sim.的函数
funcName = mainApp.getApiFunc(-1,'sim.')
print(funcName)
# 打印结果:
# ['sim.acquireLock', 'sim.addDrawingObject', 'sim.addDrawingObjectItem', .................]
可以看到getApiFunc返回了超级多sim前缀的函数(还有一些甚至在RAR都找不到,也许是废弃的函数)
我们再试着去查询单个sim函数,看看会返回什么,就以最经典的getObject为例
funcInfo = mainApp.getApiInfo(-1,"sim.getObject")
print(funcInfo)
# 打印结果:
# int objectHandle = sim.getObject(string path, map options={})
可以看到其返回了一个对输出输入值进行描述的一个字符串,让我们看看对应这个函数的RAR是怎么写的:
这段输出的实际就是RAR中这个函数的概要,至于每个输入输出值什么意思,这个暂时没有提炼的方法,只能回到RAR去看。
已经知道了单个函数该如何提炼,接下来其实非常容易,无非就是按照类的格式给它重新提炼一下。我在这里使用的是reStructuredText风格注释。
# 例如将上面那个返回字符串通过一些函数能够自动编排成这样
def getObject(path: str, options: map):
"""
:param path : String
:param options : Map
:return: int objectHandle
"""
pass
通过编排后自动提炼的结果如下:
接下来的工作就是另开一个文件,我这里写成是coppeliaSimType.py
class coppeliaSimType:
def __init__(self):
pass
然后将输出的结果直接一粘贴即可,有些返回的函数不太符合预期,这是因为提炼的函数可能无法应对奇奇怪怪的格式,导致整段垮掉,没关系,我们人工给他修补一下即可
最后的最后我们在最开始的代码中规定类型,即可享受代码提示!
import coppeliaSimType
client = RemoteAPIClient()
mainApp: coppeliaSimType.coppeliaSimType= client.require('sim')
mainApp.setStepping(True)
mainApp.startSimulation()