ものづくりのブログ

うちのネコを題材にしたものづくりができたらいいなと思っていろいろ奮闘してます。

【RaspberryPi】ros で usb カメラを扱ってみる

ros の勉強として usb カメラを扱ってみました。ここにメモを残します。

カメラについて

使用したカメラの情報です。

外観


商品データ

  • ビデオキャプチャ解像度: 480P
  • 接続: USB
  • レンズ焦点距離: F6.0MM
  • フォーカス範囲:20mm(最小)
  • ビデオ解像度: 640 x 480
  • ライン長: 最大65cm / 25.59inch

RaspberryPi の準備

Dockerfile

Dockerfile を作成します。

FROM ros:humble

RUN apt update && apt install -y \
    xterm \
    vim \
    ros-humble-usb-cam \
    ros-humble-image-tools \
    ros-humble-rqt-image-view \
    python3-opencv \
    && rm -rf /var/lib/apt/lists/*

WORKDIR /root/ros2_ws
COPY . /root/ros2_ws/

ENTRYPOINT ["/ros_entrypoint.sh"]
CMD ["bash"]

xhost

以下のコマンドで Docker コンテナで起動した GUI を local で表示します。
Docker が動いてるのはlocal上であり、特に指定しない限り root ユーザでコンテナが生成されます。

xhost +local:root
non-network local connections being added to access control list

イメージのビルド

Dockerfile を作成したディレクトリで、以下のコマンドを実行して Docker イメージをビルドします。

docker build -t my_ros2_camera .

ビルド完了後、以下のコマンドを実行して確認します。

docker images | grep my_ros2_camera
my_ros2_camera   latest    a57967aa678b   2 hours ago   1.86GB

コンテナ起動

イメージが作成できたら、コンテナを実行します。

docker run -it --rm \
    --device /dev/video0:/dev/video0 \
    --privileged \
    --net=host \
    -e DISPLAY=$DISPLAY \
    my_ros2_camera

docker コンテナ内の作業

カメラデバイスの確認

USB カメラが認識されているか確認します。

ls /dev/video*

python コード

Docker コンテナ内で USB カメラの映像を取得する Pythonノード (image_subscriber.py) を作成します。

import rclpy
from rclpy.node import Node
from sensor_msgs.msg import Image
from cv_bridge import CvBridge
import cv2

class ImageSubscriber(Node):
    def __init__(self):
        super().__init__('image_subscriber')
        self.subscription = self.create_subscription(
            Image,
            '/image_raw',
            self.image_callback,
            10)
        self.bridge = CvBridge()

    def image_callback(self, msg):
        cv_image = self.bridge.imgmsg_to_cv2(msg, desired_encoding="bgr8")
        cv2.imshow("Camera", cv_image)
        cv2.waitKey(1)

def main(args=None):
    rclpy.init(args=args)
    node = ImageSubscriber()
    rclpy.spin(node)
    node.destroy_node()
    rclpy.shutdown()
    cv2.destroyAllWindows()

if __name__ == '__main__':
    main()

カメラノードの起動

コンテナ内で、USBカメラのノードを起動できます。

ros2 run usb_cam usb_cam_node_exe

カクカクする場合は、以下で調整します。

ros2 run usb_cam usb_cam_node_exe \
  --ros-args \
  -p image_width:=320 \
  -p image_height:=240 \
  -p framerate:=10.0 \
  -p pixel_format:=yuyv \
  -p io_method:=mmap

パッケージ

パッケージの作成
mkdir ~/ros2_ws/src
cd ~/ros2_ws/src
ros2 pkg create --build-type ament_python my_package
image_subscriber.py の場所

作成した my_package の中に image_subscriber.py を配置します。

mv ~/ros2_ws/image_subscriber.py ~/ros2_ws/src/my_package/my_package/
setup.py の編集

my_package/setup.py を開いて、entry_points に image_subscriber を追加します。

root@test-desktop:~/ros2_ws# cat src/my_package/setup.py 
from setuptools import find_packages, setup

package_name = 'my_package'

setup(
    name=package_name,
    version='0.0.0',
    packages=find_packages(exclude=['test']),
    data_files=[
        ('share/ament_index/resource_index/packages',
            ['resource/' + package_name]),
        ('share/' + package_name, ['package.xml']),
    ],
    install_requires=['setuptools'],
    zip_safe=True,
    maintainer='root',
    maintainer_email='root@todo.todo',
    description='TODO: Package description',
    license='TODO: License declaration',
    tests_require=['pytest'],
    entry_points={
        'console_scripts': [
            'image_subscriber = my_package.image_subscriber:main', # <------------ 追加
        ],
    },
)

root@test-desktop:~/ros2_ws# 
ワークスペースをビルド

パッケージをビルドします。

cd ~/ros2_ws
colcon build --packages-select my_package

ビルド後、環境変数を設定します。

source install/setup.bash
パッケージ確認

以下のコマンドで my_package がリストに表示されるか確認します。

ros2 pkg list | grep my_package
my_package

ros2 run の実行

ros2 run my_package image_subscriber

作業風景

www.youtube.com