Inside of LOVOT

GROOVE X 技術ブログ

Jammy でも Noetic したい

お急ぎの方へ

ROS 1 Noetic の Jammy (Ubuntu 22.04) 向け deb パッケージを公開 apt リポジトリに登録しました。 数行のコマンド実行で ROS 1 環境が Jammy 上で作れます。 とりあえず、すぐに使いたい という人は こちら を御覧ください。

はじめに

LOVOT の開発では ROS というロボット開発に便利な OSS を一部で使用しています。 現在 ROS には ROS 1 と ROS 2 の2種類が存在していて、この2つは目的は同じでありつつも、互換性が無い形で存在しています。

ROS 1 と ROS 2 のディストリビューションは下記サイトにそれぞれまとまっています。

最近のものについてまとめるとこんな感じになります。

ROS Focal(20.04) Jammy(22.04)
ROS 1 Noetic
EoL: May 2025
無し
ROS 2 Foxy
EoL: June 20th, 2023
Humble
EoL: May 2027

2023年7月現在、Focal では ROS 1 はサポートされているが ROS 2 はサポートされておらず、Jammy では ROS 2 はサポートされているが ROS 1 はサポートされていない、という状況です。 LOVOT では、これまで ROS 1 を使用しておりまして、今後、もしOSのバージョンを変更するとなった場合に、OSと同時に ROS 2 への移行をする必要があります。変更が大きくなるとリスクも高まってしまうので、できれば避けたいです。そのため、 Jammy で Noetic を動かせるようにすることで、移行リスクを低くできるようにしたいと考えました。 そこで、今回のブログの Noetic on Jammy となるわけです。

今回の目標

前置きが長くなってしまいましたが、 Jammy でも Noetic したい ということです。 ソースからビルドして動かしている人はネット上で見かけるものの、debパッケージ化されているものは見つからず。 やっぱりパッケージ化されていた方が使いやすいよね。

ということで最終的な目標を下記のように設定しました。

  • deb パッケージを作る
  • リポジトリを登録すればすぐに使える
  • sudo apt install ros-noetic-desktop-full ができる

ビルド手順

ビルド用ツールの作成

ROS 1 では python ベースのビルド用ツールが用意されています。 まずはこちらを deb パッケージ化していきます。

依存関係の解決に rosdep というツールを利用するのですが、これには rosdistro, rospkg, catkin_pkg というパッケージが必要になります。 また、これらのツールの deb パッケージを生成するのに ros_release_python というツールを使用します。 これらは全て ros-infrastructure に用意されています。

手順はこんな感じですね。

apt install sudo
sudo apt update
sudo apt upgrade -y
sudo apt install -y git dh-python python3 python3-setuptools python3-stdeb python3-dateutil python3-docutils

cd ~
mkdir src
cd src

git clone https://github.com/ros-infrastructure/ros_release_python.git
sudo ln -sf $(readlink -f ros_release_python/scripts/ros_release_python) /usr/local/bin/

git clone https://github.com/ros-infrastructure/catkin_pkg.git
cd catkin_pkg
ros_release_python deb3
sudo apt install -y ./deb_dist/*.deb
cd ..

git clone https://github.com/ros-infrastructure/rospkg.git
cd rospkg
ros_release_python deb3
sudo apt install -y ./deb_dist/*.deb
cd ..

git clone https://github.com/ros-infrastructure/rosdistro.git
cd rosdistro
ros_release_python deb3
sudo apt install -y ./deb_dist/*.deb
cd ..

git clone https://github.com/ros-infrastructure/rosdep.git
cd rosdep
ros_release_python deb3
sudo apt install -y ./deb_dist/*.deb
cd ..

パッケージのビルド

ビルドツールが出来上がったら、それを使ってどんどんパッケージをビルドしていきます。 依存関係を確認しながら、順番に生成し、インストールします。

パッケージの生成には bloom を使うのですが、私の手元ではうまくビルドできなかったので、今回は pip で入れちゃいます。

sudo apt install -y python3-pip
sudo pip install bloom

次に ros 関連のパッケージをビルドしていきます。 基本的には bloom-generate でビルド環境を構築して、 fakeroot でビルドするという流れになります。以下にcatkinの例を書きます。

sudo apt install -y cmake
sudo rosdep init
rosdep update

git clone https://github.com/ros/catkin.git
cd catkin
bloom-generate rosdebian --os-name ubuntu --os-version jammy --ros-distro noetic
fakeroot debian/rules "binary --parallel"

# dpkg-deb: building package 'ros-noetic-catkin' in '../ros-noetic-catkin_0.8.10-0jammy_arm64.deb'.
# という感じで1つ上のディレクトリに deb パッケージができる

sudo apt install -y ../*.deb

依存関係の注意事項1

パッケージには依存関係があるので、ビルドする順番に注意が必要です。上記の例にした catkin は実は依存で最上位のパッケージなので、他のパッケージが何も無くてもビルドできます。 catkin の次にビルドできるのは genmsg などがあります。 ここらへんの依存関係は各パッケージの package.xmlに書いてあるのですが、網羅するには関連リポジトリを全部落とさないといけないので大変ですよね。ですので、ROS公式ではxml情報も含めたパッケージ一覧情報が公開されています。 distribution_cachegzipファイルの中身がそれにあたります。

  noetic:
    distribution: [noetic/distribution.yaml]
    distribution_cache: http://repositories.ros.org/rosdistro_cache/noetic-cache.yaml.gz
    distribution_status: active
    distribution_type: ros1
    python_version: 3

依存関係の注意事項2

bloom を利用した依存関係の解決では rosdep を利用して、外部サイトの情報を見に行くようになっていますが、そこには対応するOSバージョンなども記載されており、 Noetic が Jammy に対応していないと怒られてしまいます。

$ bloom-generate rosdebian --os-name ubuntu --os-version jammy --ros-distro noetic
/usr/lib/python3/dist-packages/pkg_resources/__init__.py:116: PkgResourcesDeprecationWarning:  is an invalid version and will not be supported in a future release
  warnings.warn(
/usr/lib/python3/dist-packages/pkg_resources/__init__.py:116: PkgResourcesDeprecationWarning:  is an invalid version and will not be supported in a future release
  warnings.warn(
ROS Distro index file associate with commit 'dbc7f9c9074335122cdde08048d7f51755ccdc96'
New ROS Distro index url: 'https://raw.githubusercontent.com/ros/rosdistro/dbc7f9c9074335122cdde08048d7f51755ccdc96/index-v4.yaml'
==> Generating debs for ubuntu:jammy for package(s) ['genmsg']
Could not resolve rosdep key 'catkin' for distro 'jammy':
No definition of [catkin] for OS version [jammy]
    rosdep key : catkin
    OS name    : ubuntu
    OS version : jammy
    Data:
_is_ros: true
        osx:
          homebrew:
            packages:
            - ros/noetic/catkin
        ubuntu:
          focal:
            apt:
              packages:
              - ros-noetic-catkin

Try to resolve the problem with rosdep and then continue.
Continue [Y/n]?

これを解消する方法としては rosdep が見に行く先として、ローカルのyamlファイルを追加します。 以下のような感じで、依存するパッケージ名と、それに対応するaptパッケージ名を記述していきます。

catkin:
  ubuntu: ros-noetic-catkin

そのファイルを参照するように設定ファイルを追加して、 rosdep update をすれば、ローカルのファイルも見に行くようになります。

echo "yaml file:///root/rosdep.yaml" > /etc/ros/rosdep/sources.list.d/99-custom.list
rosdep update

Jammy 特別対応

一部のパッケージは Focal 向けのままでは Jammy でビルドできないため、下記のような対応が必要になります。

  • ビルド時のc++ standard version として c++17 を指定すること
    • 一部のコードで shared_mutex()shared_lock() を使っているため
    • なぜか Focal では c++11 が指定されていてもビルドが通る
  • diagnostic_common_diagnosticshddtemp の依存を削除
    • hddtemp 自体が Jammy のパッケージとして用意されていない
  • catkin のビルド時の設定を CATKIN_BUILD_BINARY_PACKAGE="0" に変更する
    • setup.bash 等のファイルを生成するのに必要

上記の作業を一気に処理するのがこちらのスクリプトです。

set -xeu
repo_path=$1
pkg_name=$2
export DEB_BUILD_OPTIONS="parallel=$(nproc)"

cd $repo_path
for xml_path in $(find . -name package.xml); do
  xml_pkg=$(xmllint --xpath /package/name $xml_path | sed 's/^.*<name.*>\(.*\)<\/name>.*$/\1/g')
  if [ "$xml_pkg" = "$pkg_name" ]; then
    pkg_path=$(dirname $xml_path)
    cd $pkg_path
    # 既存のビルドファイルを削除
    rm -rf debian .obj*
    # shared_mutex, shared_lock 等への対策 (c++17) にする
    sed -i -e 's/\+\+\(11\|14\)/++17/g' CMakeLists.txt
    sed -i -e 's/CMAKE_CXX_STANDARD \(11\|14\)/CMAKE_CXX_STANDARD 17/g' CMakeLists.txt
    # diagnostic_common_diagnostics への対策 hddtemp 問題でビルドできない
    sed -i -e 's/<run_depend>hddtemp<\/run_depend>//g' package.xml
    bloom-generate rosdebian --os-name ubuntu --os-version jammy --ros-distro noetic
    # catkinパッケージに setup.bash 等を含めるための対策
    if [ "$pkg_name" = "catkin" ]; then
      sed -i -e 's/CATKIN_BUILD_BINARY_PACKAGE="1"/CATKIN_BUILD_BINARY_PACKAGE="0"/g' debian/rules
    fi
    fakeroot debian/rules "binary --parallel"
    cd .. && apt-get install --no-install-recommends -y ./ros-noetic-*.deb && mv ./ros-noetic-*.deb /tmp/deb
    break
  fi
done

bash build_ros_package.sh /root/noetic_build/src/catkin catkin のように、ソースのディレクトリとパッケージ名を指定して使います。 最終的に出来上がった全てのパッケージをパッケージリポジトリに登録すれば完了です。

ビルド環境生成ツール

これらのビルド手順を docker 環境内で make 一発でビルドできるようにするツールを作成しました。 今回公開したパッケージはこちらのツールで生成しております。

github.com

このツールを使う場合は下記のような手順になります。

# 環境生成 ros_base, desktop, desktop_full に対応
make ros_base

# docker 環境作成 & login
make login

# docker環境内で
make

# 生成された deb ファイルは /tmp/deb にあります

インストール手順

GROOVE X で作成したパッケージは Packagecloud で公開しています。 amd64向け ros-noetic-desktop-full と arm64向け ros-noetic-desktop + α が登録されています。 arm64向け desktop_full は Jammy に Gazebo が無かったため、ビルドできませんでした。

packagecloud.io

利用手順をまとめたものは下記の通りです。

apt update
apt upgrade -y
apt install -y curl

# apt リポジトリの追加
curl -s https://packagecloud.io/install/repositories/groove-x/ros/script.deb.sh | sudo bash

# ROS のインストール
apt install -y ros-noetic-desktop-full

Jammy での ROS 1 ライフをお楽しみください〜

付録

今回の実行環境

amd64
$ uname -srvmp
Linux 5.15.0-75-generic #82~20.04.1-Ubuntu SMP Wed Jun 7 19:37:37 UTC 2023 x86_64 x86_64
$ ./.venv/bin/python --version
Python 3.8.10
$ docker -v
Docker version 20.10.21, build 20.10.21-0ubuntu1~20.04.2
arm64

arm向けは M1 Mac の環境で実行しました。

$ uname -srvmp
Darwin 21.6.0 Darwin Kernel Version 21.6.0: Thu Jun  8 23:56:13 PDT 2023; root:xnu-8020.240.18.701.6~1/RELEASE_ARM64_T6000 arm64 arm
$ ./.venv/bin/python --version
Python 3.10.2
$ docker -v
Docker version 24.0.2, build cb74dfc

今後の話

ビルドできるパッケージを増やしていく予定です。 一度、全パッケージのビルドを試みたのですが、引っ掛かりポイントが多すぎて、 desktop_full までとしました。 desktop_full 以外でもよく使われているパッケージはたくさんあるので、順次対応していきたいと思っています。

一応、現状でも、複数ターゲットを設定することはできるので、他に必要なものがある場合は列挙してビルドすることが可能です。

arm64 では simulators がビルドできないので、こんな感じで指定しています

desktop_full_arm64: venv gen_build_env.py
    $(VENV)/python gen_build_env.py --targets desktop perception stage_ros