衝撃のわからなさ

わかってません

PFNから数えて計4年4ヶ月勤めたPreferred Roboticsを退職して、転職活動しながらクロスコンパイル環境を作ったりしています

はじめに

退職しました。
カチャカというロボットに主に組み込みまわりで関わっていて、発売されて満足しました。
量産ロボットに携わるという夢が1つも叶いました。

2ヶ月の有休期間中に、この間に作成したmimic-crossというクロスコンパイル用のDocker imageを 整備していろいろな人に使ってもらえるようにできればと考えています。
この記事ではなぜこのツールを開発した背景を振り返りながら、課題と共に紹介します。

背景

PFN入社からしてすぐ、後にカチャカとなるプロジェクトで ARM CPUボードへのインテグが始まろうとしており、 全体SlackでYoctoを知っている人がいないかという呼びかけがされてました。

私自身はPFVMという自社のNN実行フレームワークを作成するチームに配属されましたが、 ロボットのチームがこのフレームワークを使う橋渡しのようなことをやってもらいたいと言われていました。
記念受験のつもりで受けたPFNに運良く採用してもらえたのは、こういった仕事があったおかげだと思います。 本当に幸運でした。

前職のルネサスエレクトロニクスでYoctoを利用したLinux BSPまわりの業務経験があった私はもちろんすぐに手をあげ、 最終的にはロボットとエフォート50/50で働いていました。

Yocto vs Ubuntu

今組み込みまわりのディストリビューションを選定するとき、主にこれらの系統の2つを比較することになるかと思います。 私の認識ではありますが、簡単にそれぞれの特徴をまとめてみます。

Yocto

  • 特定のHWや製品向けにカスタムがしやすく、組み込みLinuxのベースとして広く使われている
  • 強力なライセンス管理機能があり、ライセンスリスト作成や特定条件を満たさないライセンスの除外などが行いやすい
  • ロスコンパイル向けのレシピを書く仕組みがある
  • ビルド済みパッケージの配布はなく、新規パッケージのビルドに時間がかかることがある
  • 対応していないソフトウェアは新規にbitbake形式のレシピを書く必要がある

Ubuntu

  • カスタムしやすくはない。その代わりHWが違っても環境が揃いやすい
  • パッケージにライセンスが同梱されてはいるが、特に管理機能はない
  • ロスコンパイルを書きやすくする仕組みはない、クロスコンパイルツールは提供されてはいる
  • ビルド済みパッケージが配布されており、非組み込み環境の資産を活用し易い
  • 多くのソフトウェアやライブラリが標準環境として利用しており、独自の手順が必要になりにくい

ディストリビューションを作る側に優しいのはYocto。
アプリケーション開発の観点からは普段のマシンの開発と同じようにUbuntuを使いたいというのが多いのではないでしょうか。

多くのソフトウェアやライブラリはUbuntuをサポート環境として提供していますが、Yoctoはサポートしていません。
カチャカには様々なソフトウェアスタックが搭載されています。
組み込み向けに開発されていない多くのソフトウェアをCPUにデプロイする必要がありました。

またAIは発展速度が早く、新しく出てくるものをすぐに試して開発サイクルを回す必要があります。
新しく出てきたものを手数少なく、エッジデバイスで動かす必要がありました。

ロスコンパイルの問題を解決してUbuntuを採用できれば最高なのだけれど…どうしようというのが検討段階の問題でした。

ロスコンパイルの問題

ロスコンパイル簡単じゃないという話

コンパイラ変えたりarchitecture指定とかすればいいでしょ?と思うかもしれません。 そもそも工数が発生してしまうのは開発サイクルからは好ましくありあますせん。 クロスコンパイルの手順は言語やビルドツールそれぞれで違い、1つ1つ対処していかなくては行けないのです。 依存パッケージを取得するのだってそのままapt-getするのではすみません。

さらに、PythonパッケージがC/C++のビルドを含む場合などはそもそもパッチを当てないとクロスコンパイルできない可能性があります。
開発開始当時はまだnumpyやgrpcなどもaarch64向けにはビルド済みパッケージが提供されておらず、 ロボットという多くのものを扱うプロダクトでこれらのものを1つ1つ確認して対処するのは困難でした。

また自身の開発チームのプロダクトもC++をビルドしてPython Wheelを作成しており対応が必要でした。

こういったケースで以下のような対応策を取られる事が多いかと思います。

ネイティブコンパイル

プロジェクトでもまずネイティブコンパイルが試されてました。
しかしメモリが4GBしかないボードではメモリ不足でビルドを回すことができませんでした。
また(当時は)CI環境でARMインスタンスを使うことができず、Apple SiliconのPCや性能の高いJetsonなどもなく、 利用することができない状態でした。

これは今日の開発においてもクラウドサービスがARM環境を選択できない、あってもARM + CUDAのテストはできない。 開発PCはx86_64マシンであるなどの問題があるかと思います。

QEMUを利用したクロスコンパイル

その他の解決方法として検索するとよく出てくるのはQEMUを使うという方法です。
この方法は遅いという問題があります。 呼び出される命令によりまちまちですが、私はQEMUにした場合およそ10倍ぐらいになるかなと普段見積もっています。

QEMUを使ってビルドはできてたのですが、プロジェクト初期の段階ですでにフルビルドが走ると2日かかっており、 QEMUのように使えて早い環境があれば…!となってました。

mimic-crossを作った

ということで作られたのがこちらです。
(業務時間外で作ってOSSと言い張ってきたので手元にある。)

github.com

これは単純にbinutilsをビルドしている例です。
このようにbaseimageを付け替えることで--platform=linux/arm64つけてクロスコンパイルした場合の時間が、 ubuntu:22.04指定の 434.8sec → 34.6sec に短縮できています。

同じ Dockerfileでnativeビルドもできるため、テストやシミュレータなどはnativeで実行するなどの使い分けもできます。

# FROM ubuntu:22.04
FROM --platform=${BUILDPLATFORM} impactaky/mc-ubuntu22.04-${TARGETARCH}:2.0.0

RUN apt-get update && \
    apt-get install -y --no-install-recommends \
        wget ca-certificates \
        binutils gcc make libc6-dev && \
    apt-get clean && \
    rm -rf /var/lib/apt/lists

RUN wget -q https://ftp.gnu.org/gnu/binutils/binutils-2.36.tar.gz \
    && tar xf ./binutils-2.36.tar.gz
WORKDIR /binutils-2.36
RUN ./configure
RUN make -j "$(nproc)"

良いと思ったらsponsorください(直球)

mimic-crossは3年以上前から存在していてカチャカのソフトウェアビルドに使っていたのですが、 すべてbashで書いてしまいメンテが絶望的だったので今年の年末あたりから書き直し始め、 有給休暇の力で一旦旧実装程度まで実装ができました。

まだまだいろいろなコーナーケースがあると思うのですが、イメージを付け替えるだけで試せるので、 ぜひ試して問題など教えていただけると嬉しいです。

対応したい機能はまだまだ大量にあり、今後も継続して開発するつもりです。
3月末までは有給なので特に頑張ります。

このプロジェクトがクロスコンパイルできなくて困っているなどありましたら、 教えていただけると嬉しいです!

今後について

決まってません! このクロスコンパイル環境の開発は継続していきたいと考えており、このような環境の需要を抱えている会社を御存じでしたら、教えていただけると大変ありがたいです。

組み込みソフトウェアというのは多くの会社において、プロダクトを作成するのに必要な1要素であり、 プロジェクトの競争力をもたらすものではなく、枯れた要素を使うべき領域だとされると思います。
しかしながらこの記事で述べたように、AIなどの開発が早く新しい技術と枯れた部分の界面になる領域でもあります。
mimic-crossのようなツールを作成することで、このような界面への課題に取り組むことができればいいなと考えています。

長い記事を最後まで呼んでいただきありがとうございました!

模索する楽しさを思い出したのと、家庭用ロボットと、ロボットエンジニアになれなかった自分のためにAPIを作っている話

1年半ほど前からロボットの会社に転職して模索する楽しさを思い出した気がするという話と、思い出す助けができるかもしれないという話。
自分のようにロボットを諦めた人とか、やってみたいと思っている人に読んで欲しい。

模索は楽しい

ロボットエンジニアにはなれなかったものの、学生時代は結構ロボットをやっていた。
一年生からロボットサークルに入り、くらだないアイディアを大量にある時間を投じて試したりするのが今になって思えば楽しかったのだなと。
すでに検証されていたのかとか別段気にしていなかったし、こうして少しずつやったことを積み上げるのというのはとても良い経験だったと思う。

模索は避けるべき

ただ多くのことは先人が行っており、成果を上げるためには無駄な模索は避けるべきだという現実に直面していく。
仕事をこなしていくことが更に大切になり、世の中には大量のベストプラクティスが溢れておりそれらを学ぶべきと。まぁこれは間違ってないと思う。
そして模索というのは楽しいものではなく避けるべき無駄な時間だという価値観にだんだん変わってしまっていた。

家庭用ロボットと模索

1年半前からロボットの会社に転職し、カチャカという家庭用ロボットを作っている。

こんなこと書いたらあとで怒られるかもしれないけれどレストランで動いている配膳ロボットを見たことあったらそれを、 小さくして棚を自動着脱可能にした感じ。あと家庭向けなので安い(配膳ロボが300万ぐらいすることを最近知った)

kachaka.life

で、この家庭用ロボットとかいうものは家で使い道を考えることになる。
自分がどう使っているかはこの記事の本題と逸れるので今度書く。

で、あーだこーだやっている中でこの感覚が懐かしいなと気づいた。サークルの頃みたいだなと。

白紙が多い領域を模索するのが楽しい

模索は楽しいが、昔のようになんでも模索するというのはもう楽しめなくなってしまっている。そういった点で昔とは少し違う。
先人に学ぶことを覚えてしまったのと、仕事をしていると時間が有限だというのがあると思う。
つまりまだ先人のいない領域の模索というのが一番楽しいく手放しに感じることができるのだと気づいた。

家庭用ロボットを模索するということ

とはいえこの情報社会、多くの先行例に簡単に触れられるのでそういう領域が少ない。
家庭用ロボットはまだまだこれからのものなので、そういう点では白紙の部分が多い。
さらに今後確実にロボットが家庭に普及していくとは思っている人は多いはずだ。だからこの分野を模索しながら考えることには意味がある。
配膳ロボットに気づくどころか模索もしていなかったのは、ただのロボット好きとしてダメだなと転職してから反省した。

ということで模索しませんか

ということで、家庭用ロボットを家で使うだけで十分模索はできるのでやりませんか。

また自分のようにロボットわからなくてもプログラムは少し書けるという人が、 できることを増やするるようにAPIを作って簡単に操作できるようにしています。

カチャカは体内でjupyterが動かせて開発環境すらいらなし、 このぐらいのコードでワゴンをキッチンに運ぶということができる。
家具や場所の登録はアプリから簡単にできるようになっている。
とかなり優しく作ったつもり。

import kachaka_api
client.update_resolver()
client = kachaka_api.KachakaApiClient()
client.move_shelf("ワゴン", "キッチン")

けれどもAPI公開してワークショップもやるということが話題になっているのは、 現役バリバリロボットを触っている人だなーと思って申し訳程度にこの記事を書きました。
ロボットから離れてしまった人、ロボットをやってみたいなとは思っていた人がぜひ、買わずともこのワークショップに参加してくれたら嬉しいです。

/etc/lsb-releaseも/etc/issueも合ってるのにlsb-releaseが変なバージョン出してきた

検索するとみんな/etc/lsb-releaseを直して解決したと行っているがあっているので仕方なくコードを読んだ。 こうなってた

$ cat /usr/lib/os-release
NAME="Ubuntu"
VERSION="20.04.3 LTS (Focal Fossa)"
ID=ubuntu
ID_LIKE=debian
PRETTY_NAME="Ubuntu 20.04.3 LTS"
VERSION_ID="18.04"
HOME_URL="https://www.ubuntu.com/"
SUPPORT_URL="https://help.ubuntu.com/"
BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/"
PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy"
VERSION_CODENAME=focal
UBUNTU_CODENAME=focal

vimのkeymapを考え直したくなったので整理

デバッガをポンポン使えるキーマップをガッツリ足したくなってprefixが足りない気持ちになったので整理する

小指

小指+何かは打ちやすいからこれをprefixキーにしたい筆頭な気がする

  • q
    • たまに誤爆して面倒なことになるから 何か+qにマップして空けても良さそう
  • a
  • z
    • 2番目に使っているprefix, 現在はfodling使うの諦めている、便利かもしれないのでzαを別に移してfolding使ってみてもいいかもしれない
  • p
  • ;
    • 使いこなせてないしprefixにして良さそうだが、'prefixと混同しそう
  • /
  • [ と ]
    • 1mmも使えこなせてない、そもそも押しにくく追いやられた機能たちがいる気がする
  • '
    • もっとも使っているprefix, もとの機能を一応''にマップしている
  • \
    • 予約機能らしい。押しにくい

薬指

  • w
  • s
    • 一般的にprefix候補筆頭のやつ。easy motionにしているけどほぼ使えてない。でもeasymotionにマップしておいたほうが便利な気もする
  • x
    • 地味に使う気がするけれどprefixにしてもdlとか押せばいいので我慢できそうではある
  • o
  • l
  • .

中指

  • e
    • prefixにしてもいい気がするけどfやtよりは移動で使う気がする
  • d
  • c
  • i
  • k
  • ,
    • ;の逆が,だと思い出せないがち、prefixにして良さげ

人差し指

  • r
    • 地味に使う
  • f
    • cf, dfみたいな感じでしか使ってない、prefixにして良さそうでは有る
  • v
  • t
    • fと同様prefixにして良さそう
  • g
    • g+α全部が違うキーになるのはなれるのがしんどそう
  • b
  • u
  • j
  • m
    • ' を潰しているのだからこいつもprefixとしてガンガン使っていくべき今はprefixにしてない
  • y
  • h
  • n
  • Space
    • 3番目に使っているprefix

方針

m;,ft あたりを新規につかっていくと良さそう. fはファイル操作のprefixとして良さげ。shiftとかに手を出さなくても思ったよりなんとかなりそう感がある

Gitlab + GitlabRunner のローカル環境を適当に作った時に引っかかったとことか

引っかかってないとこ

Gitlabは↓で簡単に立ち上がる
GitHub - sameersbn/docker-gitlab: Dockerized GitLab

RunnerはUbuntu18.04のマシンに公式のとおりに入れた
Install GitLab Runner manually on GNU/Linux | GitLab

引っかかったとこ

gitlab-runner registerにsudoつけてなかった

公式にsudoついて書いてあるし、WARNINGも出てるけれども。
登録できるものの実行してもずっとpendingで

This job is stuck because the project doesn't have any runners online assigned to it.Go to project CI settings

と怒られてた

executorにdocker指定すると動かない

``` * connect to 127.0.0.1 port 10080 failed: Connection refused

とか出る。  

gitlab-runnerとgitlabが動いているマシンが同一だとしても、Dockerの中から127.0.0.1でgitlabが見えないのでうまく動かない。  
registerで指定するアドレスは127.0.0.1ではないのにこうなるのか?という感じだった。

とりあえず `--net=host` 相当で動かせば治りそうな気がしたので、

sudoedit /etc/gitlab-runner/config.toml

して
対応する`runners.docker` に `network_mode = "host"` を足して動いた

選択範囲のGithub URLを生成する(クリップボードに入れる)Vimプラグイン書いた

ソースコード箇所を共有するときにこういうURLを貼り付けてここですみたいな話をすることが多いので書いた。

https://github.com/impactaky/github-url.vim/tree/30696af86eb3c8ea7b9ae432957a27e4c4876641/plugin/gihub_url.vim#L11-L11

いくつか既存のリポジトリもあったのだけれどそれらに比べて

  • gitコマンドのみで他の依存物がない
  • sshでcloneした場合をうまく扱える
  • git ディレクトリの外にいた場合でも動く
  • clipboardまわりを変数でカスタム可能

という違いがある

github.com

使い方

自分のdein.tomlの切り貼り
URLにしたいところを選択してgu押すのが使い方。
これでURLが表示されてクリップボードにも入る

[[plugins]]
repo = 'impactaky/github-url.vim'
hook_add = '''
let g:github_url#yank_command = "silent normal V:call OscYank()\<CR>"
nmap gu <Plug>(github_url-file)
vmap gu <Plug>(github_url-line)
'''

OscYankは neovim/tmuxのクリップボード連携(OSC 52) — ゆんたんのきまぐれBlog を参考にこんな感じに書いてある

function! OscYank() range
    let tmp = @@
    silent normal gvy
    let selected_text = @@
    let @@ = tmp
    call chansend(v:stderr, printf("\x1b]52;;%s\x1b\\", system("base64", selected_text)))
endfunction
vmap <Leader>y :call OscYank()<CR>

デバッグしたいコマンドを素早くquickrunに登録してイテレーションを回すやつ

開発していると、基本的にshell上でコマンドを叩いたりテストを回したりしていて、問題が出るとそのコマンドを集中して実行したくなる。
こういう用途に対して自分はvimのquickrunコマンドに

<build command> && ./.run_command.sh

というようなものをプロジェクトごとに登録しておいて、 zshrcには

github.com

を使って

function anyframe-widget-vim-runcommand () {
  history -n -r 1 \
    | anyframe-selector-auto \
    | sed 's/\\\\n/\n/g' \
    > .run_command.sh
}
zle -N anyframe-widget-vim-runcommand
bindkey '^v' anyframe-widget-vim-runcommand

というような処理が書いてあって、<Ctrl-V>でヒストリから選んだ内容を .run_command.sh に書き出すようにしている。
こうすると回したくなったコマンドをすぐに<Ctrl-V>Enterで登録して、編集しながらquickrunでどんどん回すことができて便利。