ROS 2 Jazzyで外部Pythonパッケージを管理する
はじめに
ROS 2 JazzyでPythonの外部パッケージを使おうと思ったのですが、pip install
やrosdep install
が弾かれるようになっていました。本記事ではこれを解決します。
$ pip install numpy
error: externally-managed-environment
× This environment is externally managed
╰─> To install Python packages system-wide, try apt install
python3-xyz, where xyz is the package you are trying to
install.
If you wish to install a non-Debian-packaged Python package,
create a virtual environment using python3 -m venv path/to/venv.
Then use path/to/venv/bin/python and path/to/venv/bin/pip. Make
sure you have python3-full installed.
If you wish to install a non-Debian packaged Python application,
it may be easiest to use pipx install xyz, which will manage a
virtual environment for you. Make sure you have pipx installed.
See /usr/share/doc/python3.12/README.venv for more information.
note: If you believe this is a mistake, please contact your Python installation or OS distribution provider. You can override this, at the risk of breaking your Python installation or OS, by passing --break-system-packages.
hint: See PEP 668 for the detailed specification.
これはROS 2ではなくpip側の更新による影響です。どうやらUbuntu 24.04での環境では、「生の環境に入れるなんて野蛮なことをするな!仮想環境を使え!」とのこと。
日本語の情報としては、以下の記事が参考になります。
この問題についてはROS Discourseでも議論されていました。
これらの記事で解決するかと思いきやキレイにやろうとすると意外とハマりポイントがあったため、その知見を共有します。
お手軽な方法
/etc/pip.conf
というファイルを作って以下のように記述します。
[install]
break-system-packages = true
これを一行で行うコマンドは以下です。
echo -e "[install]\nbreak-system-packages = true" | sudo tee /etc/pip.conf > /dev/null
以上でpip install
もrosdep install
も可能となりました。
いわゆる野蛮なことをしています。
もう少しちゃんとやる
上の方法はお手軽ですが、break-system
とか言われてしまうとギョッとしてしまいますよね。お行儀よくやるには少々面倒ですが以下のような方法があります。
sudo apt update
sudo apt install -y python3-venv
python3 -m venv --prompt ros2_ws ~/ros2_ws/.venv
source ~/ros2_ws/.venv/bin/activate
export PYTHONPATH=$(python -c 'import site; print(site.getsitepackages()[0])'):$PYTHONPATH
この例では~/ros2_ws
というROS 2のワークスペースとするディレクトリに.venv
というPythonの仮想環境の置き場を作り、それをactivateしています。注意として、activateしただけでは$PYTHONPATH
が追加されません。これはpython3
で実行したときは動作するがros2 run
で実行したときにはimport
ができないという状況になります。そのため、最後のコマンドで$PYTHONPATH
にこの仮想環境のパスを手動で追加しています。
activateするとターミナルの頭に(ros2_ws)
という表示がつきます。その後、各ROS 2パッケージで必要なPythonライブラリをpip install
なりrosdep install
なりで入れるという手順になります。
さらに細かい解説
python3 -m venv --prompt ros2_ws ~/ros2_ws/.venv
で、--prompt ros2_ws
というオプションを付けることで、ターミナルの表示を(ros2_ws)
に変更しています。このオプションを抜くと表示が(.venv)
となります。複数のワークスペースを持っている場合には、今どの仮想環境を動かしているかわかりにくくなるため、ワークスペース名と同じ名前で設定しておくとよいでしょう。
Pythonを用いたROS 2パッケージはsetuptoolsというPythonパッケージで管理されていますが、仮想環境にはこれが入っていませんでした。そのため、手始めにsetuptoolsをinstallしましょう。
pip install setuptools
その後、使用するROSパッケージで必要なPythonパッケージをインストールしていきましょう。
各ROSパッケージがrequirements.txtを持っている場合
もし、各ROSパッケージがrequirements.txt
を持っていれば、以下のように強引にすべて読み込む方法もあります。
find . -name "requirements.txt" -exec pip install -r {} \;
ただし、これはインストール順番やパッケージの重複などは加味されないため、以下のように1つに統合して整えてから実行すると良いと思います。
find . -name "requirements.txt" -exec cat {} \; > all-requirements.txt
sort all-requirements.txt -o sort-requirements.txt
requirements.txt
を確認・編集した後
pip install -r sort-requirements.txt
とすることで、整合性が取れたインストールができるかと思います。
また、作業中は気にすることはないかと思いますが、Pythonの仮想環境を抜けたい場合には、ターミナルにdeactivate
とコマンド入力してください。(ros2_ws)
という表示が取れていれば完了です。再度仮想環境に入りたければsource ~/ros2_ws/.venv/bin/activate
とすれば入れます。
しかしながらこの設定をもってしても、rosdep install
に関しては仮想環境ではなくシステム側のpipを使ってくるため、結局のところ前章と同じ状況にするしかありません。
PIP_BREAK_SYSTEM_PACKAGES=1 rosdep install -riy --from-paths src
ここでPIP_BREAK_SYSTEM_PACKAGES=1
を頭につけることで、後ろのコマンドに限りbreak-system-packagesの設定を有効にしています。ここについてよりよい方法が思いつく方が居りましたらご提案いただけますと幸いです。
別の方法
Pythonパッケージ管理のモダンなやり方として、uv
を使用するという方法もあるでしょう。
こちらの記事では単体のROSパッケージに対してPythonパッケージを管理しているものであり(というかこれが本来あるべき姿だと思うのですが)、複数のROSパッケージを使用するために、雑にROSワークスペース単位でPythonパッケージを管理したい場合には、前章で示したROSワークスペース下にvenvを作る方法が楽かと思います。ROSワークスペース単位でuv
するというのも良さそうですね。
またROS 2パッケージ単位でパッケージ管理をできるツールとしてament_virtualenvというものもあるようです。
自作のROSパッケージに関してはこれで整備するということもアリかと思いますが、これで作られていないパッケージ(たとえば人が作ったもの)が1つでも混ざると、いずれにしても前章までのような手段を取る必要があります。
おわりに
以下の方法を紹介しました。
- break-system-packagesを許可
- お手軽だが野蛮
- venvを構築
-
ros2 run
などからも読めるように$PYTHONPATH
を追加 -
pip install
で丁寧に入れる必要あり -
rosdep install
するならいずれにしてもbreak-system-packagesをオン
-
- パッケージ単位で管理
- 特有の書き方や実行の仕方が必要
- 使いたいROSパッケージがすべて管理されているとは限らない
よりよい方法がありましたら、ぜひ教えてください。
Discussion