利用ros2的image_pipeline软件包实现对相机的标定。

1.软件包安装

sudo apt install ros-humble-camera-calibration-parsers
sudo apt install ros-humble-camera-info-manager
sudo apt install ros-humble-launch-testing-ament-cmake

进入工作目录下载image_pipeline

cd ~/ros2_ws/src
git clone -b humble https://github.com/ros-perception/image_pipeline.git

 【报错】:RPC failed; curl 56 GnuTLS recv error (-9): Error decoding the received TLS packet 通常是由于网络连接问题,尤其是从 GitHub 克隆大型仓库时,可能会遇到网络不稳定或连接中断的情况。

【解决】: 默认情况下,Git 对 HTTP 请求的缓冲区大小有限制,你可以尝试增加缓冲区大小来解决此问题

git config --global http.postBuffer 524288000

 这会将缓冲区大小增加到 500MB,可能有助于解决因缓冲区不足导致的问题。

然后再次尝试克隆仓库:

git clone -b humble https://github.com/ros-perception/image_pipeline.git

编译软件包,添加环境变量 :

cd ~/ros2_ws
colcon build
source install/setup.bash

2.相机标定

启动相机节点:

cam2image 节点发布图像的topic为 /image,为了将topic重映射为/camera/iamge_raw,采用如下命令

ros2 run image_tools  cam2image --ros-args -p width:=640 -p height:=480 -p frequency:=30.0 -p device_id:=-1 -r /image:=/camera/image_raw

启动相机标定节点:

ros2 run camera_calibration cameracalibrator --size 11x8 --square 0.020 image:=/camera/image_raw camera:=/camera

【注意】:棋盘格内部角点和棋盘格行列数不相等,比如我的棋盘格是12*9,但是内部角点为11*8,其次根据自己棋盘格的大小更改square的值,我的是20mm。

标定板的参数需根据自己的实际情况设置。节点启动后会弹出一个窗口,窗口右侧有x,y,size,skew显示条,以及calibrate,save,commit按钮。

在相机视野范围内不断移动棋盘格,变化棋盘格姿态,使得棋盘到达相机视野左侧、右侧、顶部和底部。x,y,size分别对应标定板相对于相机的运动:x对应左右方向的运动,y对应上下方向的运动,size对应接近/靠近相机,skew对应倾斜姿态。

随着棋盘格的不断移动和变换姿态,标定窗口右侧x,y,size,skew对应的4个横条的长度会不断增长。当横条都变成绿色表示数据满足标定条件,此时,“CALIBRATE”按钮将会变亮,单击进行标定。标定完成后保存和提交按钮变亮。点击保存按钮后,结果自动保存到/tmp/calibrationdata.tar.gz中。

3.usb_cam的使用

安装usb_cam

sudo apt-get install ros-humble-usb-cam

启动usb_cam

ros2 launch usb_cam camera.launch.py 

报错:

Caught exception in launch (see debug for traceback): Caught exception when trying to load file of format [py]: No module named 'pydantic'

解决:下载pydantic库

pip install pydantic  -i https://pypi.tuna.tsinghua.edu.cn/simple some-package

继续启动:

ros2 launch usb_cam camera.launch.py 

报错:

Pydantic 版本要求 @root_validator 使用时必须指定 skip_on_failure=True,因为默认的 pre=False 设定可能会导致验证失败。

解决:

sudo vim /opt//ros/humble/share/usb_cam/launch/camera_config.py

原来的代码:

from pathlib import Path
from typing import List, Optional
 
from ament_index_python.packages import get_package_share_directory
from pydantic import BaseModel, root_validator, validator
 
USB_CAM_DIR = get_package_share_directory('usb_cam')
 
 
class CameraConfig(BaseModel):
    name: str = 'camera1'
    param_path: Path = Path(USB_CAM_DIR, 'config', 'params_1.yaml')
    remappings: Optional[List]
    namespace: Optional[str]
 
    @validator('param_path')
    def validate_param_path(cls, value):
        if value and not value.exists():
            raise FileNotFoundError(f'Could not find parameter file: {value}')
        return value
 
    @root_validator
    def validate_root(cls, values):
        name = values.get('name')
        remappings = values.get('remappings')
        if name and not remappings:
            # Automatically set remappings if name is set
            remappings = [
                ('image_raw', f'{name}/image_raw'),
                ('image_raw/compressed', f'{name}/image_compressed'),
                ('image_raw/compressedDepth', f'{name}/compressedDepth'),
                ('image_raw/theora', f'{name}/image_raw/theora'),
                ('camera_info', f'{name}/camera_info'),
            ]
        values['remappings'] = remappings
        return values       

修改后:

# Copyright 2023 usb_cam Authors
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
#    * Redistributions of source code must retain the above copyright
#      notice, this list of conditions and the following disclaimer.
#
#    * Redistributions in binary form must reproduce the above copyright
#      notice, this list of conditions and the following disclaimer in the
#      documentation and/or other materials provided with the distribution.
#
#    * Neither the name of the usb_cam Authors nor the names of its
#      contributors may be used to endorse or promote products derived from
#      this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
 
 
from pathlib import Path
from typing import List, Optional
 
from ament_index_python.packages import get_package_share_directory
#from pydantic import BaseModel, root_validator, validator
from pydantic import BaseModel, model_validator, validator
 
USB_CAM_DIR = get_package_share_directory('usb_cam')
 
 
class CameraConfig(BaseModel):
    name: str = 'camera1'
    param_path: Path = Path(USB_CAM_DIR, 'config', 'params_1.yaml')
    remappings: Optional[List[str]] = []
    namespace: Optional[str] = None
 
    @validator('param_path')
    def validate_param_path(cls, value):
        if value and not value.exists():
            raise FileNotFoundError(f'Could not find parameter file: {value}')
        return value
 
#    @root_validator
#   def validate_root(cls, values):
#        name = values.get('name')
#        remappings = values.get('remappings')
#        if name and not remappings:
#            # Automatically set remappings if name is set
#            remappings = [
#                ('image_raw', f'{name}/image_raw'),
#                ('image_raw/compressed', f'{name}/image_compressed'),
#                ('image_raw/compressedDepth', f'{name}/compressedDepth'),
#               ('image_raw/theora', f'{name}/image_raw/theora'),
#               ('camera_info', f'{name}/camera_info'),
#            ]
#        values['remappings'] = remappings
#        return value
    @validator('name')
    def validate_name(cls, value):
        if not value:
            raise ValueError("Name is required")
        return value
 
    def __init__(self, **data):
        super().__init__(**data)
        if self.name:
            # Automatically set remappings if name is set
            self.remappings.extend([
                ('image_raw', f'{self.name}/image_raw'),
                ('image_raw/compressed', f'{self.name}/image_compressed'),
                ('image_raw/compressedDepth', f'{self.name}/compressedDepth'),
                ('image_raw/theora', f'{self.name}/image_raw/theora'),
                ('camera_info', f'{self.name}/camera_info'),
            ])

继续启动:

ros2 launch usb_cam camera.launch.py 

报错:[ERROR] [usb_cam_node_exe-1]: process has died [pid 17787, exit code -11] 说明 usb_cam_node_exe 节点崩溃了,返回了 exit code -11(通常是段错误或内存访问错误)

可能是参数配置文件出现问题,查看相机支持的格式

修改 sudo vim /opt/ros/humble/share/usb_cam/config/params_1.yaml当中的pixel_format:改为相机支持的模式

修改后可正常运行launch文件

此后,如若需要修改相机参数,可打开/opt/ros/humble/share/usb_cam/config/params_1.yaml来修改
————————————————

参考:
                        
https://blog.csdn.net/weixin_60864335/article/details/130263861

ROS2使用usb_cam_ros2 usbcam-CSDN博客

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐