ecal的安装先要安装整个的ecal,最后的latest可以替换成你想要的适合的版本
sudo add-apt-repository ppa:ecal/ecal-latest sudo apt-get update sudo apt-get install ecal
然后再用pip install ecal5,安装python开发的库
官网上的pip install python3-ecal5的写法是错误的
ecal的自定义msg传输有两个参数,第一个为订阅的名字,第二个为类型,其实两个在底层都是字符串,传输可以使用比它推荐的protobuf更快的capnp,后面的序列化工具更快而且可操作也很多
#eCAL subscriber
class subscriber(object):
def __init__(self, topic_name, topic_type=""):
#initialize subscriber
:param topic_name: the unique topic name
:type topic_name: string
:param topic_type: optional topic type name
:type topic_type: string
python的命令行使用是在当前目录下的,例如我当前位置是:/home/bot
在该目录下的py文件使用语句os.system("python3 src/img_save/scripts/test2_image.py")
然后这个test2_image.py文件就会在/home/bot的环境下启动
所以如果使用:capnp.add_import_hook(['../src/capnp'])是无法成功的,因为这个test2_image.py
目前的环境是/home/bot,所以需要改成capnp.add_import_hook(['src/img_save/src/capnp'])
"""
即使你的capnp_subscriber.py在你的同级目录下
但是由于启动test2_image.py的环境的位置为其他地方
就会导致找不到capnp_subscriber.py这个文件
也就无法导入CapnpSubscriber这个模块
所以当出现导包不成功时,
办法一:首先我们先使用os.system("pwd")找到当前目录
看看自己在什么地方,然后再添加绝对或者相对目录去让python能找到对应的文件
"""
# test2_image.py
import sys
sys.path.append('/src/img_save/scripts')
from capnp_subscriber import CapnpSubscriber
capnp.add_import_hook(['src/img_save/src/capnp'])
import image_capnp as eCALImage
"""
办法二(最好最实用):直接读取所要启动的脚本文件的绝对目录
然后再根据这个绝对目录去用相对目录的思想去添加路径
这样可以保证在不同的启动地方也能找到对应的文件
"""
script_path = __file__ #获得当前文件的绝对路径
directory_path = os.path.dirname(script_path) #获得当前文件的文件夹路径
sys.path.append(directory_path)
from capnp_subscriber import CapnpSubscriber
capnp_path=directory_path+"/capnp"
capnp.add_import_hook([f'{capnp_path}'])
import image_capnp as eCALImage
"""
其他那些包能找到是因为它们都下载到了python安装目录下的某个位置
这个位置在系统的环境变量里面有保存,所以可以直接找到,不需要再添加位置
"""
钩子函数:添加一个查询的路径,比如
capnp.add_import_hook(['src/img_save/src/capnp'])#添加了一个capnp专门的查找路径
import image_capnp as eCALImage
#因为capnp的文件规则是读取image.capnp文件就需要写成image_capnp,python是没法知道这个规则的,所以前面加了钩子函数,这样就可以了
ros里,有依赖关系的两个脚本,例如a.py 里有import b,如果两个都需要运行,最好不要在cmakefile里对这两个编译,因为到时候ros会把编译好的文件放到devel/lib/包名 里面,然后启动的时候,运行a.py时,由于需要import b,所以ros会从devel/lib/包名里面找b,但是这个路径是不对的,所以如果有需要,应该把a需要的东西拉出来加一个中间文件c,不参与cmakefile编译,防止系统出错
python的赋值问题:
-
可变与不可变类型: Python中的数据类型分为可变类型(如列表、字典、集合、类实例等)和不可变类型(如整数、浮点数、字符串、元组等)。当你复制一个不可变类型的数据时,你实际上得到了一个新的独立的对象,但复制一个可变类型的数据,你只是得到了一个新的引用指向同一个对象。
-
赋值与复制: 在Python中,赋值操作(
=
)只是创建了一个指向内存地址的引用。如果你复制了一个列表或字典,但原始数据被修改了,那么复制的副本也会反映出这些修改,因为它们引用的是同一个对象。 -
深拷贝与浅拷贝:
- 浅拷贝(shallow copy):创建一个新的对象,但它的元素仍然是原始对象的引用。这可以通过
list()
、dict()
、对象的.copy()
方法或copy
模块的copy()
函数来实现。 - 深拷贝(deep copy):创建一个新的对象,并且递归地为原始对象的所有元素创建新的副本。这可以通过
copy.deepcopy()
来实现
- 浅拷贝(shallow copy):创建一个新的对象,但它的元素仍然是原始对象的引用。这可以通过
类的静态成员变量问题:
class ms:
i=0 #静态变量
lisa=[] #静态变量
def __init__(self): #用self的都是成员变量,新创建的
self.data=[]
def f(self):
self.i+=10 #这个i其实是成员变量
ms.lisa.append(self.i)
self.data.append(self.i)
return self.i
a=ms()
b=ms()
a.i=50 #其实这个a.i是动态创建的新的成员变量(如果类里原来没有的话),而不是ms里面的静态变量i,要访问静态变量i需要使用:ms.i
Linux下python的环境问题,首先Linux一般都会自带python,像Ubuntu20.04就是自带python3.8,然后这个python一般放在/usr/bin文件里面,有个python3的程序,大概率是软链接,然后pip的关联的python版本也是可以通过 vim /usr/bin/pip里面在开头找到他是属于哪个python版本的pip
其实具体流程就是,python3 ——(从环境变量里面从头开始找到python3) ——(这个python3是个软链接,去执行真正的python3.8)
(所以如果你觉得版本错乱了,你可以先which python3,先找到是从哪里开始执行的,然后再看它的软链接指向)
这是/usr/bin/pip里面的指向,所以这个pip也是属于python3.8的
如果想要指定某个python版本的pip的话,就可以这样写:python3.11 -m pip install xxx
同时要注意,如果使用sudo,那么你的环境就是本地的环境了,假如你现在使用conda创建的环境,使用sudo的话也会回到原本的环境里
Linux里面,如果用的是图形窗口,直接点击软件打开,可能会没法更新系统环境信息,比如vscode,直接打开的话,之前设置的系统环境变量可能在它里面的终端是没被修改或者不对的,所以要从终端打开它
#!/usr/bin/python3
# -*- coding: utf-8 -*-
# generated from catkin/cmake/template/script.py.in
# creates a relay to a python script source file, acting as that file.
# The purpose is that of a symlink
python_script = '/home/gds/lobot2/src/img_save/scripts/yolo_recive_R.py'
with open(python_script, 'r') as fh:
context = {
'__builtins__': __builtins__,
'__doc__': None,
'__file__': python_script,
'__name__': __name__,
'__package__': None,
}
exec(compile(fh.read(), python_script, 'exec'), context)
ros使用exec去运行指定位置的python节点脚本文件,而不是用命令行去启动,原因是
环境隔离:exec
可以在当前Python解释器环境中执行脚本,这保证了脚本能够访问到正确的Python模块和依赖,同时避免了与当前shell环境的潜在冲突。
变量和命名空间控制:通过exec
,可以精确控制脚本执行时的全局命名空间。如你提供的代码片段所示,通过传递一个context
字典给exec
,可以在执行的脚本中模拟一个独立的全局命名空间,这有助于避免变量污染。
(其实还有很多其他的,用exec去执行就是把代码一条条的按照字符串的方式去运行)
不管什么语言什么编译器,都尽量不要把test作为文件名,因为很多时候test有其特殊含义,如在CMakelists里,当项目启动了CTest(CMake的测试驱动程序)时,不能使用“test”作为可执行文件或库的名称。
python创建特定的二维数组:
用torch.load读取整个模型时,读取到的是这个.pt或.pth的所有信息,并且里面全是以字典的形式保存的,其中可能会包含了各种说明和层与参数,但是我们需要加载一个模型时,并不是需要这么多的东西
假设我们有一个只保存了模型参数,也就是各个层的参数的.pt或.pth文件,首先使用torch.load读取,然后可以把这个参数用load_state_dict读取到与这个模型对应的对象里面,如:
我们需要先创建一个跟这个.pt模型一样的对象,然后将模型的训练好的参数复制进去就行了
model_restoration = MB_TaylorFormer()
checkpoint = torch.load(r"OTS-MB-TaylorFormer-B.pth")
model_restoration.load_state_dict(checkpoint["params"])
model_restoration.cuda()
model_restoration = nn.DataParallel(model_restoration)
model_restoration.eval()
并且,如果是.pt文件,有可能其中直接就有完整的一个模型对象,例如下面这个例子,
mod[model]就是一个yolov10DetectObject,直接就可以用的,直接就能:
model=mod[model]
model(input_data) #使用继承自nn.moduel的forward函数
python路径问题:找不到的路径,把这个项目文件转成包