TECH PLAY

アプトポッド

アプトポッド の技術ブログ

252

aptpod Advent Calendar 2025 12月5日の記事です。 こんにちは、QAグループのKurahashiです。 突然ですが、リグレッションテストを毎回手作業でやるの大変じゃないですか? 画面遷移を一つずつ確認して、スプレッドシートにチェック入れて...正直もっと効率化できないかなと思いますよね。 ふと「AI に任せられないかな?」と思って Claude に相談してみたら、Claude 上で直接 Playwright が動いて、自動でテストを実行できるとのこと!! まだ、お試し段階ですが「これいけるな」という感触があったので記事にしました。 やってみたこと 実際の手順 やってみてわかったこと 今後の展開 まとめ おまけ やってみたこと 今回お試しで弊社製品の「Edge Finder」で画面遷移テストを、Claude と Playwright で自動化してみました。 Edge Finder とは intdashに接続しているデバイスが送信しているリアルタイムデータをブラウザから確認するためのWebアプリケーションです。 www.aptpod.co.jp 従来のやり方 手作業で画面を一個ずつクリック スプレッドシートにチェック 今回試した方法 テストケース(CSV)を Claude に渡す Claude が Playwright で自動実行 その前に、「どうやって Claude が Playwright 動かしてるの?」って疑問に思いますよね。 答えは MCP (Model Context Protocol) です。 簡単に言うと、Claude がローカルのツールを直接操作できる仕組みです。 ┌─────────────┐ │ Claude │ ← チャットで指示 └──────┬──────┘ │ MCP ┌──────┴──────┐ │ Playwright │ ← Claude が直接実行 └─────────────┘ なので先ずは、MCP の設定です。 ただ、これがくせ者で...私は苦労しました😅 環境は人それぞれなので、ここでは私が特にハマった3つのポイントを記載しておきます。 JSON構文の末尾コンマ抜けや括弧の閉じ忘れ。 @playwright/mcpとは別に npx playwright install が必須。 設定後のClaude App完全再起動を忘れずに! 実際の手順 「ここからが本番」と意気込みましたが、環境整備が終わった時点でほぼゴールでした。 試しに今まで使っていたテストケースを投げると自動でブラウザが起動しテストをサクッとこなしていきました。(あまりの早さに呆然と眺めているだけで終わってました...) 1.テストケースを CSV で用意 普段使ってる Googleスプレッドシートをそのまま CSV でダウンロード。 特別なフォーマットは不要です。 2.Claude に投げる Claude Desktop に CSV をアップロードして、こんな感じで頼みました。 このCSVのテストケースをPlaywrightで実行してください。 対象URL: https://*****.*****.jp/console/edges/ 3.Claude が自動実行 Claude が自動で以下の作業を進めてくれます。 CSV を読んで理解 Playwright のコードを生成(裏側で) 実際にブラウザ起動してテスト実行 結果をレポートにまとめてくれる(一部抜粋ですがこのような形で結果を出力してくれます) やってみてわかったこと ✅ とにかく楽 CSV 渡すだけで自動テスト完了 コード書く必要なし ✅ 試行錯誤しやすい エラーが出ても、その場で Claude に相談 会話しながら直せる ✅ プログラミング知識不要 コマンド打たなくていい エディタも不要 ✅ テストケースを詳しく書いていたのが正解だった 今まで「細かすぎかな?」って思っていましたが、これが Claude には助かるらしい。 前提条件がある → どの画面から始めればいいかわかる ボタン名が具体的 → どのボタンを押せばいいかわかる 期待値が明確 → 検証条件をそのまま実装できる 人間が読んでわかりやすいテストケースは、AI にもわかりやすい ってことですね。 今後の展開 今回はお試しで Edge Finder の画面遷移テストだけやってみました。 予想以上にうまくいったので、今後は 他製品の画面遷移テストにも適用 より複雑なテストにも挑戦 チーム全体で使えるように このあたりを進めていきたいと思います。 まとめ やってみた感想 思ってたより簡単だった CSV 渡すだけで自動化できた コード書かなくていいの、楽すぎる 「AI でテスト自動化とか難しそう」っと思っていましたが、実際やってみると全然そんなことなかったです。 特に「プログラミングはちょっと...」って人こそ、試してみる価値あると思います。 おまけ Claude に頼めば、こんなこともできます。 スクリーンショット撮影 テスト実行時に各画面のスクリーンショットも撮ってください レポート生成 結果をHTMLレポートにして保存してください 全部、会話で頼めます。便利。
aptpod Advent Calendar 2025 – 12 月 4 日の記事です。 この記事は、コーポレートマーケティング室デザイナーの tetsu が担当しています。 当チームでは、製品・案件向けアプリケーションの UI デザインをはじめ、マーケティングクリエイティブ、WEB サイトや当テックブログのデザイン・運用などを担当しています。 テック業界の師走といえばアドベントカレンダー。アプトポッドのテックブログでも毎年多くの記事が公開されます *1 が、その運用の中で地味に負荷が大きかったのが OGP(サムネイル画像)の作成 でした。 これまでは、デザイナーが毎回書き出し・設置を行っており、急ぎの差し替えや連携の手間が小さなストレスとして積み重なっていました。 そこで今年は Figma の新機能「Figma Make」 を活用し、OGP 作成から進捗管理までを自動化・アプリ化しました。この記事では、その構築プロセスを紹介します。 *2 www.figma.com これまでの OGP 制作フロー 作成ステップ 1. Figma Make の設定 2. デザインと基本機能の実装 ベースデザインの作成 画像生成機能の実装 テキスト配置の調整 3. 管理アプリとしての UI 拡張 4. Supabase 連携によるステータス管理 5. 書き出し画質の最適化 まとめ これまでの OGP 制作フロー 通常時のテックブログでは、記事内容に合わせて毎回サムネイルを手作業で制作しています。 コンテキストに合わせたイメージを作るため、記事を読む時間と画作りで1記事に1〜2時間までの工数を目標に制作しています。 普段のOGP しかしアドベントカレンダー期間中は、 毎日更新(時間制約) 全体の統一感(デザイン要件) という理由から、昨年までテンプレートを使用していました。 テンプレートの活用をした場合でも、執筆者とのやりとりや設置確認などで15分程度はかかります。 15分×20記事で300分程度は工数をかけていたことになります。 また、工数以上に急ぎの差し込み対応である場合が多く、常に他のタスクの手をとめる必要がありました。 2022〜2024年のアドベントカレンダーOGP 上記の課題を解決するために、今年はさらに一歩進め、テンプレートから“アプリ化”へと発展させた形です。 作成ステップ 1. Figma Make の設定 Figma Make の設定から 「実験モデル > Gemini 3 Pro」 を有効化します。 これにより、プロトタイプ上で高度な AI モデルを利用できるようになります。 Figma Make 設定画面 2. デザインと基本機能の実装 ベースデザインの作成 まず、アドベントカレンダー向けにクリスマスらしいベースデザインをラフで作ります。 この段階で 編集可能エリア(タイトル・著者名) をあらかじめ定義しておきます。 ベースデザイン 画像生成機能の実装 プロンプトで以下を指定します: サイズは 1200 × 630px(OGP 標準) プレビュー内容を JPG としてダウンロード可能 にする 日替わり感を出すため、アイコンや小物を可変にする 画像生成UI テキスト配置の調整 テキストの級数やフォントは UI から調整できますが、 位置・マージン調整は精度を高めるため数値指定 が必要でした。 Figma Make と数度やりとりし、うまくいかない箇所はコードを確認しながら値を指定しました。 3. 管理アプリとしての UI 拡張 ここまでは「デザインチームが書き出し、Figma に一覧化」という想定でした。しかしアドベントカレンダー期間中は、執筆者の編集待ちや掲載タイミングの調整が発生し、お互いに小さな負荷が生まれがちです。 そこで、執筆者自身が “自分の担当日を選び、その場で OGP を生成できる” 管理 UI を追加しました。 担当日を選択して OGP を作成 入力完了ステータスを一覧で可視化 一覧性のある管理UI 画像を生成する側のUIにも、管理UIとの導線や、現在編集している日付をわかりやすくするために右側に日付バーなどを追加しました。 最終的な画像生成UI これにより、執筆者は進捗を自分で管理でき、デザイナー側も状況を一目で把握できるようになりました。 4. Supabase 連携によるステータス管理 プロトタイプ段階ではステータスがブラウザローカルに保存されるだけで、実運用には不十分でした。 そこで、オープンソースの BaaS (Backend as a Service)である Supabase を採用し、進捗ステータスをクラウドで管理できるようにしました。 supabase.com Figma Make は API 連携まわりの操作性が良く、デザイン畑の人間でもほぼノーコードで扱える点が特に便利でした。 5. 書き出し画質の最適化 最終的にデザインの細部を調整し、出力処理を整えます。 普段はデザイナーが毎回 JPG 圧縮の度合いを調整していますが、今回は 設置作業を執筆者に委ねるため、品質設定をシステム側で固定 しています。 書き出し時に自動で Quality 0.8 の JPG に変換 画質とファイルサイズのバランスを安定化 これにより、誰が生成しても品質が揃い、運用負荷を最小化できます。 まとめ 今回の取り組みによって、師走の忙しい時期に細切れで発生していたデザイナーのタスクが大幅に軽減されました。執筆者も、自分のタイミングで OGP を生成・設置でき、全体の流れがスムーズになりました。 「運用フロー自体をデザインする」 ことで、チーム全体のコンテキストスイッチを減らせたことが最大の成果だと感じています。 Figma Make のようなツールを活用すれば、デザイナーでもアプリライクな課題解決を手軽に実装できます。ぜひ試してみてください。 *1 : アプトポッドのアドベントカレンダーは、12 月の平日毎日更新 *2 : この記事の内容は 2025 年 11 月現在の情報です
intdashグループの大久保です。 aptpod Advent Calendar 2025 の12月3日の記事を担当します。 Linuxでアプリケーションを開発するとき、その依存ライブラリ含めどう配布するかは悩ましい問題です。debのようなパッケージであれば、対応するディストリビューションごとにビルドしなければなりません。muslであれば単体で動作する実行バイナリを作れますが、依存するライブラリが多ければビルドが難しかったり、対応不可であったりします。 ここでは、Linuxのアプリケーション配布をするときに有用と思われるAppImageを紹介します。 AppImageとは テスト用アプリケーションの作成 debパッケージからAppImageへの変換 AppImageの動作 カスタムのAppRun まとめ AppImageとは AppImageは、1つの実行ファイルに依存するファイルを内包するようにし、ディストリビューションに関わらず単体で動作するようにしたパッケージフォーマットです。 https://appimage.org/ 今回は、debパッケージからAppImageを作成できる pkg2appimage を使用します。 テスト用アプリケーションの作成 開発言語は特に制約はありませんが、今回はAppImageパッケージを生成する途中でdebパッケージを経由する方法をとるので、debパッケージを簡単に作れるRustを今回は例に使います。他の方法でdebパッケージを作成してもらっても問題ありません。 ここではGTKを使用して画像を表示するシンプルなGUIアプリケーションを作成します。 Cargo.tomlは以下のように準備します。 [ package ] name = "appimage-test" authors = [ "Test <test@example.com>" ] version = "0.1.0" edition = "2024" license = "MIT" [ dependencies ] gtk4 = "0.10" # cargo-deb の設定 [ package.metadata.deb ] maintainer = "Test <test@example.com>" depends = "$auto" section = "misc" priority = "optional" assets = [ # コンパイルされたバイナリを /usr/bin に配置 [ "target/release/appimage-test" , "usr/bin/" , "755" ] , # desktopファイルを /usr/share/applications に配置 [ "appimage-test.desktop" , "usr/share/applications/" , "644" ] , # アイコンファイル (logo.png) を /usr/share/pixmaps/appimage-test.png として配置 [ "logo.png" , "usr/share/pixmaps/appimage-test.png" , "644" ] , ] main.rsは以下になります。注意点としては、画像ファイルにアクセスするとき /usr/share/pixmaps/appimage-test.png と絶対パスを指定するのではなく、実行ファイルのある場所 usr/bin からの相対パスで指定していることです。AppImageは実行時に一時的なパスにファイルを配置するため、絶対パスが機能しなくなります。 use gtk4 :: {Application, ApplicationWindow, Image, gdk_pixbuf :: Pixbuf, prelude :: * }; use std :: env; fn main () { let application = Application :: new ( Some ( "com.example.appimage-test" ), Default :: default ()); application. connect_activate (build_ui); application. run (); } fn build_ui (app: & Application) { let exe_path = env :: current_exe (). expect ( "Failed to get executable path" ); // 実行ファイルからの相対パスから usr/share/pixmaps/appimage-test.png を取得 let exe_dir = exe_path . parent () . expect ( "Failed to get executable directory" ); let image_path = exe_dir. join ( "../share/pixmaps/appimage-test.png" ); let pixbuf = Pixbuf :: from_file ( & image_path). unwrap_or_else ( | e | { panic! ( "Failed to load image file from path {:?}. Error: {}" , image_path, e ); }); let image = Image :: from_pixbuf ( Some ( & pixbuf)); let window = ApplicationWindow :: new (app); window. set_title ( Some ( "AppImage Test (GTK4)" )); window. set_default_size (pixbuf. width (), pixbuf. height ()); window. set_child ( Some ( & image)); window. present (); } Linuxのdesktopファイルを適当に用意し、appimage-test.desktopと名前をつけて保存しておきます。 [Desktop Entry] Version=1.0 Type=Application Name=AppImage Test GenericName=Test Application Comment=A simple GTK4 test application Exec=appimage-test Icon=appimage-test Terminal=false Categories=Utility;Development; StartupNotify=true 他に適当な画像を用意して logo.png として保存しておきます。 以上のものを用意すれば、 cargo-deb でdebパッケージを生成しましょう。target/debian以下にdebファイルが生成されているはずです。 $ cargo deb debパッケージからAppImageへの変換 debパッケージが用意できたら、以下のようなレシピファイルをyamlで作成します。レシピ内にUbuntuのバージョンが含まれますが、UbuntuのバージョンはdebパッケージのビルドとAppImageへの変換の実行するホスト環境、そしてレシピ内で統一しておいたほうが無難です。 app : appimage-test ingredients : dist : noble sources : - deb http://archive.ubuntu.com/ubuntu/ noble main universe debs : - /path/to/appimage-test_0.1.0-1_amd64.deb レシピファイルを作成したら変換用スクリプトをダウンロードしてきましょう。 Releases · AppImageCommunity/pkg2appimage · GitHub ここからダウンロードした実行バイナリで変換に失敗した場合は、GitHubにある 生のスクリプト を実行してやるとうまく行く場合があるようです。 $ wget https://raw.githubusercontent.com/AppImage/pkg2appimage/master/pkg2appimage $ chmod +x pkg2appimage $ ./pkg2appimage testrecipe.yml 変換に成功すれば、outディレクトリ内にAppImageファイルが作成されているはずです。 $ ls out/ AppImage_Test-0.1.0.glibc2.39-x86_64.AppImage これを実行すれば用意した画像を表示するシンプルなウィンドウが表示されます。 AppImageの動作 AppImageの特徴は、実行時に FUSE を用いて、動作に必要なファイル群を一時的にマウントして展開することです。その動作を見るためには、作成された実行ファイルに --appimage-mount オプションを付けて実行します。 $ ./AppImage_Test-0.1.0.glibc2.39-x86_64.AppImage --appimage-mount これを実行すると /tmp/.mount_XXXXX のようなディレクトリ内に、実行中そのAppImageが使うファイルがマウントされていることが確認できます。今回の例として作成したアプリケーションで、画像が /usr/share/pixmaps/appimage-test.png にあるのにソースコード上は相対パスを使ってアクセスしているのは、実行時欲しい画像が実際には /tmp/.mount_XXXXX に展開されているので、それにアクセスできるようにするためです。ここはアプリケーションの実装時に気を付けないといけない点です。また、デフォルトでは一部の基本的なライブラリ(libcなど)はパッケージに含まれず、実行OS側に存在しなければなりません。libfuseもインストールされている必要があります。 カスタムのAppRun AppImageパッケージを起動するとき、まずAppRunというファイルが実行されます。対象となるアプリケーションによっては、カスタムのAppRunを用意してやる必要があります。その場合は、レシピの script にAppRunを作成する処理を記述します。元のdebパッケージがdesktopやアイコンファイルを含んでいない場合、ここで作成処理を追加することもできます。 app : appimage-test ingredients : dist : noble sources : - deb http://archive.ubuntu.com/ubuntu/ noble main universe debs : - /path/to/appimage-test_0.1.0-1_amd64.deb script : - cat > AppRun <<\EOF - # !/bin/sh - HERE="$(dirname "$(readlink -f " ${ 0 }")")" - export LD_LIBRARY_PATH="${HERE}/usr/lib:${HERE}/usr/lib/x86_64-linux-gnu:${LD_LIBRARY_PATH}" - exec "${HERE}/usr/bin/appimage-test" "$@" - EOF - chmod a+x AppRun スクリプト内で LD_LIBRARY_PATH などの環境変数を設定し、最後に配置した実行ファイルを呼び出します。アプリケーションに合わせて設定する環境変数を変えましょう。また、デフォルトのAppRunに任せると、カレントディレクトリを変更されてしまうので、相対パスを引数に受け付けるCLIツールをAppImage化する場合はカスタムのAppRunを用意する方が無難です。 まとめ AppImageはLinuxで開発していると興味深い技術なのですが、パッケージ化するとなると日本語の情報がほとんど無いので今回取り上げてみました。いろいろ苦労させられることの多いLinuxでのアプリケーション配布における1つの選択肢として覚えておくのは良いかと思います。
計測データを動画プレイヤーで再生したいみなさん、 こんにちは。ソリューションアーキテクトの伊勢です。 こちらは aptpod Advent Calendar 2025 12月2日の記事です。 今回はintdashの計測データをMP4ファイルとして出力する方法をご紹介します。 はじめに 複数データの出力 MP4ファイルとは やってみた 出力パターン①:音声 出力パターン②:音声 + 映像 出力パターン③:音声 + 映像 + 字幕 起動オプション データ取得オプション 出力オプション 多重化オプション サンプルプログラム データ取得 データ変換 データ出力 MP4多重化 おわりに リンク はじめに intdashのMedia Explorerでは、計測の映像をMP4ファイルでダウンロードできます。 1 Media Explorer また、Meas Converterでは、車両データ解析で利用されるMDFファイルでダウンロードも可能です。 tech.aptpod.co.jp 複数データの出力 利用用途によっては複数データを統合してファイル出力したいケースもあります。 今回は、より複雑な構成のMP4ファイルを出力してみます。 MP4ファイルとは 動画や音声をひとつのファイルにまとめて扱える形式です。 再生時には内部の映像や音声を取り出し、タイムスタンプに基づいて同期再生します。 おおまかな構成は以下のようになっています。 今回はこれらのトラックを統合(多重化)します。 trak (video) : ビデオトラック trak (audio) : オーディオトラック trak (subtitle) : 字幕トラック MP4 File ├─ ftyp # ファイルタイプ情報 (ブランド識別) ├─ moov # メタ情報(再生に必要な情報の塊) │ ├─ mvhd # ムービーヘッダ(全体の時間情報など) │ ├─ trak (video) # ビデオトラック │ │ ├─ tkhd # トラックヘッダ │ │ ├─ mdia # メディア情報 │ │ │ ├─ mdhd # メディアヘッダ(時間単位など) │ │ │ ├─ hdlr # ハンドラ(映像/音声の区別) │ │ │ ├─ minf # メディア情報 │ │ │ │ ├─ stbl # サンプルテーブル │ │ │ │ │ ├─ stsd # サンプル記述子(コーデック情報) │ │ │ │ │ │ ├─ avc1 (AVC/H.264 codec box) │ │ │ │ │ │ │ ├─ avcC (AVCDecoderConfigurationRecord) │ │ │ │ │ │ │ │ ├─ SPS (Sequence Parameter Set) │ │ │ │ │ │ │ │ └─ PPS (Picture Parameter Set) │ │ │ │ │ ├─ stts # 時間情報(各サンプルのduration) │ │ │ │ │ ├─ stsc # チャンク構造 │ │ │ │ │ ├─ stsz # サンプルサイズ │ │ │ │ │ └─ stco # チャンクオフセット │ ├─ trak (audio) # オーディオトラック │ │ ├─ tkhd │ │ ├─ mdia │ │ │ ├─ mdhd │ │ │ ├─ hdlr │ │ │ ├─ minf │ │ │ │ ├─ stbl │ │ │ │ │ ├─ stsd # サンプル記述子(例: mp4a) │ │ │ │ │ ├─ stts │ │ │ │ │ ├─ stsc │ │ │ │ │ ├─ stsz │ │ │ │ │ └─ stco │ └─ trak (subtitle / others) # 他トラック (例: 字幕) │ ├─ mdat # メディアデータ本体(映像フレームや音声サンプル) │ ├─ [Video Sample 1] → H.264フレーム (AVCC形式: length-prefixed NALU) │ ├─ [Video Sample 2] → H.264フレーム │ ├─ ... │ ├─ [Audio Sample 1] → AACフレーム │ ├─ [Audio Sample 2] │ └─ ... └─ free / udta / meta # 追加のメタデータ(オプション) やってみた おおまかな構成です。 iPhoneアプリ intdash Motion で取得した計測データをもとにします。 データ種類ごとにファイルを出力し、最後にMP4ファイルに多重化します。 2 音声:PCMデータ → WAVファイル 映像:H.264データ → バイナリファイル 字幕:GNSSデータ(高度・速度・緯度経度) → SRTファイル 多重化後:MP4ファイル データフロー 出力パターン①:音声 シンプルな例として、音声ファイルをWAVファイルに出力します。 3 対象のエッジと開始時刻〜終了時刻を指定して実行します。 実行:音声 youtu.be 出力パターン②:音声 + 映像 続いて、複数トラックを多重化します。音声 + 映像を出力するパターンです。 実行:音声 + 映像 多重化で警告が出ています。 これは、開始時刻〜終了時刻を直接指定したためで、動画の基準点であるIDRフレームが最初に現れるまで映像フレームが生成されず、黒一色で表示されます。 4 [ h264 @ 0x157704b90 ] no frame! [ h264 @ 0x157704b90 ] non-existing PPS 0 referenced youtu.be 出力パターン③:音声 + 映像 + 字幕 最後に音声 + 映像 + 字幕を出力・多重化する例です。 計測を指定して、計測の開始〜終了時刻のデータを対象とします。 字幕の緯度経度を逆ジオコーディングで住所に変換するため、Google Geocoding APIのAPIキーを指定しています。 実行:音声 + 映像 + 字幕 youtu.be 起動オプション データ取得オプション --api_url required :サーバーURL --api_token required :APIトークン --project_uuid :プロジェクトUUID(省略時は Global Project) いずれか required 計測指定 --meas_uuid :計測UUID エッジ+時間範囲指定 --edge_uuid :エッジUUID --start :開始時刻、RFC3339形式 --end :終了時刻、RFC3339形式 出力オプション --outdir :出力先ディレクトリ(省略時は ./out ) --tracks :出力するトラック audio , video , subtitle を指定(複数可、省略時はすべて) --fps :映像の入力フレームレート(映像出力時、省略時は15) --gmap-api-key :Google Maps API Key(字幕出力時、逆ジオコーディングに使用、省略時は緯度経度を出力) 多重化オプション --mux :WAV / H.264 / SRT を MP4 に多重化(省略時は多重化なし) サンプルプログラム 多重化には SDK入門③ でインストールしたffmpegを利用しています。 クラスアーキテクチャ データ取得 intdash REST APIからのデータ取得はメモリ消費を抑えるため、 チャンク転送エンコーディング でリクエストしています。 api = measurement_service_data_points_api.MeasurementServiceDataPointsApi( self.client ) params: dict [ str , object ] = { "project_uuid" : self.project_uuid, "name" : self.meas_uuid if self.meas_uuid else self.edge_uuid, "time_format" : "ns" , "_preload_content" : False , # 全データロードの抑止 } if self.start: params[ "start" ] = self.start if self.end: params[ "end" ] = self.end if self.data_id_filter: params[ "data_id_filter" ] = self.data_id_filter stream = api.list_project_data_points(**params) データ変換 Motionで収集した音声を単純に繋げるだけだと、zzzzやppppと聞こえるジッタノイズが入っているため、除去します。 PCMデータサンプル間の時間揺らぎを等間隔サンプリングします。 f32 = decode_pcm_s16le(data_bytes) # bytes -> float32 f32_out = self.resampler.push_block(t_rel, f32) if f32_out.size: i16 = encode_pcm_s16le(f32_out) # float32 -> bytes データ出力 映像と音声はメモリに溜め込まず、1件ずつ出力しています。 if data_name == "1/pcm" : ... self._wav.write(i16) ... elif data_name == "1/h264" : ... self._h264.write(data_bytes) また、字幕はGNSSの複数項目を統合して生成します。 高度・速度・緯度経度・住所の字幕セグメントに集約します。 elif data_name == "1/gnss_speed" ... aggregator.update_speed(v) ... elif data_name == "1/gnss_altitude" : ... aggregator.update_altitude(alt) ... elif data_name == "1/gnss_coordinates" : ... changed, lat_q, lon_q = aggregator.update_latlon(lat, lon) ... aggregator.update_address(addr) 集約した字幕は高度が更新されたタイミング、約1秒に1回出力します。 seg = aggregator.on_tick(t_rel) # 高度は約1Hz if seg: self._write_segment(seg) 今回は1回だけREST APIへのリクエストして、データ名で処理を分岐しています。 5 for t_ns, _, data_name, data_bytes in self.reader.get_datapoints(): ... if data_name == "1/pcm" : ... elif data_name == "1/h264" : ... elif data_name == "1/gnss_speed" : ... elif data_name == "1/gnss_altitude" : ... elif data_name == "1/gnss_coordinates" : MP4多重化 音声・映像・字幕それぞれで最初のデータポイントの相対時刻が異なるため、計測開始からのオフセット(ffmpegの -itsoffset オプション)を与えて調整しています。 cmd += [ ... "-itsoffset" , f "{opts.v_offset:.6f}" , "-i" , str (inputs.video), ... cmd += [ "-itsoffset" , f "{opts.a_offset:.6f}" , "-i" , str (inputs.audio)] ... cmd += [ "-itsoffset" , f "{opts.s_offset:.6f}" , "-i" , str (inputs.subtitle)] おわりに 今回は、複数データを一般的な動画ファイルに多重化する例を紹介しました。 マルチモーダルデータも、SDKを使えば、自由に整形が可能です。 intdashはデータの時系列が管理されているため、出力時にもデータが同期されます。 なお、今回は海外eSIMを使ったiPhoneで計測を行いました。 海外での計測は以下の記事でも検証しています。 tech.aptpod.co.jp リンク 本シリーズの過去記事はこちらからご覧ください。 SDK入門①〜社用車で走ったとこ全部見せます〜 :REST APIでデータ取得 SDK入門②〜データ移行ツールの作り方〜 :REST APIでデータ送信 SDK入門③〜RTSPで映像配信するぞ〜 :リアルタイムAPIでデータ取得 SDK入門④〜YOLOで物体検知しちゃう〜 :リアルタイムAPIでデータ送信 SDK入門⑤〜iPadでData Visualizerを見る会〜 :リアルタイムAPIでキャプチャデータ送信 SDK入門⑥〜最速最高度で計測する日〜 : AWS LambdaでREST APIデータ送信 SDK入門⑦〜計測リプレイツールの作り方〜 : REST APIでデータ取得、リアルタイムAPIでデータ送信 SDK入門⑧〜動画アップロードツールの作り方〜 :REST APIで映像データ送信 Media ExplorerでのMP4ダウンロードについては、 SDK入門⑧ で解説しています。 ↩ サンプルプログラムを GitHub にて公開しています。Motionの計測データのみで動作確認しています。未回収データポイントがあると映像と音声がずれるなどの問題が起こりえます。 ↩ サンプリングレートを48kHzにしています。元計測の音声データにあわせる必要があります。 ↩ H.264のIDRフレームについては、 SDK入門⑧ で解説しています。 ↩ 字幕集約がなければ、音声、映像ごとにリクエストする方がシンプルかもしれません。 ↩
aptpod Advent Calendar 2025 12月1日の記事です。 みなさまお久しぶりです。アプトポッドで営業企画をしている神前(こうさき)と申します。 前回 から1年ぶり、5年連続でAdvent Calendarのトップバッターです。甲子園でいったらそこそこ強豪ですね。 今年も懲りずにSalesforceネタで書いていきたいと思います。メインの業務がそれだから仕方ないね。 今年やったこと エンドユーザー向けマイページ作成の経緯 設計 ちょっとしたポイント 補足 見せ方について 作ってみてよかったこと まとめ 今年やったこと この1年間でやったことのうち、大きなトピックとしては、「エンドユーザー向けマイページ」の公開でしょうか。 サンプルページ これまでも内部的には弊社の一部パートナー企業様向けのポータルサイトは公開して使ってもらっていたのですが、エンドユーザー様向けのものは今回が初となります。 Salesforceには「 Experience Cloud 」という機能があり、社内で利用しているSalesforce環境と連携した外部ユーザー向けWebサイトをつくる事が可能です。 使い方は様々で、 セールスパートナー企業向けのサイトをつくり、商談情報を直接パートナーに入力してもらう エンドユーザー向けのサイトをつくる、FAQやお問い合わせ機能をもたせ、エンドユーザーに直接ケースを起票してもらう 会員専用ページをつくり、いわゆるコミュニティを形成する 他 といったことが利用法として想定できます。 今回のケースは「エンドユーザーが当社製品の契約状況や、具体的な利用状況を(当社の営業等を介さずに)直接確認することができるサイト」となります。 そんな機能(ツール)があるのを知らなかった!知ってたけどどう使っていいかわからない!みたいな方がいたら本記事は少しは役に立てるかもしれません。 エンドユーザー向けマイページ作成の経緯 当社の主力製品である「 intdash 」をご利用いただくにあたり、いくつかのプランからお客様の用途に合ったものを提供しています。これまでも提供プランそのものについては何度か変更があったのですが、現時点での最新バージョンからは「瞬間的なデータ流量の最大値」から「1ヶ月間でのトータルのデータ流量」を元に提供をする形になっています。 必然的に、お客様からすると「月にどれだけ使えるプランにしたのか」と「今月はあとどれだけ使えるのか」を確認できないといけません。 そうした情報をどこでみれるようにするのかについてはいくつか候補はあったのですが、最終的にSalesforce上(=Experience Cloudで作成したサイト)でみれるようにすることとなりました。 ちょうど弊社が利用しているMVNO事業者の各SIMの利用状況を確認するサイトがSalesforceで作られていることがわかっていたので、そちらをベンチマークとして作成をすすめていきました。 設計 当社はBtoB企業ですので、エンドユーザーといっても一般消費者ではなく企業が対象となります。 どういった項目を見れるようにするのか、どういう風に見せるのか、といった内容については営業側、開発側と何度か打ち合わせをしながら詰めていきました。 特に、そもそものデータ(A社が◯月◯日に◯Gデータを消費した)の大元がSalesforce内にあるわけではないので、当社の場合は大元のデータがあるAWSからAPIでSalesforceへデータを流し込む部分については開発側におんぶにだっこの状態でした。 AWS側でどういう風にデータを持っているのか、どんなデータを持っているのか(逆に、どんなデータは持っていないのか)によってSalesforce側で追加で何をすることが必要なのかが変わってくるのでこのあたりは特に大変だったように記憶しています。 ただ、一回決まってしまえばやることは明確なので、AWS側からデータを流し込む先(=各項目)を用意して、AWS側では持っていないデータ(そのデータがどのエンドユーザーなのか、どういう契約なのか、等)についてはSalesforceで持っているデータと組み合わせて補完するためのフローを構築する形となります。そこの領域については自分の領域なのであーでもないこーでもないと頭を使いながら設計していきました。 さて、そういった「データをどこからもってくるのか」、「何を見せるのか」といった部分については割と大変というか、営業側(データを見るお客様に一番近い立場)と開発側(データを持っているシステムに一番近い立場)の両方と関わりながらすすめていくので結構おおがかりになるのですが、サイト自体はそれほど複雑だったり、特別なことをしているわけではありません。 サイト内に各種タブがあり、各タブ内で表示する情報や表現方法に違いはあるものの、基本は 「ダッシュボード」 と 「レポート」 を埋め込んでいるだけです。 つまり、日常的にこの2つを利用しているのであれば多少の工夫は必要なものの、おおよそ同様のものはつくれるものと思います。 ちょっとしたポイント どんなデータをどう見せるのか、どこからデータを持ってくるのかといった点は各社さんが持っているデータやどういう目的でどういう属性の人に見せるのかでケースバイケースなのであまり参考になるお話は書けないのですが、どう見せるのかの部分についてはちょっとしたポイントが参考になると思うので書きたいと思います。 使っているのはダッシュボードとレポートの2種類とすでに記載していますが、普段から使っている方はご存知の通り、これらをそのまま使うだけでは「見る人によって見せるものを変える(=動的に見せる)」というのはできません。ですが、実はユーザー側にちょっとしたことをすると実現できるのです。 言葉だけで説明をすると複雑になるので、図をいれていきます。 以下のようなケースを想定します。 ■レポートで、とあるレコードa(にある情報)をXさんにのみ見せるようにしたい 各レコードとオブジェクト、項目の関係を表したのが下記の図です。わかりやすくするためYさんも図にいれています(XさんとYさんは別の企業)。XさんとYさんは別々の企業なのでXさんに見せたいものはYさんには見えてはいけないですし、その逆も然りです。 関係図 さて、レポートを作成するときに、普通にオブジェクトAを使うだけではXさんにもYさんにもレコードaの情報は見えてしまいます。 そこで、オブジェクトAとユーザーにそれぞれ項目αと項目Zを作成します(ここでのユーザーは、設定画面から見る方のユーザーです)。 ※ユーザーXやYにアカウントの払い出しをしているという想定です。 当社の事例。「累積データ流量」がオブジェクトA、「マイページ管理No.」が項目αに該当。 こちらはユーザー側の画面。下部にある「マイページ管理No.」が項目Zに該当。 これらの項目のデータ型はなんでもよいのですが、テキストが無難です(一意にできるのであれば数値とかでも可)。 その後に、オブジェクトAにのみ項目βを作成し、データ型を「数式」、数式の戻り値のデータ型を「チェックボックス」にして以下のような数式を設定します。 [項目α] = $User.[項目Z] 当社の項目βの設定画面。戻り値がチェックボックス。数式のうち、左の「MypageNo」が項目α、「$User」の後ろの「MypageNo」が項目Z。 あとはそれぞれ項目αと項目Zに一意になるような値を入力すればOKです(もちろんαとユーザーXの項目Zは同じ値にするようにする)。 最後にレポート側の「検索条件」に「項目β=true」としてあげれば全て完了です。 レポートの検索条件画面。赤い枠の箇所が「項目β=true」に該当する箇所。 仮に、レコードaの項目αに「AAA」という値をいれ、ユーザーXの項目Zに同様に「AAA」、ユーザーYの項目Zには「BBB」という値をいれます。 ※項目α、項目Zには管理者側からしか値をいれることができないようにしてあります。 ユーザーXがサイトにログインをすると項目βに入力した数式が成立し、チェックボックスがはいるためレポートを閲覧した時にレコードaの情報を閲覧できます。一方で、ユーザーYがサイトにログインしても項目βの数式は成立しないのでチェックボックスは入らずレポートでレコードaの情報を閲覧することはできません(そもそもでてこない)。 項目Zに「AAA」とはいっているマイページ太郎さんには同様に項目αに「AAA」とはいっている項目が表示される。 項目Zに「BBB」とはいっているマイページ次郎さんにはマイページ太郎さんに見えていた項目は表示されない。 これで、同じサイトに同じレポート、同じダッシュボードを貼り付けたとしてもユーザーによって見せたいデータを変えるという動的な見せ方が可能になります。 補足 上記のやり方で動的にレポートをみせることはできるのですが、当社の場合は運用面を考慮して少しゆるくしています。 例えば、今回ユーザーXとユーザーYは別々の会社という設定にしていますが、同じ会社に所属していて、XとY両方に同じ情報をみせる必要がある場合を考えてみましょう。その場合、ユーザー側の項目Zが完全に一意であってはXかYのどちらかにしか情報をみせられません。こうした状況を想定しなくてよい場合(レコードaは常に一人のユーザーにしか見せる必要がない)であればもっと機械的にシンプルにすることも可能でしょう。 また、当社の場合、オブジェクトA内のレコードは毎日毎日増えていきます(毎日のデータ使用量のデータなので当然ですね)。レコードが増えるたびに項目αに手作業で値をいれていくことはできないのでフローを活用しています。詳細は省きますが、さらに大元となるデータをもっておいて、オブジェクトAにレコードが作成された際に、キーとなる値を使って大元から項目αにいれるべき値をもってきて上書きする、という感じです(テキストだとわかりにくいですが・・・)。これもオブジェクトA内のレコードそのものがそんなに増えないような運用であればそこまでしなくてもよいので、どこまでやるか、というのは運用次第という感じですね。 見せ方について ここまでできたらあとは事前に決めていた通りにダッシュボードやレポートを調整していけば完成です。 どの情報をどのように見せるのか、グラフにするのか、グラフでも棒グラフなのか円グラフなのか、あるいは表形式にするのかといった点は見せたいデータによって変わるので最適と思われる表現方法にしてもらえればよいと思います。 当社の場合は日々のデータ使用量の推移を見せたいので、棒グラフとしています。 サンプルページ 上記の図では、青を使用量、赤が残りの使用量を表しています。 期間やそれ以外の項目である程度絞り込んだり、グラフの表現形式をある程度ユーザー側で調整できるのはよいですね。 それとは別に、トップページでは表形式にすることで複数のデータを網羅的に見れるようにしたり、トップページなのでお知らせの枠や当ページの操作マニュアルへのリンクを掲載しています。 サンプルページ 使っているデータ自体は同じでも表現方法でいかようにも見せれるので色々試してみてもよいかもしれませんね。 作ってみてよかったこと 今年の4月に本サイトをオープンし、徐々にお客様にも使っていただいています。まだまだ改善の余地はありますし、実際に社内からも改善要望もあったのでそこは対応をしつつ、もっと便利に、もっと使いやすくしていければと考えています。 個人的にやってよかったなと思った点を最後に記載したいと思います。 当社では年に数回イベントに出展をしています。 【参考】 メンテナンス・レジリエンス TOKYO 2025 見学レポート 片手サイズ × 高速起動 ── EDGEPLANT R1 & CAN FD USB Interface[人とくるま展2025展示レポート] ブース内でデモを展示することもあるわけですが、その際に、どれだけ実際に通信量を消費するのかを本サイトの社内向けのものを使ってその場で営業メンバーが確認していました。デモとはいえ、こういう風にintdashを使って、これぐらいの時間使うとこれぐらいの使用量になるのか、というのを開発側の手を煩わせることなくその場ですぐに確認できるというのは、地味ではあるものの自分がなにがしかに貢献できたのではないかと感じました。 普段の仕事柄、あまり派手な何かをするというよりも、こうした地味な改善の積み重ねが業務の大半なので、実際に使ってもらってるシーンを見れてよい経験でした。 まとめ 長くなってきたのでそろそろ締めたいと思います。 昨年とは違いTips寄りの記事を今年は書いてみました。細かい注意点(項目ごとのアクセス権限の設定とか)は書ききれないほどあるのですが、マニアックになるので今回は省きました。 そういった点よりも、Salesforceで普段使っているレポートやダッシュボードとExperience Cloudを組み合わせればこんなこともできるんだ、ということをおわかりいただければ幸いです。 現在は何をしているかと言うと、Salesforceの提供している自立型AIエージェント「 Agentforce 」の活用を試みています。 とはいえ、いきなり使えるというとそういうわけでもないので、まずはSalesforceに社内のいろんな情報を集約できるように地ならしをやっています。 来年にはAgentforceを活用してこんなことができるようになったよ!みたいな記事を書けるようにやっていきたいと思います。 本記事が少しでも参考になっていると幸いです。 それではまた1年後にお会いしましょう!
気軽に計測データを分析したいみなさん、 こんにちは、ソリューションアーキテクトの伊勢です。 せっかくデータ収集しても、こんな悩みはないですか。 収集したデータをどう利活用したらいいかわからない 分析ツールを導入したけどどう分析したいかわからない 分析結果をどう考察したらいいかわからない IoTあるあるですね。 今回は専門的な分析知識を使わず、 intdashの収集データをノーコードで分析したいと思います。 生成AIはChatGPTの最新版GPT-5を利用します。 1 はじめに データ分析とは GPT-5とは VM2M Data Visualizerとは やってみた CSVダウンロード センサーデータで体感を定量化 行動データから安全性を客観評価 現場運用を解決 おわりに はじめに データ分析とは 数値や記録などのデータを収集・整理・可視化・解釈し、有用な知見(インサイト)を得る一連の活動です。 データ分析の流れ DXを推進するAIポータルメディア「AIsmiley」 データ分析とは?基礎から分かる手法と流れ、仕事でのメリットも解説 このうち、前処理(クレンジング)〜結果の解釈、また報告のためのレポート作成を ChatGPTにまるっとお願いできますし、 なんなら、問題の発見や定義への助言も得られます。 2 GPT-5とは OpenAIが2025年に発表した最新の大規模言語モデルで、マルチモーダル処理(テキスト・画像などを併用可能)や高いコーディング能力を備えています。 また、CSVファイルなどのデータを読み込んで「要約・可視化・パターン検出」といった分析支援を行えます。 今回はこのGPT-5を活用して、intdashの計測データをノーコードで分析してみます。 VM2M Data Visualizerとは 時系列データを可視化するダッシュボードアプリケーションです。 エッジからintdashサーバーに送られているリアルタイムデータをサーバー経由で受信して表示したり、intdashサーバーに保存された過去のデータを表示したりします。 www.aptpod.co.jp 分析対象データは、このダッシュボードからCSVファイルでダウンロードします。 やってみた 3つ課題を設定してデータ分析によって結論を導きます。 まずはデータの準備方法の説明です。 CSVダウンロード intdashのビューアーであるVM2M Data Visualizerで分析対象データを作成します。 任意の計測を選択してから、CSVダウンロードします。 CSVダウンロード項目の指定 注意点です。 適度にサンプリングする データが100万行を超えるとChatGPTの分析処理が重くなってくるため、必要な精度にサンプリングします。 Sampling Interval で 1 / 10 / 100 / 1,000 ms のいずれかを選択します。 必要項目に限定する 余計な項目があると、ChatGPTが勘違いしたり、分析が重くなったります。 必要な項目のチェックボックスだけを選択します。 自然言語形式のタイムスタンプを付与する 分析しやすいように「年月日 時分秒」形式の時刻を最初の列に追加します。 Add human-readable timestamps (yyyy/mm/dd HH:MM:SS). をチェックします。 それでは、最初の分析課題です。 センサーデータで体感を定量化 課題 船酔いしなかったのはなぜか。 こちらの記事でご紹介したカーフェリーのGNSSデータを使います。 tech.aptpod.co.jp 私は元々船酔いしやすいタイプなのですが、この出張時には幸い大丈夫でした。 これは当日の船揺れが穏やかだったからなのか、私が船酔いを克服したからなのか、収集データから分析してみます。 茨城県大洗港〜北海道苫小牧港 Data VisualizerからダウンロードしたCSVファイルはこのようになります。 "#timestring","#timestamp","UBX-HNR-ATT_roll@0/UBX-HNR-ATT[BD-67]","UBX-HNR-ATT_pitch@0/UBX-HNR-ATT[BD-67]","UBX-HNR-PVT_lon@0/UBX-HNR-PVT[BD-67]","UBX-HNR-PVT_lat@0/UBX-HNR-PVT[BD-67]","UBX-HNR-PVT_speed@0/UBX-HNR-PVT[BD-67]","UBX-HNR-PVT_headVeh@0/UBX-HNR-PVT[BD-67]" "'2025/03/20 05:21:58.000000'","1742415718.000000","0","24.45279","140.5754456","36.308563","0.1476","102.80244" "'2025/03/20 05:21:59.000000'","1742415719.000000","0","24.45279","140.5754431","36.3085641","0.3456","102.80244" "'2025/03/20 05:22:00.000000'","1742415720.000000","1.31278","8.01281","140.5754409","36.3085642","0.9359999999999999","121.40534000000001" "'2025/03/20 05:22:01.000000'","1742415721.000000","0","8.11894","140.5754397","36.308563899999996","0.3564","112.06946" ... ChatGPTでCSVファイルを選んでアップロードします。 最初にこういったプロンプトを与えます。 フェリー航行のCSVデータをアップロードします。 タイムスタンプ、緯度経度、方位角、速度、姿勢角が含まれます。 課題:船酔いしなかったのはなぜか のためにデータ分析を行います。 以下を確認してください。 - 項目の一覧 - データ行数 - タイムスタンプ範囲 アップロードファイルの内容確認 必要に応じてデータをクレンジングします。 3 データを整えてください。 - 見やすさのため、項目名のUBX-HNR-PVT_部分と"@"以降を削除してください。 - 空の値が含まれます。直前の値を使用して穴埋め(forward fill)してください。 結果表示についても指示しておきます。 4 また、 - 分析結果のグラフは英語で、本文は日本語で表記してください。 分析準備 早速、効果的な分析方法をおすすめしてくれます。 次に進めるとしたら、まず「ロール角・ピッチ角の変動」を時系列グラフで描いて、船の揺れが小さかったかどうかを確認しますか? そのまま実行してもらいます。 姿勢角のグラフ化 Data Visualizerの roll/pitch のグラフ描画ともあっているようです。 修正して欲しいところは追加で依頼します。 修正後のグラフ 分析結果をどう理解したらいいかも質問できます。 評価指標のアドバイス 気になる部分を他項目を絡めて分析します。 特定時間帯への質問 船揺れに対する知見 最後にレポートとしてまとめてもらいます。 レポート指示 レポートまとめ 結論はこのようになりそうです。 結論 船酔いしなかったのは、当日の船の揺れが小さかったためである。 体質改善や慣れによる克服ではない。 続いての分析課題です。 行動データから安全性を客観評価 課題 弊社営業は安全運転か。 こちらの記事でご紹介した社用車の計測データを使います。 tech.aptpod.co.jp この日、社用車は出張で弊社の営業担当が運転していました。 関西への長距離ドライブで危険運転がなかったか、分析してみます。 社用車の走行計測データ 複数計測に跨って1つのCSVファイルを生成するため、 Data Visualizerを開始時刻と終了時刻をブラウザのアドレスバーで指定します。 エンジン始動で計測が区切れているためです。 https://example.jp/vm2m/?playMode=storedData&startTime=2024-11-13T15:42:01.389%2B09:00&endTime=2024-11-13T19:53:20.124%2B09:00 ダウンロードしたCSVファイルをアップしてプロンプトを与えます。 社用車走行のCSVデータをアップロードします。 タイムスタンプ、緯度経度、方位角、速度、アクセル、ブレーキ、ステアリングが含まれます。 課題:ドライバーは安全運転していたか のためにデータ分析を行います。 以下を確認してください。 - 項目の一覧 - データ行数 - タイムスタンプ範囲 CSVファイルのアップロード データをクレンジングします。 データを整えてください。 - 見やすさのため、項目名の0_RMC_部分と"@"以降を削除してください。 - 空の値が含まれます。直前の値を使用して穴埋め(forward fill)してください。 また、 - 分析結果のグラフは英語で、本文は日本語で表記してください。 データクレンジング 複数のデータ項目をクロス分析してグラフ描画して、考察させてみます。 特にステアリング(ハンドル操作)は高速になるほど操作が少なくなっていることがわかります。 車速 vs 各操作 わかりやすいように閾値を設定して再分析してもらいます。 閾値設定 ハンドル操作は低速時のみのようです。 具体的にどういうときに発生しているのか、地図に可視化してみます。 5 地図ファイルのダウンロードリンク 出力されたHTML ハンドル操作は曲がり角と駐車時に集中 ハンドル操作は停車・低速走行に集中しているという分析結果が、視覚的にも確認できました。 では、まとめてもらいます。 レポートまとめ 結論 データが示す限り、弊社営業は模範的なドライバーでした。 少なくともアクセルとブレーキは疑う余地なしです。 最後の課題は少し難しめです。 現場運用を解決 課題 モーター発熱の要因はなにか。 こちらの記事で紹介した、2025年7月の展示会での計測データを使います。 tech.aptpod.co.jp Unitree Go2-Wは研究開発モデルのため、稼働を続けるとモーターが過熱して、基板保護のために自ら脱力します。 6 分析には複数エッジの計測を利用します。 展示会でのData Visualizerスクリーン マルチモーダル環境センシング(俯瞰カメラ) 検出人物数 7 四足ロボット Unitree Go2-W ロボット脚関節モーターの温度 ロボット脚関節モーターの角度・加速度 8 ロボットの消費電流 カメラ画角が限られて不正確ながら、検出人物数は会場の人出の推移とします。 CSVをアップして、データをクレンジングします。 展示会中の計測データをアップロードします。 タイムスタンプ、俯瞰カメラによる検出人物数、四足ロボットの脚関節モーターの温度・角度・加速度、ロボットの消費電流が含まれます。 課題:モーター発熱の要因はなにか。 のためにデータ分析を行います。 以下を確認してください。 - 項目の一覧 - データ行数 - タイムスタンプ範囲 データを整えてください。 - 見やすさのため、項目名のimu.、motor_state.部分と"@"以降を削除してください。 また、 - 分析結果のグラフは英語で、本文は日本語で表記してください。 CSVファイルアップロード まずは各データの日にち・時間帯ごとのヒートマップを表示してもらいます。 会期3日間、開催時間10〜17時の時間帯別のヒートマップを示してください。 - 人出の多寡:検出人物数で推測してください。 - ロボットの稼働負荷:加速度XYZで代替してください。 - ロボットのモーター温度 各平均値のヒートマップ ぱっと見では相関関係はよくわかりません。 もう少し細かく判定条件を検討します。 脚関節角より、ロボットの状態を分類してください。 - 電源OFF:ロボットデータの行なし。 - 直立:関節角が以下の値近辺、姿勢を保つためにモーター負荷が発生。 0.angle: 0 1.angle: 42 2.angle: -85 3.angle: 0 - 歩行・階段:加速度・関節角の揺れが激しい。 - 伏せ:関節角が以下の値近辺、脱力状態でモーター負荷がかからない。 0.angle: -29 1.angle: 75 2.angle: -145 3.angle: 29 ロボット状態の判定 条件ごとに他項目との関係性を分析してもらいます。 状態ごとのモーター温度と消費電流) 状態ごとのモーター温度と消費電流(テキスト) よく知らない要素は別の要素に置き換えて説明してもらいます。 分析結果の解釈質問 具体的な運用対処も確認してみます。 運用対処の助言 これは実用上の経験とも合致します。 9 まとめです。 まとめ(依頼) まとめ(結論) 他データとの関連性を見出せたかも報告してもらいます。 まとめ(人出との関連) 結論 モーターの発熱は「酷使」の証拠である。 ただし、それが必ずしも来場者への貢献量を意味するわけではない。 おわりに 本記事では、簡単にCSVと生成AIだけでここまで分析できることを紹介しました。 intdashは複数データのタイムスタンプが揃うため、分析の正確さが向上します。 今回は最も基本的な形式として数値データを分析しました。 他の形式の計測データも分析にトライしてみようと思います。 有償サブスクリプションのChatGPT Plusを利用しています。 ↩ 生成AIの回答には 意図しない嘘:ハルシネーション が含まれます。常に分析結果の妥当性を確認しながら使うことが重要です。 ↩ GNSSとCANのように複数ソースからデータを収集している場合、1つのソースから発生タイミングでは他のソースの項目は空であるためです。 ↩ 確認したバージョンだとグラフ中の日本語が文字化けします。 ↩ 過去の記事 で利用したPythonのfoliumライブラリを指定しています。 ↩ 上位モデル は長時間の稼働ができるようになっています。 ↩ 人物検出: SDK入門④〜YOLOで物体検知しちゃう〜 を動かしています。 ↩ 実際はモーターは5つ以上あります。稼働中はどのモーターも動いているため、一部で分析しました。 ↩ 同じ質問でも毎回回答が異なります。複雑な課題ほど、データの与え方やプロンプトの微妙なニュアンスでも分析結果が変わりやすいかもしれません。 ↩
関連ニュース IoT・通信の最前線と「intdash」が拓く新たな共創のかたち イベントの目的 会場の印象:共創を前提にした展示構成 アプトポッド/intdashの展示 intdash の特徴 注目技術と共創の視点 技術トレンド・気づき(BE creation視点) 技術者視点での総括 個人的に興味を持った展示 まとめ 関連ニュース ニュース - トヨタ自動車様「第2回 スタートアップ企業 新事業・新技術展示会」出展のお知らせ(2025年9月26日) - トヨタ自動車様のYoutubeチャンネル「トヨタイムズ」での紹介記事 IoT・通信の最前線と「intdash」が拓く新たな共創のかたち  こんにちは、ソリューションアーキテクトの村松です。自動車分野のお客様の業務課題に対して「intdash」の技術を用いた解決方法を検討、システム構築等の提案業務に携わっています。 2025年10月9日、愛知県豊田市のトヨタ自動車 本社で開催された 「第2回 スタートアップ企業 新事業・新技術展示会」 に、技術者視点で参加してきました。 本記事では、展示会の印象や気づき、特に データ収集・通信基盤技術「intdash」 に焦点を当て、製造業のお客様との共創の視点で、IoTプラットフォームとはどうあるべきかを整理します。 www.aptpod.co.jp イベントの目的  本展示会参加の主な目的は以下の2点です。 AI・IoT技術の最新トレンドを把握すること intdash (アプトポッド)の活用拡大可能性を探ること 加えて、トヨタ自動車様が掲げる BE creation(新事業創出スキーム) において、技術者としてどのように共創に関われるかを考察する場ともなりました。 https://global.toyota/newbiz/becre/about/ 会場の印象:共創を前提にした展示構成  会場の最初に目に入ったのは、トヨタ自動車様が外部技術との接点づくりを意識した BE creation ブース です。 4つの展示区画に分かれ、トヨタ自動車様の技術・プラットフォームを開放し、スタートアップやアカデミア、産業界と共創する姿勢が強く印象に残りました。 展示構成は「共創」を前提とし、 “自社技術を囲う”のではなく、“他社技術とつなげる”ための空間設計 がされていました。 来場者同士の会話を促す配置や、リアルタイム連携デモが複数同時に展開されるなど、単なるプレゼンテーションではなく 「共に作る場」 としての意図が明確に感じられました。 アプトポッド/intdashの展示  アプトポッドのブースでは、基盤技術 intdash と TOYOTA GAZOO Racing 様における「intdash」によるリアルタイム遠隔計測システムの公式採用について紹介。 世界中を転戦するレース車両に弊社ハードウェア「EDGEPLANT T1」が搭載され、過酷な使用環境の中、高精度/大容量な計測データがクラウドに集約されレース車両の日々の性能改善や車両開発に活用されています。 ブース風景 先日、トヨタ自動車様のYouTubeチャンネル「トヨタイムズ」において、ニュルブルクリンク24時間レースでの利用シーンが公開されています。 こちらも合わせてぜひご覧ください。 トヨタイムズ公式チャンネル(該当動画はこちら) ※「intdash」利用シーンは 3:40頃 / 17:13頃 / 19:58頃 に登場します。 www.aptpod.co.jp intdash の特徴 製品ページへ 高スループット・低遅延のストリーミング通信基盤 複数のデバイス・拠点間でリアルタイムにデータをやり取り可能 展示では、センサーや車載機器から取得したデータをクラウドで統合・可視化・解析するデモが連続して行われ、多くの来場者が訪れていました。 技術者視点では、intdash は単なるスタンドアロン技術ではなく、 共創を支える基盤 として価値を持っています。 BE creation におけるプラットフォーム提供者としての立ち位置 共創エコシステムへのデータ基盤技術の供給 出展企業・スタートアップとのインターフェース技術としての拡張性 モビリティ、製造、建設、エネルギーなど異分野融合領域での利用接点 つまり、intdash は「データをつなぐ技術」であると同時に、 "共創インフラとしての可能性" を秘めています。 www.aptpod.co.jp 注目技術と共創の視点 技術 特徴 共創ポテンシャル スカイディスク(最適ワークス) AIによる生産計画最適化 プラットフォームと連携し、リアルデータを活用したクロス企業製造最適化が可能 LOZI(SmartBarcode) 製造~物流可視化ソリューション リアルタイムタグ情報をプラットフォームに流し込み、他モジュールと連携可能 ALGO ARTIS 複雑スケジュール最適化エンジン intdash のストリーミングデータで動的スケジューリング実現の連携可能性 Preferred Networks 自社完結型 AI基盤 通信最適化・分散AI・プラットフォーム連携で戦略的立ち位置を模索     技術力だけでなく、「共創に開くか閉じるか」が技術の将来性を決める という点が非常に印象的でした。 技術トレンド・気づき(BE creation視点) 通信基盤の価値向上 : 裏方のインフラから、共創の土台への期待 インターフェース性・拡張性 : API公開やモジュール接続、他社技術との共存性が重要 共創組織文化と技術アプローチの融合 : 制度設計と接続性設計の両立が不可欠 リアルタイム制御×生成AI : ストリーミングデータとリアルタイムAIによる制御・最適化が進行中 技術者視点での総括  intdash は単なるデータ基盤ではなく、 "BE creation の文脈で意味を持つ共創インフラ" として成長可能です。 現代の技術価値は、「良いものを作ること」だけでなく、 "誰と、どう使われるか" によって決まります。 今後のアクションプランとしては: BE creation を考慮しつつ具体的な技術提供先を探索 他出展企業との共同PoC(概念実証)を企画 intdash の機能を共創・拡張性・プラットフォーム性に合わせて強化 これにより、intdash は "「つなぐ技術」から「共創を支える基盤」へ" さらなる進化をしていく。 個人的に興味を持った展示  浮体式洋上風車を開発するベンチャー、 アルバトロス・テクノロジー の展示も印象的でした。 https://www.albatross-technology.com AI普及によるCPU/GPU消費電力の増加に対して、 安定した再生可能エネルギーの一分野として注目される浮体式洋上発電 。 従来型の洋上風力発電とは異なり、低フットプリント・折りたたみ可搬可能な設計 発電時は、携帯電話基地局のような形状で、空間の有効利用が可能 低コストで安定した電力供給が可能 日本の国土は38万km²ですが、EEZ(排他的経済水域)を含めた海洋面積は世界第6位。 洋上領域の利用は、新たな技術・エネルギーパラダイムの鍵 になると感じました。 まとめ intdash は共創を支えるデータ基盤として大きな可能性を秘めてる。 技術の未来は、単なる性能より「共創への開放度」が重要となる。 組み合わせから生まれる新たな価値創出が期待される。
動画ファイルをintdashに取り込みたいみなさん、 こんにちは。ソリューションアーキテクトの伊勢です。 今回はMP4ファイルをintdashの計測データとして登録する方法をご紹介します。 はじめに データフロー H.264とは MP4ファイルとは H.264の格納形式とは Gstreamerとは インストール やってみた 実施手順 MP4ファイルダウンロード 映像編集 アップロード実行 計測再生 サンプルプログラム Convertor MeasurementWriter UploadService エントリーポイント おわりに リンク はじめに すでに保有している計測データファイルをintdashで可視化したいケースがあります。 例えば、システム構想段階でUXを試したいときなどです。 MP4ファイルの計測データ化 通常、intdashの計測データはエッジコンピューターからサーバーに送信されますが、サーバーにファイルの計測データを登録する機能もあります。 intdashのMeas Hubでは、タイプスタンプとデータ値が格納されたCSVファイルをアップロードして計測を作成できます。 Meas Hub 計測アップロード一覧 time,DATA_1,DATA_2,DATA_3 2024-01-01T00:00:00.123456789Z,1,0.1,str1 2024-01-01T00:00:01.123456789Z,2,0.2,str2 2024-01-01T00:00:02.123456789Z,3,0.3,str3 2024-01-01T00:00:03.123456789Z,4,0.4,"str4,example" 2024-01-01T00:00:04.123456789Z,5,0.5,"str5 ""last data""" この方法ではデータは数値または文字列の形式である必要があります。 今回は映像データを登録するため、SDKを使ってツールを実装します。 1 データフロー 今回は、取り込んだ映像を他の計測と同期再生させてみます。 既存の計測からMP4としてダウンロード 映像編集ソフトで加工 ツールでMP4ファイル(編集後)をアップロード Data Visualizerで可視化・同期再生 データフロー H.264とは 今回扱う映像データはH.264で圧縮されています。 前のフレームから変化した部分だけを扱い、データ量を低減する仕組みです。 IDRフレーム/キーフレーム:すべての画素を持ち、単独でデコードできます。動画の基準点として定期的に差し込まれます。 Non IDRフレーム/デルタフレーム:変化した部分だけを持ち、単独では表示できません。IDRフレームと組み合わせて利用されます。 www.idknet.co.jp H.264フレームは、1〜複数のNAL Unit(Network Abstraction Layer Unit)というバイナリ列で構成されます。 MP4ファイルとは 動画や音声をひとつのファイルにまとめて扱える形式です。 再生時には内部の映像や音声を取り出し、タイムスタンプに基づいて同期再生します。 H.264の格納形式とは バイナリデータである映像フレームを区切る方法です。 AVCC形式:保存向き。フレームの先頭にフレームサイズを記録します。最新のMP4で利用されます。 2 Annex B形式:ストリーム向き。フレームの先頭に境界を示すスタートコードを付与します。intdashなど伝送処理で利用されます。 Gstreamerとは 動画・音声を変換できるオープンソースのメディアフレームワークです。 3 今回はMP4ファイルのAVCC形式からAnnex B形式へ変換するのに利用します インストール SDK入門② でインストールしたREST APIのクライアントライブリと、 SDK入門④ でインストールしたGstreamerとPyGObjectライブラリを利用します。 やってみた 実施手順 それでは、前述の流れでMP4ファイルを取り込みます。 H.264フレームのタイムスタンプが各段階でどうなるかを示します。 タイムスタンプ対応 MP4ファイルはAVCC形式のタイプスタンプ項目に1フレーム目起点の相対時刻を持ちますが、絶対時刻はありません。 そのため、ツールで改めて計測の基準時刻を与える必要があります。 MP4ファイルダウンロード intdashのMedia Explorerで元計測の映像をMP4ファイルとしてダウンロードします。 4 このとき、映像1フレーム目の時刻を覚えておきます。 MP4ファイル作成画面 MP4ファイルをダウンロードします。 MP4ファイルダウンロード 映像編集 MP4ファイルを映像編集ソフトで編集します。 今回は文字をオーバーレイしてみます。 MP4ファイルを出力します。解像度・FPSは映像編集ソフトに依存します。 アップロード実行 対象エッジと基準時刻を指定してアップロードします。 今回は元の計測とは別のエッジとして作成します。 基準時刻は元計測の映像1フレーム目の時刻にします。 5 ツール起動 全ての映像フレームがアップロードされ、計測が完了します。 アップロード完了 作成された計測 計測再生 intdashのData Visualizerで元の計測を指定してプレイバック再生します。 映像(左)・GNSS・IMU:元の計測です。 映像(右):編集したMP4ファイルから取り込んだ計測です。 www.youtube.com 映像は元の計測がHD・15FPS、編集後がFullHD・30FPSですが、 計測データのタイムスタンプにより、問題なく同期再生されます。 サンプルプログラム Gstreamerとデータ送信を非同期で実行しています。 クラスアーキテクチャ Gstreamer:H.264フレームをAVCC形式からAnnex B形式に変換します。 Fetchステージ:GsteamerからAnnex B形式のフレームを取り出します。 Convertor Gstreamerをラップします。 入力はMP4ファイルから呼ばれるため、特にメソッドはありません。 出力では、映像フレームを size ごとに取得します。 while len (frames) < size: sample = await asyncio.to_thread(self.sink.emit, "pull-sample" ) MeasurementWriter 計測の作成・完了、シーケンスの作成・置き換え、チャンク送信を行います。 6 intdashのH.264フレームは以下のNAL Unit順で扱うため、Gstreamerから出力されるAUD NALU Type:9 をスキップしています。 IDRフレーム:SPS NALU Type:7 →PPS NALU Type:8 →IDR NALU Type:5 non-IDRフレーム:non-IDR NALU Type:1 payload = MeasurementWriter.skip_aud(frame) IDR/non-IDRを判定し、送信時のデータ型を指定してデータポイント、チャンクを生成しています。 is_idr = self.is_idr_frame(payload) type_name = "h264_frame/idr_frame" if is_idr else "h264_frame/non_idr_frame" store_data_point_group = StoreDataPointGroup( data_id=StoreDataID( type =type_name, name=data_name), data_points=[store_data_point], ) store_data_chunk = StoreDataChunk( sequence_number=self.sequence_number, data_point_groups=[store_data_point_group], ) UploadService GstreamerパイプラインとFetchステージを並列起動しています。 self.convertor.start() fetch_task = asyncio.create_task(self.fetch()) # H.264フレーム取得 エントリーポイント MP4ファイルを読んでH.264(Annex B形式)に変換するGstreamerパイプラインを定義しています。 PIPELINE = """ filesrc location="{path}" ! qtdemux name=demux demux.video_0 ! h264parse config-interval=-1 ! video/x-h264,stream-format=byte-stream,alignment=au ! appsink name=sink sync=false emit-signals=true """ 計測の基準時刻をRFC3339形式で指定します。 指定がないときは現在時刻を基準時刻にしています。 datetime.fromisoformat(basetime) if basetime else datetime.now(tz=timezone.utc), おわりに 今回はintdash外のデータを取り込む一例を紹介しました。 MP4ファイルのタイムスタンプを利用して、intdashの時系列管理に統合できました。 既存の計測データでintdashへの格納や可視化を試せると、システム運用を具体的にイメージしやすくなります。 リンク 本シリーズの過去記事はこちらからご覧ください。 SDK入門①〜社用車で走ったとこ全部見せます〜 :REST APIでデータ取得 SDK入門②〜データ移行ツールの作り方〜 :REST APIでデータ送信 SDK入門③〜RTSPで映像配信するぞ〜 :リアルタイムAPIでデータ取得 SDK入門④〜YOLOで物体検知しちゃう〜 :リアルタイムAPIでデータ送信 SDK入門⑤〜iPadでData Visualizerを見る会〜 :リアルタイムAPIでキャプチャデータ送信 SDK入門⑥〜最速最高度で計測する日〜 : AWS LambdaでREST APIデータ送信 SDK入門⑦〜計測リプレイツールの作り方〜 : REST APIでデータ取得、リアルタイムAPIでデータ送信 コードは GitHub で公開しています。 ↩ MPEG-4 Part 10です。本ツールはこの形式のMP4を前提としています。 ↩ 入門④ でも利用しました。 ↩ 2025年4月のバージョンから時間範囲を指定できるようになりました。 ↩ 計測の開始時刻≦映像の1フレーム目の時刻のためです。 ↩ 計測シーケンス、チャンク送信は 入門② を参照ください。 ↩
IoTデータの通信量にお困りのみなさん、 こんにちは、ソリューションアーキテクトの伊勢です。 車両やロボットがデータ伝送するには無線通信が必要ですが、SIM 1枚では安定しないという課題があります。 山間部や遮蔽物が多いなど電波が弱いエリア 4K画質映像やLiDAR点群などの大容量データ 今回は、SIMやWifiなど複数の回線を束ねるボンディングという技術を実現するマルチ回線ルーターをご紹介します。 はじめに ボンディングとは peplinkルーターとは ボンディングの効果 実測してみた MAX BR2 Pro MAX BR2 Micro おわりに はじめに ボンディングとは 複数の物理的な回線やインターフェースを束ね、仮想的に単一の高速・大容量・高信頼性の通信チャネルとして利用する技術です。 専用のルーターがパケットレベルでデータを複数の回線に分散して送信します。 これにより、1本の帯域を超える大容量データでもスムーズに伝送できます。 通信回線ボンディング peplinkルーターとは 当社ではpeplink社のマルチ回線ルーターをご提供しています。 1 サーバーに配置した仮想ルーター〜物理ルーター間にVPNを構成する仕組みです。 ポイント VPNで伝送したデータは終端ルーターで統合を行う仕組みのため、束ねた複数回線の帯域を単純に足し合わせたより少し低くなります。 tech.aptpod.co.jp ボンディングの効果 車載したエッジコンピューターからカメラ2台分の映像を送信・可視化しました。 www.youtube.com SIM 1枚構成では伝送遅延によりブロックノイズが発生しますが、 SIM 2枚構成ではスムーズに表示できていることがわかります。 2 当社でも、お客様への提案のほか、展示会デモで活用しています。 展示会で多くの方にご来場いただくとLTE回線が混雑する場合、複数SIMの利用でロボットのカメラ・LiDARデータ伝送や遠隔操縦の安定化を感じられます。 tech.aptpod.co.jp 実測してみた ボンディングで通信速度が数値的にどのぐらい上がるのか、色々と回線を組み合わせて検証してみました。 物理ルーターコンソール ポイント 今回はモビリティではなく、オフィスの机上定点で測定しています。 2機種で帯域を計測しました。束ねられる回線数が異なります。 5G マルチ回線モバイルルーター:MAX BR2 Pro インタフェース 回線数 5G/LTE SIM 2 USB 1 Wi-Fi 2 有線WAN 2 マルチ回線モバイルルーター:MAX BR2 Micro インタフェース 回線数 LTE SIM 2 有線WAN x1(LANと共用) 1 計測にはGoogleスピードテストを使用しました。 ポイント 数回実施してみていますが、エリア・時間帯で変動する要素が大きく、結果を保証するものではありません。 MAX BR2 Pro 計測タイミングでブレが大きいのですが、 SIM 1枚よりSIM 2枚の方が、 SIM 2枚よりSIM 2枚 + USB/Wifiの方が 概ね帯域が増加していることが確認できました。 MAX BR2 Pro測定結果 ボンディングの分散具合をintdashへのデータ伝送で確認しました。 アップリンクを多く発生させるため、iPhoneアプリ Motion でMJPEGを送信します。 これで上り40Mbpsほどになります。 MJPEGを送信 FullHD/5FPS 以下のパターンを確認しました。 有線WAN x1 SIM x1 docomo SIM x2 docomo/Softbank SIM x2 docomo/Softbank + Wifi x1 Throughput Tx が複数回線で分散されていることがわかります。 ポイント どのように分散されるかは回線品質の状態によります。 3本まとめたのにほとんど2本しか使われないパターンもありました。 ボンディングによる通信の分散 MAX BR2 Micro SIM 2枚では、ダウンリンク・アップリンクともに15Mbps出ています。 3 MAX BR2 Micro測定結果 おわりに peplinkルーターで回線ボンディング後の帯域を確認しました。 DX化が進むと収集データは多様化・多数化・大容量化されていきます。 ネットワーク帯域の確保は、intdashの安定運用に必要不可欠になっていきます。 当社では、4機種のpeplinkルーターをご提供しています。 大容量データを扱うモビリティの通信安定性に課題を感じている方は、ぜひお問い合わせください。 www.aptpod.co.jp 専用VPN(SpeedFusion VPN)を用いたルーターを利用します。peplinkルーターの日本代理店である CASO様 にご提供いただいています。 ↩ SpeedFusion Engineはすでに販売終了で、現在は後継機をご提供しています。 ↩ 有線WANはEthernetポートが埋まってしまい、PCから接続・スピードテストできないため割愛しています。 ↩
はじめに こんにちは、エンジニアの上野です。 この度、株式会社アプトポッドは2025年7月23日(水)~7月25日(金)に東京ビッグサイトにて開催された「メンテナンス・レジリエンス TOKYO 2025」にNTTドコモビジネス株式会社様と共同で出展いたしました。 mente.jma.or.jp 昨年度のレポート に続きまして、今年は私が弊社の展示や関連技術の見学をしてきましたので、その内容の一部をご紹介したいと思います。 はじめに 会場の様子 展示内容 リアルタイムデジタルツインデモ ロボット点検・設備 マルチモーダル環境センシング 広帯域モバイル伝送 他社様のブースを見学した感想 おわりに 会場の様子 私が見学した日は、快晴かつ真夏の陽気で、非常に暑い一日でした。 それにも関わらず展示会場は多くの来場者で賑わっており、ありがたいことにアプトポッドのブースも盛況で、弊社の技術やサービスに対して高い関心をお寄せいただきました。 展示内容 リアルタイムデジタルツインデモ 昨年に引き続き、日立建機株式会社様のご協力のもと、弊社が開発した リアルタイムデジタルツイン基盤 のデモを展示しました。 youtu.be 今回のデモでは、遠隔地のオペレーターがホイールローダーの搭乗者に対して作業エリアの切り替えを指示し、移動完了後にエリアのステータスが変化する様子を展示しました。私はこのアプリケーションの開発を担当しています。 昨年は点群と重機の可視化が中心でしたが、今年は事前に計測した数千万点クラスの点群を用いて、よりリアルな現場再現と遠隔操作の連携によるインタラクティブな体験を提供するなど、デジタルツインの完成度が一層向上しています。 ロボット点検・設備 今年もUnitree Go2による遠隔操作デモを展示しました。加えて、今回は各足の先端にゴムタイヤを搭載したUnitree Go2-Wも展示されており、階段のような段差も軽々と乗り越える様子が印象的でした。 youtu.be Go2-Wには酸素センサーとアルコールセンサーが搭載されており、会場内に用意されたアルコールスプレーによって、リアルタイムに数値が変化する様子が確認できました。 ロボットによる点検業務への応用が期待されており、異常検知や設備状況の可視化など、実運用を見据えた展示となっていました。 マルチモーダル環境センシング アプトポッドでは、LiDAR・カメラ・温湿度センサーなど、複数のセンサーデータを統合して多面的な環境把握を行う「マルチモーダル環境センシング」にも取り組んでいます。 本展示では、カメラ映像による人体検知、LiDARスキャナによる空間のメッシュ化および人体検出、さらにはサーモグラフィカメラを活用した温度センシングを組み合わせたデモを実施しました。 熱分布の可視化により、異常発熱や熱中症の兆候、設備の異常を早期に発見することが可能です。取得した温度データはintdash上でリアルタイムに可視化され、時系列での分析にも対応しています。 なお、LiDARスキャナによる空間のメッシュ化および人体検出については、株式会社東海林ファジィロボット研究所様 の技術を利用させていただきました。 LiDARスキャナから取得した点群をリアルタイムにメッシュ化することにより、人体検出や詳細な空間形状の把握が可能となります。 広帯域モバイル伝送 アプトポッドでは、複数のモバイル回線を束ねて広帯域なデータ伝送を実現する「intdash Multi Mobile Network」というソリューションを提供しています。 www.aptpod.co.jp youtu.be 今回の展示でも、Unitree Go2に本ソリューションを適用。複数のSIMを用いることで、1枚のSIMでは処理しきれない広帯域の点群・映像データも安定して送信できている様子を確認できました。 UnitreeGoに搭載されたマルチSIMルーター、SIMが2枚刺さっている様子。 一方、昨年と同じ構成(MID-360 LiDAR × SIM1枚)では、データ伝送がギリギリという印象であり、実際のユースケースではマルチSIMの重要性がより高まっていることを実感しました。 他社様のブースを見学した感想 今回、他社様の展示を見学して特に印象的だったのは、「現場の3D化」がより一般化・多様化してきているという点です。 私もかつてiPhone搭載LiDARを用いた3Dスキャン記事を書いたことがありますが、今回の展示ではiPhoneを使ったスキャン、ハンディ型LiDAR、据え置き型レーザースキャナ、ドローン搭載型など、実に多様なスキャン手法が紹介されていました。 特に、法律上ドローンが使いづらい場所ではハンディタイプが有効であり、iPhoneの弱点である位置精度を補うGNSS連携型デバイスなども見られ、各社の工夫と進化が垣間見えました。 炎天下でのiPhoneスキャンに苦しんだ経験がある私としては、代行スキャンサービスの展示も非常に魅力的に感じられ、3D計測の市場が着実に広がっていることを実感しました。 おわりに 昨年に続き出展させていただいた「メンテナンス・レジリエンス TOKYO 2025」は、弊社にとっても技術の発信と学びの両面で非常に有意義な機会となりました。 ご来場いただいた皆様、誠にありがとうございました。 人手で行っていた業務をロボットで行いたい ロボットの遠隔操作を行いたい 大量データを扱えるハイパフォーマンスな可視化アプリケーションを開発したい アプトポッドでは、IoT・ロボティクス・リアルタイム通信の分野で培った技術を活かし、皆さまの課題解決を全力でサポートいたします。お気軽にご相談ください。 お問合せフォームはこちら。 www.aptpod.co.jp
はじめに IoTシステムのデータ伝送には、MQTTが一般的に広く採用されています。AWS IoT、Azure IoT Hubなど、主要クラウドプラットフォームでもMQTTブローカーを内蔵したマネージドサービスが提供されており、ここ数年でIoTシステムの構築は劇的に楽になりました。 しかしながら、MQTTで伝送したリアルタイムデータを実際に活用するための 可視化や分析ツール に関しては、現在も様々なサービスが登場し発展の途上にあります。 MQTTデータ可視化ツールの現状と課題 代表的なMQTTデータの可視化ツールとして、以下のようなものが挙げられます。 MQTT Explorer Node-RED Dashboard ThingsBoard Grafana Live + MQTT Data Source InfluxDB + Chronograf これらのツールにはそれぞれ特徴がありますが、高頻度なセンサーデータ(数百~数千Hz)のリアルタイム表示には十分に対応できず、パフォーマンスに問題が生じるものも多くあります。また、センサーデータに動画や音声といったマルチモーダルデータを統合的かつ同期的に扱うことは難しく、多くのツールでは同期再生ができません。 高頻度マルチモーダルデータの可視化を実現するintdash/Visual M2M 当社は、高頻度でリアルタイム性を求められるIoTデータの伝送と可視化に特化したintdash(伝送ブローカー)およびVisual M2M(可視化ダッシュボードツール)を自社開発しています。intdashとVisual M2Mは、以下のような特徴を持ちます。 ハイパフォーマンス : 数千Hzを超える超高頻度データでもスムーズに描画 マルチモーダル : センサー値に加え、動画や音声なども統合的に同期再生 本記事では、可視化ダッシュボードツールであるVisual M2Mを用いて、MQTTで伝送された高頻度リアルタイムデータを、ハイパフォーマンスに可視化する方法についてご紹介します。 www.aptpod.co.jp 従来Visual M2M(可視化ダッシュボード)を利用するにはバックエンドの伝送基盤としてintdash(伝送ブローカー)を導入し、送信デバイス側もintdashへの対応が必要でしたが、既存のMQTT環境からもintdashの高性能な可視化環境を利用してみたいとのお声をいただき、このたび、後段でご紹介する「MQTT-intdashリレープログラム」を実験的に開発しました。本記事ではこのリレープログラムを用いたMQTTとVisual M2Mの連携方法をご紹介します。 本プロジェクトは現在 Experimental なステータスにあり製品化を模索している状況ですが、ご要望をいただければ本番システムにて稼働できる品質のソフトウェアをご提供可能です。ご興味をお持ちいただけましたら、お問い合わせ等の詳細情報についてはブログ末尾をご確認ください。 MQTTからintdashへのリレー構成 本来、最適なパフォーマンスを実現するには、伝送基盤のintdashと可視化ツールのVisual M2Mをセットで導入していただき、デバイス側も含めてすべてintdashに置き換えていただくのが理想です。 しかし、デバイス側の置き換えには大きな移行コストがかかることも踏まえ、今回は既存システムを活用しながらリレーによってMQTTとintdashを接続する構成をご紹介します。こちらの構成では、まずはintdashとVisual M2Mの性能を気軽に体感していただくことを目的としています。 本構成のメリット: 既存のMQTT環境を変更することなく試験的にVisual M2Mを導入可能 Visual M2Mの優れたパフォーマンスと高機能な可視化を手軽に体験 デメリットとしては、MQTTとintdashの二重構造による冗長性が挙げられますが、まずはVisual M2Mの利便性を体感し、最終的にintdashへの全体移行を検討するためのきっかけとしてご活用いただければ幸いです。 構築ハンズオン 本記事では、既存のMQTTベースのIoTシステムにintdashおよびVisual M2Mを追加導入する構成を前提としたハンズオンを行います。具体的には、OSSのMQTTブローカー(Mosquitto)とRaspberry Piを用いたセンサーデバイスで既存システムを模倣し、そのシステムにintdash/Visual M2Mをリレープログラム経由で追加して、データの可視化までを行います。 ※ 記事執筆当初はハンズオンも含む記事とする予定でしたが、想定外に分量が多くなってしまったため、ハンズオン部分は別途別記事に切り出すこととしました。後日公開予定です。以降のセクションは、ハンズオンの結果についてスクリーンショット付きで解説していきます。 実際の可視化の様子 まずは一般的なMQTTダッシュボードを使用してデータを可視化してみましょう。Raspberry Piからデータ送信を開始しMQTTダッシュボードを確認すると、データが流れている様子が確認できます。 今回は冒頭でも触れた MQTT ExplorerとNode-RED Dashboardをサンプルとしてご紹介します。 MQTT Explorer MQTT Explorer は構築しやすい反面、可視化の表現が限定的です。1トピックあたり1パネルとなり、それぞれのデータの相関具合を確認したりするには少し工夫が必要です。 Node-RED Dashboard 次に、Node-RED Dashboardで可視化する方法も試してみます。 こちらは重ね合わせでの表現も可能ですが、一方でパフォーマンス面で問題が生じました。パフォーマンスの問題については後続のセクションでVisual M2Mと比較します。 Visual M2M 同じデータをintdashにリレーし、Visual M2Mで可視化してみます。 Visual M2Mでは、様々な可視化パーツとグリッドで構成された柔軟なダッシュボードにより、流れているデータを自由に可視化することができます。 ダッシュボードの自由度も高く、描画パフォーマンスも良好で、高頻度なセンサーデータをリアルタイムに描画できました。 描画パフォーマンスの比較 今度は、ダッシュボードの描画パフォーマンスについて、Visual M2Mとその他のツールを比較してみましょう。 今回は比較対象として、Node-RED Dashboardを取り上げます。以下に、Node-RED Dashboard と Visual M2M を並べて再生した動画を示します。 youtu.be Node-RED Dashboardは、静止画では一見問題なく描画されているようにも見えましたが、連続再生していると徐々に描画がリアルタイムから遅れていき、最終的には何秒も遅れたデータが画面上に描画されるようになってしまいました。一方、Visual M2Mは、高頻度データでも滑らかかつ遅延なく表示できています。 低遅延なIoTデータの伝送や可視化については、MQTTなどの "伝送プロトコル" の部分が注目されがちではありますが、最終的にエンドツーエンドで低遅延にデータを届けるには描画側のパフォーマンスも重要な要素であることをおわかりいただけたかと思います。 Grafana との比較と Visual M2M の強み MQTTに少し詳しい方であれば、広く使われている Grafana が比較対象として出てきていないことにお気づきかもしれません。 Grafana は、ダッシュボードの柔軟性やリアルタイム描画のパフォーマンスに関して評価する場合、OSSにおいては最も魅力的かつデファクトスタンダードとなりつつある選択肢の一つです。 このセクションでは、この Grafana について個別に枠を設けて特に掘り下げて、 Visual M2M との違いを明らかにしていきます。 grafana.com Grafana におけるリアルタイム再生の仕組み Grafana は、もともとサーバー監視などで利用されることが多く、単体のままではリアルタイム描画には対応していませんでした。 しかし、v8 で追加された Grafana Live というメッセージングエンジン(Grafana専用のブローカー)を有効化することによって、リアルタイム描画が可能になります。 Grafana Live では、Grafana が稼働しているサーバーのプロセス内に可視化専用の Pub/Sub ブローカーを起動するようです。 Grafana と MQTT とをつなぐ MQTT Data Source は、この仕組みを使用してMQTTブローカーからのデータを専用ブローカーに中継し、Webブラウザまで送り届けます。 Grafana Liveの可視化専用ブローカーは可視化に特化した簡易的なものではあるものの、MQTTブローカーから別のブローカーに中継するという意味で、intdash/Visual M2Mの構成と近しい構成といえます。 Grafana vs Visual M2M それでは、比較のために Grafana での描画の様子をみてみましょう。 UIのデザインに関にしては、これまでに比較した MQTT Explorer や Node-RED Dashboard からは一歩抜きん出ていることが分かります。 黒を基調としたダークなデザインである点がVisual M2Mと良く似ていますが、Visual M2Mのほうが若干ビビッドではっきりした色合い、Grafana のほうがすこし落ち着いた色合いをしています。 youtu.be ここからは、Visual M2Mとの違いを一つずつ見ていきます。 Visual M2Mとの違い① : ブローカーの違い 違いの1つ目は、ブローカーの違いです。 Grafana Live の可視化専用ブローカーは可視化専用の簡易的なもので、通常構成ではサーバーのプロセス内でしか通信ができません。複数のプロセス間で通信するには v8.1 で追加された Redis-based Live HA の構成が必要ですが、これはまだ Experimental 扱いのようです。また、メッセージサイズやフレーム頻度にも限界があり、今回のケースのようなIMUセンサー1台程度であれば問題ありませんでしたが、大量のデバイスからのデータや大量データの可視化ではパフォーマンスが追いつかなくなることが予想されます。 一方、intdash/Visual M2Mでは、そもそも大量のデータを中継するために作られたデータ伝送用のブローカーintdashがデータを中継する構成をとるため、デバイスやデータ量が増えても問題は生じにくくなっています。 Visual M2Mとの違い② : マルチモーダル対応の違い 違いの2つ目は、マルチモーダルデータへの対応方法の違いです。 IoTデータを収集するフィジカルな現場では、数値データだけでなく映像や音声などマルチモーダルなデータを取り扱うことがよくあります。 たとえばリアルタイムな映像データをGrafanaで再生しようと考えた場合、どうなるでしょうか? そもそもMQTTでの映像伝送はあまり一般的ではないのでWebRTCなどを併用することになりますが、WebRTC用のプラグインはコミュニティにより提供されたものしか存在しないようです。 さらにWebRTC用をはじめとする映像再生系のプラグインは、いずれもGrafana Live を使用する仕組みではなく、直接映像データを映像ソースから受け取る仕組みになっているようでした。 このようにデータがそれぞれ別の経路を辿って伝送され、さらに別々の開発元によって作られた別のパネルで再生されるような構成では、 一見同時に再生されているように見えても、各瞬間瞬間で本当に同時刻のデータが画面上に描画されているかは担保できません。 一方、intdashでは、共通のブローカー(intdash)により、センサー値から映像・音声、点群データまで大小様々なデータを、単一のコネクションにより転送することができます。 可視化ツールである Visual M2M も、データの同期を正しく取って再生するように作り込まれているので、マルチモーダルな様々なデータがその瞬間どの様に関連していたのかを正確に把握することができます。 今後の拡張性と推奨構成 今回は、既存システムを活かすことを重視し、intdash/Visual M2Mを横付けする構成としました。しかし、この構成はintdash/Visual M2Mの持つパフォーマンスを最大限に生かせるものではなく、構成上の冗長性もあります。 intdashの性能を最大限に活かすには、バックエンドのMQTTブローカーもintdashに移行し、よりシンプルで効率的な構成とすることがおすすめです。 Visual M2Mはマルチモーダルデータを同一のダッシュボードで再生できるため、従来のMQTTベースのダッシュボードツールでは対応していなかった製造や音声などのデータも、センサーデータとあわせて同期再生できるようになります。 intdashをベースとすることで、マルチモーダルなデータを含む高度なリアルタイム監視や分析環境をシンプルな構成で実現することができるようになり、複数のOSSを組み合わせて構築する場合に比べて運用や保守の負担が大きく軽減されます。 おわりに 本記事では、既存のMQTT環境を維持しながら、intdashおよびVisual M2Mを導入し、その強力なパフォーマンスやマルチモーダルデータの統合表示機能を体感いただける構成をご紹介しました。本記事をきっかけに、まずはVisual M2Mの優れた性能をお試しいただき、そのメリットを実感していただければ幸いです。 ぜひ、この機会にintdash/Visual M2Mのトライアルをお試しください。ご質問や導入に関するご相談は、以下のリンクからお気軽にお問い合わせください。 www.aptpod.co.jp www.aptpod.co.jp
ソリューションアーキテクトの奥山です。 人とくるまのテクノロジー展 2025 YOKOHAMA(5/21–23、パシフィコ横浜) には617 社が出展、約8万人に迫る大型イベントとなりました。弊社アプトポッド も新製品を携えて出展しましたので、レポートをお届けします。 アプトポッドブース(No. 206)では “ 小型 × 即時データ活用 ” を掲げ、 EDGEPLANT R1 と EDGEPLANT CAN FD USB Interface を初披露しました。さらに、自動車業界で長年実績を持つ計測機器メーカー様でも intdash を核にした連携サービスの採用が広がっています。 展示会概要と弊社ブースのご紹介 新製品 EDGEPLANT R1 ―片手サイズエッジコンピュータ 特徴 ユースケース EDGEPLANT CAN FD USB Interface — 高速起動CANロガー 特徴 ユースケース ご要望をお寄せください 関連ブースのご紹介 共和電業様 KYOWA CLOUD STREAM IMV様コネクタ評価試験 まとめ デモ機貸与・PoC のお申し込みはこちら↓ 製品に関するお問い合わせはこちら↓ 展示会概要と弊社ブースのご紹介 会期:2025-05-21(水)– 23(金) 会場:パシフィコ横浜・展示ホール/ノース 規模:出展 617 社・約1,470 小間、総面積 26,500 ㎡、来場者数 79,808 名 アプトポッド は Testing ゾーンに出展しました。来場者の約 7 割が車両開発・研究エンジニアという環境で、 リアルタイム計測と省スペース を両立した新製品と intdash 活用事例を中心に展示しました。 以下が営業チーム渾身のブースです! 狭いながらも目線・動線を計算し、intdash を知っていただくためレイアウトにこだわりました。こだわりすぎて展示コンテンツがギリギリまで仕上がらなかったのはここだけの話です。 www.aptpod.co.jp 弊社ブース 中央 2 台が今回リリースした EDGEPLANT R1 と EDGEPLANT CAN FD USB Interface 。両脇は参考展示の 4K 防塵防水カメラと電源制御ユニットです(鋭意製品化中!)。 新製品 自動車遠隔データ収集ソリューションでは、 intdash Multi Network のデモ映像に足を止める方が多く、「導入したい」とのお声もいただきました。 自動車遠隔データ収集ソリューション 展示会に来れなかった方も intdash Multi Network のデモ映像で体感してみてください。 www.youtube.com 大型ディスプレイでは弊社クラウド活用事例を上映し、「コスト改善につながった」といったお客さまの声を掲示しました。 クラウドによるデータ収集と自動化を支援 映像をYoutubeに公開しましたので、ご覧ください。 www.youtube.com 当日、お客様から様々な業務課題や製品FAQをいただきました。最近の傾向として、遠隔計測にとどまらず計測対象となるデータの種類や容量が爆増するなかで、どのようにデータ処理や管理を効率的に進めるのか、データ収集後の利用活用について課題をお持ちのお客様が多くいらっしゃる印象をもちました。弊社エキスパートによる提案事例紹介や商談裏話などを共有させていただき、お客様との対話を深めることができました。会期を通じて、展示会ならではな熱気を感じとることができ、より良い製品をめざして開発に取組むための活力をいただくことができました。 intdash AutomotivePro おかげさまで 3 日間とも大盛況。最終日はブース内が身動きできないほどでした。ご来場いただいた皆さま、誠にありがとうございました! 大盛況のブース その他、人とくるまのテクノロジー展で展示させていただいた動画は以下リンクからご覧いただけます。 youtu.be youtu.be テックブログらしく技術ネタを一つ。写真のモザイクは YOLOv8-face を使った自作 Python スクリプトで自動処理しています。Haar Cascade ではなく Transformer ベースの最新モデルを採用し、高精度に顔を検出して OpenCV でモザイクを適用。 プライバシー保護もモダンな AI 技術で解決 しています。 新製品 EDGEPLANT R1 ―片手サイズエッジコンピュータ 特徴 機能 概要 通信一体型 LTE / GNSS / Wi-Fi(オプション) をオンボード 計測 I/O CAN 2 ch・アナログ 4 ch・USB × 3・IMU (416 Hz) 車載適合 −20 ~ +65 °C・耐振動 / 耐衝撃・CAN ウェイク対応 OS Terminal System OS 2+intdash SDK 筐体 84 × 95 × 28 mm・285 g(片手サイズ) 詳細はプレスリリースをご覧ください。 www.aptpod.co.jp ユースケース 二輪走行テスト — シート下やカウル内に収まるサイズ&軽量で操縦安定性評価に最適 搬送ロボ/AGV 監視 — 小型モビリティへの搭載性に優れ、遠隔テレメトリが容易 ユーザー車両フリート調査 — 目立たない場所に設置でき、市場品質データを長期取得 EDGEPLANT CAN FD USB Interface — 高速起動CANロガー 特徴 機能 概要 CAN / CAN FD 2 ch データレート ~ 8 Mbps 高速ブート 電源投入後すぐにロギング開始(SD 40 GB) 自己給電 USB / 外部 9–36 V。イグニッション連動&低スタンバイ電流 筐体 57 × 64 × 24 mm・約110 g(従来比 −30 %) 詳細はプレスリリースをご覧ください。 www.aptpod.co.jp ユースケース ECU 起動シーケンス検証 — イグニッション直後の CAN FD を取りこぼしゼロで取得 短サイクル配送車の運行ログ — STOP&GO 数分でもロギング欠落なし EV 常時電源ログ — イグニッション OFF 中も CAN 通信を検知・記録 ご要望をお寄せください 開発中機能の優先順位はユーザーの声を基に決定しています。ぜひお気軽にフィードバックをお寄せください! 関連ブースのご紹介 共和電業様 KYOWA CLOUD STREAM 共和電業様のブースでは、多チャネルロガー CTRS‑100 シリーズ と intdash を連携したクラウド計測サービス KYOWA CLOUD STREAM を展示。センサデータをリアルタイムでクラウド可視化し、取得データは MF4 形式で自動エクスポートできるため、後段の FFT など二次解析ツールへスムーズに受け渡せます。現場とオフィスをシームレスにし、業務効率を大幅に向上させます。 共和電業様ブース KYOWA CLOUD STREAM kyowacloud.kyowa-ei.com IMV様コネクタ評価試験 IMV様のブースでは、長期連続運転を想定した耐久試験業務の一つである「コネクタ評価試験」における intdash 活用デモをご紹介いただきました。振動と通電ストレスを同時に与えながら、接触抵抗・電圧降下・温度・加速度 をリアルタイムで送信し、試験中のグラフ化や異常監視を自動化。これにより、自動車や航空宇宙分野で求められる高度な品質試験において、データ収集・管理の負荷を大幅に軽減し、試験設備の稼働率向上が期待できます。 IMV様ブース まとめ 「片手サイズ × 高速起動」 の EDGEPLANT 新製品は、車載開発の “あと少し足りない” を埋める存在になると実感。 共和電業様・IMV 様の共同デモでは intdash のクラウドネイティブ計測 が試験現場の省力化に寄与できることを再確認しました。 会期 3 日間で 450 枚超 の名刺/バーコードを頂戴し、具体的な PoC ご相談も多数。ご来場ありがとうございました! デモ機貸与・PoC のお申し込みはこちら↓ www.aptpod.co.jp 製品に関するお問い合わせはこちら↓ www.aptpod.co.jp
intdashグループの落合です。普段はIoTデバイス側の製品開発を担当しています。 弊社が アプライアンス 製品として提供しているゲートウェイデバイスには、独自のLinuxディストリビューションである intdash Terminal System [1] (以降、Terminal System OSと呼びます)が搭載されており、 Mender を利用したOTAアップデート機能を備えています。 一方、お客様から intdash Edge Agent 2 [2] を個別インストールした場合でも同じようにOTAアップデートを行いたいという要望をいただくことがあります。 本記事では、個別インストールしたintdash Edge Agent 2をアップデートするために使えるOTAソリューションを選定し、どのようにリモートからアップデートできるか、実際の実装例も含めて解説していきます。 正確には intdash Terminal System 2 OSといいます。このOSは、Yocto Projectをベースに開発された独自のLinuxディストリビューションで、ゲートウェイデバイスに搭載されています。​Menderを利用したOTAアップデート機能を備え、電源を入れるだけでintdashに接続し、データ送受信が行えます。 ゲートウェイデバイスからintdashサーバーへ時系列データを送受信するソフトウェアです。​ゲートウェイデバイスにインストールすることで、センサーやカメラから取得したデータをクラウドにアップロードし、遠隔監視や制御を可能にします。 組み込みデバイスのOTAソリューション比較 intdash Edge Agent 2 の OTAに適したソリューション選定 OTAアップデート機能の実現方法 準備: Raspberry Pi に intdash Edge Agent 2をインストールする 実装例:AWS IoT Device Management 編 ステップ1: Thing の作成とAWS IoT Device Client の設定 ステップ2 : AWS IoT Job の作成と送信 ③ OTAアップデート用のJobの作成 実装例:Mender 編 ステップ1: Hosted Menderアカウントの作成と mender-client のインストール ステップ2 : Mender Artifact の作成とデプロイ ④ Mender Artifactの作成と登録 ⑤ アプリケーションアップデート まとめ 付録:AWS IoT Device Management編 ステップ1: Thing の作成と AWS IoT Device Client の設定 ① AWS IoT CoreでThingを作成する ② AWS IoT Device Clientのインストール 付録:Mender編 ステップ1: Hosted Menderアカウントの作成と mender-client のインストール ① hosted Mender accountの作成 ② Mender Clientのインストール ③ hosted Menderでの認証 組み込みデバイスのOTAソリューション比較 OTAソリューションには、OSレベルでのアップデートが可能なものと、OS上のミドルウェア/ソフトウェアのアップデートのみが可能なものがあります。 ソリューション OSアップデート ソフトウェアアップデート ライセンス/コスト AWS IoT Device Management △ ※ FreeRTOSがインストールされたデバイスのみが対象 ○ ※ 所定のソフトウェア(AWS IoT SDK)がインストールされたデバイス 従量課金制 Mender ○ ※ Yocto Project等で必要要件を満たしてビルドされたLinux OSが対象 ○ ※ 所定のソフトウェア(mender-client)がインストールされたデバイス 商用版:有償 OSS版:無償(機能制限あり) RAUC ○ ※ Yocto Project等で必要要件を満たしてビルドされたLinux OSが対象 △ ※ Yocto Project等でビルドされたLinux OS上であれば可能 オープンソース:無償 SWUpdate ○ ※ Yocto Project等で必要要件を満たしてビルドされたLinux OSが対象 △ ※ Yocto Project等でビルドされたLinux OS上であれば可能 オープンソース:無償 Balena × △ ※ BalenaOSがインストールされたデバイスが対象 商用版:有償 開発用:無償(台数制限あり) 比較表を見ると、ソフトウェアアップデートする場合については、RAUC や SWUpdate、Balena のように専用のOSを必要とするものと、AWS IoT Device Management や Mender のように、クライアントソフトウェアをインストールすればよいだけのものとに分かれることが分かります。 ちなみに、前述の Terminal System OS の場合は、Yocto Project によるカーネルレベルでのカスタマイズを行っていたことと、コンテナ技術によるアプリケーションのデプロイにも対応させたかったことからMenderでのOSアップデートを採用しています。以下の記事にて詳しく解説されていますので、よろしければご覧ください。 tech.aptpod.co.jp intdash Edge Agent 2 の OTAに適したソリューション選定 intdash Edge Agent 2を個別にインストールする場合、既存のOSに追加でインストールするケースがほとんどです。 このため、選定基準として次の点を重視しました: 既存OSに手を加えずに導入できること クライアントソフトウェアのインストールのみで利用できること これらの基準から、AWS IoT Device ManagementとMenderが候補として残りました。どちらも既存OSに必要なソフトウェアをインストールするだけで、アップデートが実現可能です。 以降では、この2つのソリューションについて、実現方法を検討していきます。 OTAアップデート機能の実現方法 intdash Edge Agent 2は、専用の公開リポジトリを登録することで、aptコマンドによってインストール・アップデートをすることができます。よって、OTAアップデートの際にも、OTAソリューションによって apt コマンドを実行することさえできれば、実際のアップデート自体は aptコマンドがよしなにやってくれることになります。 OTAソリューションとaptコマンドの役割分担を整理すると、以下のようになります。 ソリューション / プログラム 役割 OTAソリューション 遠隔からのユーザーの指示に従いaptコマンドを実行 Apt リポジトリからパッケージをダウンロードしてアップデート AWS IoT Device ManagementではJob機能を使用して、Menderではアプリケーションアップデート機能を使用して、それぞれリモートからコマンドを実行できます。 準備: Raspberry Pi に intdash Edge Agent 2をインストールする 今回はRaspberry Pi 4B に Ubuntu 22.04 LTS(Raspberry Pi Generic preinstalled server image)をインストールしたデバイスを用いて、AWS IoT Device Management と Mender における具体的なOTAアップデートの実現方法を確認していきます。 intdash Edge Agent 2をaptコマンドでインストールするには、公開リポジトリの登録が必要です。登録した後に古いバージョンの intdash Edge Agent 2もバージョン指定でインストールしておきます。 $ sudo apt-get update $ sudo apt-get install -y \ apt-transport-https \ ca-certificates \ curl \ gnupg-agent $ sudo mkdir -p /etc/apt/keyrings $ curl -fsSL https://repository.aptpod.jp/intdash-edge/linux/ubuntu/gpg | \ sudo gpg --dearmor -o /etc/apt/keyrings/intdash-edge.gpg $ echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/intdash-edge.gpg] \ https://repository.aptpod.jp/intdash-edge/linux/ubuntu \ jammy \ stable" \ | sudo tee /etc/apt/sources.list.d/intdash-edge.list $ sudo apt-get update $ sudo apt-get install --no-install-recommends -y intdash-edge-agent2=1.2.0 インストールされている、バージョンも確認しておきます。 $ apt list -a --installed intdash-edge-agent2 Listing... Done intdash-edge-agent2/unknown 1.3.0 arm64 [upgradable from: 1.2.0] intdash-edge-agent2/unknown 1.2.3 arm64 intdash-edge-agent2/unknown 1.2.1 arm64 intdash-edge-agent2/unknown,now 1.2.0 arm64 [installed,upgradable to: 1.3.0] intdash-edge-agent2/unknown 1.1.5 arm64 intdash-edge-agent2/unknown 1.1.4 arm64 intdash-edge-agent2/unknown 1.1.2 arm64 intdash-edge-agent2/unknown 1.1.1 arm64 intdash-edge-agent2/unknown 1.1.0 arm64 intdash-edge-agent2/unknown 1.0.9 arm64 intdash-edge-agent2/unknown 1.0.8 arm64 intdash-edge-agent2/unknown 1.0.7 arm64 intdash-edge-agent2/unknown 1.0.6 arm64 intdash-edge-agent2/unknown 1.0.5 arm64 intdash-edge-agent2/unknown 1.0.4 arm64 intdash-edge-agent2/unknown 1.0.3 arm64 インストールされたバージョンは 1.2.0 になっていて、最新のアップデートは 1.3.0 、 1.2.0 に対するパッチアップデートでは 1.2.3 が存在することが分かります。 ちなみに、以下のように設定をしておくことで、インストールされるバージョンを固定することができます。 $ cat << EOF | sudo tee /etc/apt/preferences.d/intdash-edge-agent2.pref Package: intdash-edge-agent2 Pin: version 1.2.* Pin-Priority: 999 EOF この設定ファイルでは、インストールされるバージョンを 1.2.x系のパッチバージョンに限定しています。 実装例:AWS IoT Device Management 編 今回やりたいことに適したドキュメントが こちら にあるので、これを参考にしました。概要をまとめると以下のようになります。 ステップ1: Thing の作成と AWS IoT Device Client の設定 ① AWS IoT CoreでThingを作成する ② AWS IoT Device Clientのインストール ステップ2 : AWS IoT Job の作成と送信 ③ OTAアップデート用のJobの作成 ステップ1: Thing の作成とAWS IoT Device Client の設定 ステップ1に関しては、本編上に記載すると煩雑になりすぎるため、巻末に付録として添付しました。詳細な手順を知りたい方は、リンク先の巻末を御覧ください。 ステップ2 : AWS IoT Job の作成と送信 ③ OTAアップデート用のJobの作成 AWS IoT Job を作成することで、アップデートを行いましょう。 準備編 でAptの設定が事前に完了しているため、以下のコマンドを実行すると、「特定のマイナーバージョンに対してパッチバージョンの更新のみ行う」作業が実行されます。 $ apt-get install -y intdash-edge-agent2 このため、アップデートをするには、テンプレートの AWS-Install-Application を使用すれば問題ありません。 AWS IoT CoreのコンソールでJobを作成する手順は以下の通りです。 左側メニューから Manage > Remote actions > Jobs を選択し、 Create job をクリックします。 Create custom job を選択し、 Next をクリックします。 Name に名前(ここでは Update_intdashEdgeAgent2 )を入力し、 Next をクリックします。 Things to run this job に対象のThing(ここでは UpdateTestPilot )を選択し、 Job document は From template を選択し、 Template type に AWS managed templates を選択し、 Template に AWS-Install-Application を選択し、 packages にアップデートするパッケージ名(ここでは intdash-edge-agent2 )を入力し、 runAsUser に root を入力し、 Next をクリックします。 Job run typeにSnapshot を選択し、 Submit をクリックします。 Jobが完了するまで待ちます。 完了したので、Raspberry Pi 側でログを確認してみます。 $ journalctl -u aws-iot-device-client -f Jun 24 03:01:07 update-test-pilot aws-iot-device-client[7133]: 2024-06-24T03:01:07.772Z [ERROR] {8435}: debconf: falling back to frontend: Readline Jun 24 03:01:07 update-test-pilot aws-iot-device-client[7133]: 2024-06-24T03:01:07.772Z [ERROR] {8435}: debconf: unable to initialize frontend: Readline Jun 24 03:01:07 update-test-pilot aws-iot-device-client[7133]: 2024-06-24T03:01:07.772Z [ERROR] {8435}: debconf: (This frontend requires a controlling tty.) Jun 24 03:01:07 update-test-pilot aws-iot-device-client[7133]: 2024-06-24T03:01:07.772Z [ERROR] {8435}: debconf: falling back to frontend: Teletype Jun 24 03:01:07 update-test-pilot aws-iot-device-client[7133]: 2024-06-24T03:01:07.772Z [ERROR] {8435}: dpkg-preconfigure: unable to re-open stdin: Jun 24 03:01:07 update-test-pilot aws-iot-device-client[7133]: 2024-06-24T03:01:07.772Z [WARN] {JobEngine.cpp}: While executing action Install-Application, JobEngine reported receiving errors from STDERR Jun 24 03:01:07 update-test-pilot aws-iot-device-client[7133]: 2024-06-24T03:01:07.772Z [INFO] {JobsFeature.cpp}: Job exited with status: 0 Jun 24 03:01:07 update-test-pilot aws-iot-device-client[7133]: 2024-06-24T03:01:07.772Z [WARN] {JobsFeature.cpp}: JobEngine reported receiving errors from STDERR Jun 24 03:01:07 update-test-pilot aws-iot-device-client[7133]: 2024-06-24T03:01:07.772Z [INFO] {JobsFeature.cpp}: Job executed successfully! Jun 24 03:01:08 update-test-pilot aws-iot-device-client[7133]: 2024-06-24T03:01:08.195Z [INFO] {JobsFeature.cpp}: No pending jobs are scheduled, waiting for the next incoming job Install-Application が status: 0 で終了しているため、成功したようです。 現在のパッケージバージョンを確認してみます。 $ apt list --installed intdash-edge-agent2 Listing... Done intdash-edge-agent2/unknown,now 1.2.3 arm64 [installed] N: There are 14 additional versions. Please use the '-a' switch to see them. ✅ 期待通りに、マイナーバージョンは変わらずに、パッチバージョンの更新がされました! 実装例:Mender 編 Menderを使用して、アプリケーションのアップデートを行う方法は、 こちら に記載されているように、 Mender Clientがインストールされたイメージ を使用することもできますが、本記事の趣旨に沿って、今回は 準備編 で構築済みのRaspberry Piに対して、追加でmender-clientをインストールしてみます。 手順をまとめると以下のようになります。 ステップ1: Hosted Menderアカウントの作成と mender-client のインストール ① hosted Mender accountの作成 ② Mender Clientのインストール ③ hosted Menderでの認証 ステップ2 : Mender Artifact の作成とデプロイ ④ Mender Artifactの作成と登録 ⑤ アプリケーションアップデート ステップ1: Hosted Menderアカウントの作成と mender-client のインストール ステップ1に関しては、本編上に記載すると煩雑になりすぎるため、巻末に付録として添付しました。詳細な手順を知りたい方は、リンク先の巻末を御覧ください。 ステップ2 : Mender Artifact の作成とデプロイ ④ Mender Artifactの作成と登録 アプリケーションアップデートのために必要なMender Artifactの作成をして、アップデートを行なってみましょう。 準備編 でAptの設定が事前に完了しているため、以下のコマンドを実行すると、「特定のマイナーバージョンに対してパッチバージョンの更新のみ行う」作業が実行されます。 $ apt-get install -y intdash-edge-agent2 このため、上記コマンドを実行するMender Artifactを作成すれば問題ありません。 Mender Artifact は、 ファイルフォーマット に準拠して作成する必要があります。ただし、今回はスクリプトを実行するだけなので、 mender-clientのインストール によって使用できるようになる scriptアップデートモジュール を利用することで簡単に作ることができます。 作成に必要なmender-artifactツールはdockerイメージが提供されているため、そちらを使用して以下のコマンドで作成します。 まず、アップデートを行うコマンドを実行するスクリプトを記載します。 $ cat > update-script.sh << EOF #!/bin/bash apt-get install -y intdash-edge-agent2 EOF 次にdockerでmender-artifactを実行します。 $ docker run -v $(pwd):/work -w /work \ --rm mendersoftware/mender-ci-tools:1.0.0 \ mender-artifact write module-image -T script \ -n intdash-edge-agent2-update-1.0 \ -t raspberrypi4 \ -o intdash-edge-agent2-update-1.0.mender \ -f update-script.sh ホストのカレントディレクトリに intdash-edge-agent2-update-1.0.mender というファイルが出来上がっているので、これでMender Artifactは完成です。 次に intdash-edge-agent2-update-1.0.mender を hosted Mender に登録します。手順は以下の通りです。 hosted Mender にログインし、 RELEASES をクリックし、 UPLOAD をクリックします。 アップロードするファイル intdash-edge-agent2-update-1.0.mender のファイルを選択します。 UPLOAD ARTIFACT をクリックします。 ⑤ アプリケーションアップデート 作成したMender ArtifactをRaspberry Piにデプロイしてアップデートをしてみます。手順は以下の通りです。 hosted Mender にログインし、 DEVICES > All devices をクリックし、 Status: accepted で認証済みのデバイスをフィルターします。対象のデバイスにチェックを入れ、右下の + ボタンをクリックします。 表示されたメニュから Create deployment for this device をクリックします。 Select a Release to deploy に intdash-edge-agent2-update-1.0 を選択し、 CREATE DEPLOYMENT をクリックします。 deploymentが完了するまで待ちます。 deploymentが完了すると、 DEPLOYMENTS > Finished の中にリストされます。 成功しているようです。 詳細を確認すると以下のようになっています。 Raspberry Piにログインして、現在のパッケージバージョンを確認してみます。 $ apt list --installed intdash-edge-agent2 Listing... Done intdash-edge-agent2/unknown,now 1.2.3 arm64 [installed] N: There are 14 additional versions. Please use the '-a' switch to see them. ✅ 期待通りに、マイナーバージョンは変わらずに、パッチバージョンの更新がされました! まとめ OTAソリューションとして使える、AWS IoT Device Management、Mender、RAUC、SWUpdate、Balenaを比較し、シンプルなOTAアップデートのシナリオをAWS IoT Device ManagementとMenderで試してみました。 今回のようにソフトウェアアップデートだけを考えると、AWS IoT Device ManagementはJobのテンプレートが準備されているため、学習コストや手間が少なと導入しやすかったです。ですが、将来的にOSのアップデートも視野に入れるのであればMenderを選択するケースもあると思います。 OTAアップデートを検討中の方にとって、この記事が参考になったら幸いです! 付録:AWS IoT Device Management編 ステップ1: Thing の作成と AWS IoT Device Client の設定 ① AWS IoT CoreでThingを作成する ⚠️ 「 ② AWS IoT Device Clientのインストール 」の作業にあるビルドが約20分かかります。まずはそちらを先に進めていただいてから、この作業をする方が効率的かもしれません。 AWSマネジメントコンソールからIoT Coreを開きます。 左側メニューから Manage > All devices > Things を選び Create things をクリックします。 Create Single Thing を選び Next をクリックします。 Thing name に名前(ここでは UpdateTestPilot )を入力しNextをクリックします。 Auto-generate a new certificate (recommended) を選択し Next をクリックします。 Create plicy をクリックします。 Policy name に名前(ここでは AllActions )を入力して、 Policy action に * を選択し、 Policy resource に * を選択し、 Create をクリックします。 ☑️ AWS IoT Core での Thing と Certificates と Policy の関係性は以下の図のように、Policyは直接Thingに紐付いている訳ではなく、Certificatesを経由して紐付いています。 +--------------+ +---------------+ +---------------+ | Thing | 1----1..* | Certificate | 1----0..* | Policy | +--------------+ +---------------+ +---------------+ `- アクティブなCertificateは1つだけ Policies の画面は閉じて Create single thing の画面に戻り、作成したポリシーを有効にして Create thing をクリックします。 証明書と鍵のダウンロードのためのダイアログが出るので、ファイル全てをダウンロードして Done をクリックします。 ダウンロードした証明書や鍵はデバイス側で使うので、Raspberry Piにコピーし、PCからは削除しておきます。 ② AWS IoT Device Clientのインストール AWS IoT Device Client の GitHub リポジトリ にREADMEがあるので、そちらの手順に従いインストールしてみます。 まずは、Raspberry Pi の Ubuntu にログインし、必要なパッケージをインストールします。 $ sudo apt install build-essential cmake git libssl-dev 使用するAWS IoT Device Clientのソースは v1.9.2 にします。 $ git clone -b v1.9.2 https://github.com/awslabs/aws-iot-device-client プロジェクトディレクトリ内に移動します。 $ cd aws-iot-device-client ソースをそのままビルドすると、ワーニングが出る箇所があり、ビルドエラーとして扱わられるようになっているためビルドできないので、対象のワーニングは許容するパッチをあてます。 $ sed -i -e 's/target_compile_options(${DC_PROJECT_NAME} PRIVATE -Wall -Wno-long-long -pedantic -Werror)/target_compile_options(${DC_PROJECT_NAME} PRIVATE -Wall -Wno-long-long -pedantic -Werror -Wno-error=ignored-attributes)/' CMakeLists.txt ビルドします。 ⚠️ 今回の環境では20分程度かかります。 $ bash << BUILD_SCRIPT #!/usr/bin/env bash set -e mkdir build cd build cmake ../ cmake --build . --target aws-iot-device-client BUILD_SCRIPT 次にセットアップのための準備を行います。 セットアップでは以下の情報が必要になります。 AWS IoT endpoint 作成済みの証明書など一式 各ファイルのパーミッションはAWS IoT Device Clientの期待にあったパーミッションになっている必要がある そのため、まず AWS IoT endpoint を以下のAWS CLIを実行して取得します。AWS CLIの認証情報は IoT Coreにアクセスできる認証情報を使用して実行してください。 aws iot describe-endpoint --endpoint-type iot:Data-ATS 証明書など一式はディレクトリに移動し、適したパーミッションに変更をします。 sudo install -m 0700 -d /root/certs sudo mv ~/*-certificate.pem.crt ~/*-private.pem.key ~/*-public.pem.key ~/AmazonRootCA?.pem /root/certs/ sudo find /root/certs/ -type f -exec chown root:root {} \; sudo find /root/certs/ -type f -exec chmod 0644 {} \; sudo find /root/certs/ -type f -name "*-private.pem.key" -exec chmod 0600 {} \; 準備した情報を用いてセットアップを行うために、setup.shを実行します。 $ sudo ./setup.sh WARNING: Only run this setup script as root if you plan to run the AWS IoT Device Client as root, or if you plan to run the AWS IoT Device Client as a service. Otherwise, you should run this script as the user that will execute the client. Do you want to interactively generate a configuration file for the AWS IoT Device Client? y/n y Specify AWS IoT endpoint to use: あらかじめ取得したAWS IoT endpoint。 e.g. xxxxxxxx-ats.iot.ap-northeast-1.amazonaws.com Specify path to public PEM certificate: /root/certs/*.pem.crt Specify path to private key: /root/certs/*-private.pem.key Specify path to ROOT CA certificate: /root/certs/*.pem Specify thing name (Also used as Client ID): UpdateTestPilot Would you like to configure the logger? y/n y Specify desired log level: DEBUG/INFO/WARN/ERROR INFO Specify log type: STDOUT for standard output, FILE for file STDOUT Specify path to desired log file (if no path is provided, will default to /var/log/aws-iot-device-client/aws-iot-device-client.log: Creating default log directory... Would you like to configure the SDK logging? y/n n Enable Jobs feature? y/n y Specify absolute path to Job handler directory (if no path is provided, will default to /etc/.aws-iot-device-client/jobs): Enable Secure Tunneling feature? y/n y Enable Device Defender feature? y/n y Specify an interval for Device Defender in seconds (default is 300): Enable Fleet Provisioning feature? y/n n Enable Pub Sub sample feature? y/n n Enable Config Shadow feature? y/n n Enable Sample Shadow feature? y/n n { "endpoint": "xxxxxxxx-ats.iot.ap-northeast-1.amazonaws.com", "cert": "/root/certs/*.pem.crt", "key": "/root/certs/*-private.pem.key", "root-ca": "/root/certs/*.pem", "thing-name": "UpdateTestPilot", "logging": { "level": "INFO", "type": "", "file": "/var/log/aws-iot-device-client/aws-iot-device-client.log", "enable-sdk-logging": false, "sdk-log-level": "TRACE", "sdk-log-file": "/var/log/aws-iot-device-client/sdk.log" }, "jobs": { "enabled": true, "handler-directory": "/etc/.aws-iot-device-client/jobs" }, "tunneling": { "enabled": true }, "device-defender": { "enabled": true, "interval": 300 }, "fleet-provisioning": { "enabled": false, "template-name": "", "template-parameters": "", "csr-file": "", "device-key": "" }, "samples": { "pub-sub": { "enabled": false, "publish-topic": "", "publish-file": "/etc/.aws-iot-device-client/pubsub/publish-file.txt", "subscribe-topic": "", "subscribe-file": "/etc/.aws-iot-device-client/pubsub/subscribe-file.txt" } }, "config-shadow": { "enabled": false }, "sample-shadow": { "enabled": false, "shadow-name": "", "shadow-input-file": "", "shadow-output-file": "" } } Does the following configuration appear correct? If yes, configuration will be written to /etc/.aws-iot-device-client/aws-iot-device-client.conf: y/n y Configuration has been successfully written to /etc/.aws-iot-device-client/aws-iot-device-client.conf Creating default pubsub directory... Do you want to copy the sample job handlers to the specified handler directory (/etc/.aws-iot-device-client/jobs)? y/n y Do you want to install AWS IoT Device Client as a service? y/n y Enter the complete directory path for the aws-iot-device-client. (Empty for default: ./build/aws-iot-device-client) Enter the complete directory path for the aws-iot-device-client service file. (Empty for default: ./setup/aws-iot-device-client.service) Do you want to run the AWS IoT Device Client service via Valgrind for debugging? y/n n Installing AWS IoT Device Client... /usr/bin/systemctl Created symlink /etc/systemd/system/multi-user.target.wants/aws-iot-device-client.service → /etc/systemd/system/aws-iot-device-client.service. ● aws-iot-device-client.service - AWS IoT Device Client Loaded: loaded (/etc/systemd/system/aws-iot-device-client.service; enabled; preset: enabled) Active: active (running) since Sat 2024-06-22 06:34:09 UTC; 69ms ago Main PID: 41844 (aws-iot-device-) Tasks: 1 (limit: 3864) Memory: 844.0K (peak: 1.5M) CPU: 38ms CGroup: /system.slice/aws-iot-device-client.service └─41844 /sbin/aws-iot-device-client --config-file /etc/.aws-iot-device-client/aws-iot-device-client.conf Jun 22 06:34:09 mptcp-proxy systemd[1]: Started aws-iot-device-client.service - AWS IoT Device Client. q AWS IoT Device Client is now running! Check /var/log/aws-iot-device-client/aws-iot-device-client.log for log output. 付録:Mender編 ステップ1: Hosted Menderアカウントの作成と mender-client のインストール ① hosted Mender accountの作成 アカウントがない場合は hosted Menderにサインアップ します。 ② Mender Clientのインストール こちら の手順に従ってインストールの準備をします。 $ sudo apt-get update $ sudo apt-get install --assume-yes \ apt-transport-https \ ca-certificates \ curl \ gnupg-agent \ software-properties-common $ curl -fsSL https://downloads.mender.io/repos/debian/gpg | sudo tee /etc/apt/trusted.gpg.d/mender.asc $ gpg --show-keys --with-fingerprint /etc/apt/trusted.gpg.d/mender.asc $ echo "deb [arch=$(dpkg --print-architecture)] https://downloads.mender.io/repos/debian ubuntu/jammy/stable main" \ | sudo tee /etc/apt/sources.list.d/mender.list > /dev/null $ sudo apt-get update インストーラーを起動 $ sudo apt-get install mender-client4 インストーラーを起動するとコンソールに以下のように、hosted Menderに接続するための情報を訪ねられるので、入力していきます。 Mender Client Setup =================== Setting up the Mender client: The client will regularly poll the server to check for updates and report its inventory data. Get started by first configuring the device type and settings for communicating with the server. The device type property is used to determine which Mender Artifact are compatible with this device. Enter a name for the device type (e.g. raspberrypi3): [update-test-pilot] raspberrypi4 Are you connecting this device to hosted.mender.io? [Y/n] Y Enter your credentials for hosted.mender.io Email: あらかじめMenderサーバーに登録しておいたEメール Password: あらかじめMenderサーバーに登録しておいたパスワード Demo intervals uses short poll and retry intervals (Recommended for testing.) Do you want to run the client in demo mode? [Y/n] Y Mender setup successfully. ③ hosted Menderでの認証 Menderでの認証方法には さまざまな方法 がありますが、ここでは Authorize-on-request Flow で認証します。 hosted Mender にログインし、 DEVICES > All devices をクリックし、 Status: pending で認証待ちのデバイスをフィルターします。対象のデバイスのMACアドレスが表示されているのでこのデバイスをクリックします。 Accept をクリックして認証します。
既存の計測データをアップストリームしたいみなさん、 こんにちは。ソリューションアーキテクトの伊勢です。 システム開発の現場では、一度取得した計測データを再利用して送信したい場面があります。 今回はintdashの計測データを "リプレイ" する方法をご紹介します。 はじめに 再び、intdash API/SDKとは チャンク転送エンコーディング List Data Points のレスポンス確認 やってみた インストール 全体構成 対象計測 リプレイ開始 起動オプション データ取得元オプション データ送信先オプション 再生オプション サンプルプログラム説明 データポイント取得 時刻変換 再生スピード調整 メモリ使用量表示 サンプルプログラム修正 エクスポート インポート おわりに リンク はじめに 開発中にエッジの載っているモビリティをいつでも自由に動かせるとは限りません。 他の作業と利用が重なる 計測には複数名体制の準備が必要 利用施設の申請が必要 偶然得られたデータが再現できない また、本番データを検証環境でデバッグしたいケースもあります。 そんなときに、取り溜めた計測データを手軽にリアルタイム送信できれば、開発効率が高まります。 再び、intdash API/SDKとは 本シリーズではこれまで、intdash APIを REST API と リアルタイムAPI に分けて説明してきました。 このうち、REST APIは一般的なHTTPリクエスト・レスポンス形式の通信方式です。 intdash SDK REST APIで唯一、大容量データ取得に特化した List Data Points エンドポイントは、チャンク転送エンコーディングをサポートしています。 これは、大きなデータを効率よく転送し、クライアント側のメモリ消費を抑えるための設計です。 List Data Pontsエンドポイントのレスポンス定義 チャンク転送エンコーディング サーバーがコンテンツの全体のサイズを事前に決定できない場合や、大容量データ転送の効率化に使用されるデータ転送方式です。 通常、HTTPレスポンスの Content-Length ヘッダには、クライアントが受信すべきデータの総バイト数が記載されます。 しかし、動的に生成されるコンテンツや巨大データのようにデータサイズが事前に不明な場合、 Content-Length を指定するのが難しくなります。 そこで Transfer-Encoding: chunked ヘッダを指定して、データをチャンク(塊)に分けて順次送信する方式が使われます。 これには以下の利点があります。 サーバーは全データを用意する前にレスポンスを開始できる クライアントはメモリを節約しつつデータを逐次処理できる この方式は、ストリーミングや大容量データのダウンロードに適しています。 1 List Data Points のレスポンス確認 レスポンスヘッダを確認してみます。 curlコマンドで List Data Points エンドポイントを叩きます。 HTTP1.1を明示的に指定しています。 2 export API_URL = < YOUR_API_URL > export API_TOKEN = < YOUR_API_TOKEN > export PROJECT_UUID = < YOUR_PROJECT_UUID > export MEAS_UUID = < YOUR_MEAS_UUID > curl -I -X GET " ${API_URL} /api/v1/projects/ ${PROJECT_UUID} /data?name= ${MEAS_UUID} " -H " X-Intdash-Token: ${API_TOKEN} " --http1.1 レスポンスヘッダに Transfer-Encoding: chunked が含まれていることが確認できます。 List Data PointsのHTTPレスポンス 一方、他のエンドポイントでは Content-Length が使用されています。 curl -I -X GET " ${API_URL} /api/v1/projects/ ${PROJECT_UUID} /measurements/ ${MEAS_UUID} " -H " X-Intdash-Token: ${API_TOKEN} " --http1.1 List Data Points以外のHTTPレスポンス 今回紹介するサンプルプログラム 3 では、このチャンク転送エンコーディングを活用して、大容量の計測データ取得時にメモリを節約します。 やってみた インストール SDK入門③ まででインストールしたパッケージを利用します。 加えて、メモリ使用量を表示するため、システム監視ライブラリを導入します。 pip install psutil 全体構成 A環境に保存された計測データをB環境に再度アップストリームします。 全体構成図 対象計測 データ収集に労力のかかる例として長時間の計測を使います。 荷物搬送のためカーフェリー移動した北海道出張 さんふらわあ しれとこ は2025年に引退が決まっているベテラン船で、客室はすべて年季が入ったベット4つの相部屋です。 www.sunflower.co.jp 当社製 EDGEPLANT T1 でGPSデータを収集しました。 客室ベッドでT1と添い寝 茨城県大洗港〜北海道苫小牧港は約302海里 乗船〜下船の20時間26分32秒 リプレイ開始 20時間超の計測を等倍で再生するのは辛いので早送りします。 再生スピード調整機能を使って60倍速でアップストリームします。 起動すると、A環境からREST APIからの計測データ取得と、B環境へのアップストリームが始まります。 リプレイ開始 VM2M Data Visualizer のLIVE再生で位置情報が60倍速で更新されていきます。 津軽海峡冬景色 Edge Finderでリアルタイムデータを確認 再生が完了すると、ちょうど時間が1/60の計測が作成されています。 20分26秒に短縮 起動オプション 今回は、データ取得元を計測UUIDで指定して、別サーバー環境に、再生スピード指定でアップストリームしました。 他にも以下のオプションがあります。 データ取得元オプション 取得元の時間範囲として、計測、またはエッジ・開始時刻・終了時刻を指定します。 --api_url requried :サーバーURL --api_token requried : APIトークン --project_uuid :プロジェクト、省略時はGlobal Project いずれか requried 計測指定: --meas_uuid :計測 エッジ指定: --edge_uuid :エッジ --start :開始時刻、RFC3339形式 --end :終了時刻、RFC3339形式 --data_id_filter :データIDフィルター、カンマ区切りで複数指定 <データ型名>:<データ名>, <データ型名>:<データ名>, ... データ送信先オプション プロジェクト以外は、省略時はデータ取得元と同じになります。 --dst_api_url :サーバーURL --dst_api_token : APIトークン --dst_project_uuid :プロジェクト、省略時はGlobal Project --dst_edge_uuid :エッジ 再生オプション --speed :再生スピード、省略時は等倍(1.0) サンプルプログラム説明 APIアクセス部分を中心に説明します。 クラスアーキテクチャ 2つの処理を非同期で実行しています。 Feed:REST APIから受け取ったデータポイントをキューに登録します。 メモリ消費量を抑えるため、キューが一杯だったら、空くまで待機します。 Fetch:キューからデータポイントを取り出して、アップストリームします。 元の計測と同じ頻度でデータ送信するため、経過時間分スリープします。 再生スピードを指定すると スリープ時間をその分調整します。 データポイント取得 メモリ消費低減のため、 _preload_content を False にして随時読み込みます。 api = measurement_service_data_points_api.MeasurementServiceDataPointsApi( self.client ) params = { "project_uuid" : self.project_uuid, "name" : self.meas_uuid if self.meas_uuid else self.edge_uuid, "time_format" : "ns" , "_preload_content" : False , # 全データロードの抑止 } if self.start: params[ "start" ] = self.start if self.end: params[ "end" ] = self.end if self.data_id_filter: params[ "data_id_filter" ] = self.data_id_filter stream = api.list_project_data_points(**params) 時刻変換 データ送信を待機するため、取得したデータポイントの絶対時刻から経過時間を算出します。 basetime_ns = int (basetime.timestamp() * 1_000_000) * 1_000 ... elapsed_time = tuple [ 0 ] - basetime_ns 再生スピード調整 算出した経過時間分スリープします。 elapsed_time_speed = int (elapsed_time / self.speed) sleep_time = ( basetime_ns + elapsed_time_speed - iscp.DateTime.utcnow().unix_nano() ) / 1_000_000_000 if sleep_time > 0 : await asyncio.sleep(sleep_time) 送信するデータポイントの経過時間は、現在時刻と新たな計測の基準時間との差分です。 elapsed_time_replay = ( iscp.DateTime.utcnow().unix_nano() - start_time.unix_nano() ) await self.upstreamer.send(elapsed_time_replay, type , name, data) メモリ使用量表示 チャンク転送エンコーディングによりメモリ消費が抑えられることを確認するため、使用量をログ表示しています。 process = psutil.Process() mem_info = process.memory_info() logging.info(f "Memory Usage: {mem_info.rss / 1024 / 1024:.2f} MB" ) メモリ使用量ログ おおよそ55MBで推移しています。 試しに _preload_content オプションを外して(デフォルト True で)実行すると、ストリーム開始まで10秒ほどかかり、600〜700MBほど消費します。 一括取得で実行 サンプルプログラム修正 本シリーズで以前、REST APIで計測データをエクスポート/インポートするサンプルプログラムを紹介しました。 tech.aptpod.co.jp こちらは、計測データ量に依存してメモリ消費が増えてしまうため、長時間計測には不向きでした。 今回、同じように _preload_content オプションを指定して、メモリ消費量を抑えるようした修正版を追加しました。 4 エクスポート List Data Pointのオプション指定を変更しました。 api = measurement_service_data_points_api.MeasurementServiceDataPointsApi(client) params = { "project_uuid" : project_uuid, "name" : meas_uuid, "time_format" : "ns" , "_preload_content" : False , } stream = api.list_project_data_points(**params) 一定量ずつ取得した計測データをバッファに取っておいて、1行ずつ順次返すように変更しました。 # バッファ格納 buffer = b "" while True : chunk = stream.read(chunk_size) if not chunk: break buffer += chunk # JSON Line切り出し while b " \n " in buffer : line, buffer = buffer .split(b " \n " , 1 ) line_json = json.loads(line.decode()) if "data" not in line_json: continue if "d" not in line_json[ "data" ]: continue yield line_json 出力ファイルがJSONだとインデント処理が煩雑になるため、JSON Linesに変更しました。 修正前フォーマット:JSON { " measurement ": <計測オブジェクト>, " basetimes ": [ <基準時刻>, <基準時刻>, .. ] , " datapoints ": [ <データポイント>, <データポイント>, .. ] } 修正後フォーマット:JSON Lines {"measurement": <計測オブジェクト>} {"basetime": <基準時刻>} {"basetime": <基準時刻>} ... {"datapoint": <データポイント>} {"datapoint": <データポイント>} ... さきほどのGPS計測をエクスポートすると以下のようになります。 修正前は1.4GBほどメモリを消費しました。 5 python lesson2/migrate/src/meas_export.py --api_url <YOUR_API_URL> --api_token <YOUR_API_TOKEN> --project_uuid <YOUR_PROJECT_UUID> --meas_uuid <YOUR_MEAS_UUID> エクスポート修正前:一括取得版 修正後は46MBほどになりました。 python lesson2/migrate/src/meas_export_mem.py --api_url <YOUR_API_URL> --api_token <YOUR_API_TOKEN> --project_uuid <YOUR_PROJECT_UUID> --meas_uuid <YOUR_MEAS_UUID> エクスポート修正後:随時取得版 インポート あわせて、JSON Linesファイルを随時読み出すようにインポートを修正しました。 with open (file_path, "r" , encoding= "utf-8" ) as f: for line in f: try : yield json.loads(line, object_hook=measurement_decoder) except json.JSONDecodeError as e: logging.warning(f "JSON decode error: {e}" ) CHUNK_SIZE ずつ送信するよう制御しています。 buffer .append(entry[ "datapoint" ]) if len ( buffer ) >= CHUNK_SIZE: sequence_number = send_chunks( client, project_uuid, measurement_obj.uuid, measurement[ "basetime" ], sequence_uuid, buffer , sequence_number, ) buffer .clear() エクスポートしたファイルのインポート結果です。 修正前は2.5GBほどメモリを消費して途中で止まりました。 python lesson2/migrate/src/meas_import.py --api_url <YOUR_API_URL> --api_token <YOUR_API_TOKEN> --project_uuid <YOUR_PROJECT_UUID> --edge_uuid <YOUR_EDGE_UUID> --src_file <YOUR_JSON_FILE> インポート修正前:一括読み出し版 修正後は50MB未満に収まりました。 python lesson2/migrate/src/meas_import_mem.py --api_url <YOUR_API_URL> --api_token <YOUR_API_TOKEN> --project_uuid <YOUR_PROJECT_UUID> --edge_uuid <YOUR_EDGE_UUID> --src_file <YOUR_JSONL_FILE> インポート修正後:随時み出し版 おわりに 今回は開発で利用できるツールの一例を紹介しました。 実データを元に繰り返し送信したり、別環境で再現できると検証の質が向上します。 このようにREST/リアルタイムAPIを組みあわせると自由度の高い制御も可能です。 リンク 本シリーズの過去記事はこちらからご覧ください。 SDK入門①〜社用車で走ったとこ全部見せます〜 :REST APIでデータ取得 SDK入門②〜データ移行ツールの作り方〜 :REST APIでデータ送信 SDK入門③〜RTSPで映像配信するぞ〜 :リアルタイムAPIでデータ取得 SDK入門④〜YOLOで物体検知しちゃう〜 :リアルタイムAPIでデータ送信 SDK入門⑤〜iPadでData Visualizerを見る会〜 :リアルタイムAPIでキャプチャデータ送信 SDK入門⑥〜最速最高度で計測する日〜 : AWS LambdaでREST APIデータ送信 同じ"ストリーミング"と呼んでいますが、チャンク転送エンコーディングとintdashのリアルタイムAPI(iSCP)は別のプロトコルです。 ↩ HTTP2以降では Transfer-Encoding は省略されうるためです。 ↩ GitHub で公開しています。 ↩ GitHub のlesson2に反映してあります。 ↩ JSONフォーマットを一時保持するメモリ消費が大半です。 ↩
intdash SDKを使って開発したプログラムを自動で実行したいみなさん、 こんにちは、ソリューションアーキテクトの伊勢です。 これまで本シリーズではプログラムをコマンドで手動起動してきましたが、検証や運用では自動で起動したい場面が多いはずです。 今回はWebhookとLambdaを組み合わせて、計測完了直後にプログラムを起動する方法を紹介します。 はじめに 全体構成 Webhookとは AWS Lambdaとは Lambdaレイヤーとは API Gatewayとは やってみた AWS構築 距離算出Lambda カスタムLambdaレイヤー作成 Lambda関数作成 レスポンス返却Lambda Lambda関数作成 API Gateway作成 Webhook設定 設定登録 設定確認 計測 計測対象 計測開始 計測完了 サンプルプログラム説明 Webhook設定ツール 一覧 取得 登録 テスト 距離算出 距離算出プログラム レスポンス返却プログラム おわりに リンク はじめに 全体構成 SDK入門② の距離算出プログラムが計測完了直後に起動されるようにします。 距離算出 計測イベントをWebhookリクエストとしてAPI Gatewayに送信します。 Webhookリクエストを受けたAPI GatewayがLambdaを起動します。 レスポンス返却Lambdaは、リクエストが計測完了のときに距離算出Lambdaを起動します。 1 距離算出Lambdaは、プログラムの完了をSlackで通知します。 Webhookとは システム内イベントをシステム外にHTTPで通知する仕組みです。 これでintdash内の変化をintdash外からリアルタイムに知ることができます。 イベントドリブンなシステム連携により、効率的なワークフローを実現できます。 tech.aptpod.co.jp 今回はよりシンプルな使い方を紹介します。 Lambda関数をインラインコードで作成 intdash SDKのLambdaレイヤーを作成 ローカルPCでテストコードによる動作確認 2 AWS Lambdaとは 言わずと知れたサーバレスでコードを実行できるコンピューティングサービスです。 aws.amazon.com 従量課金で手軽であり、作成した関数をイベントで起動できます。 今回はWebhookリクエストをAPI Gatewayで受けてLambdaを起動します。 Lambdaレイヤーとは Lambda関数の実行環境に共有ライブラリや依存ファイルを追加する仕組みです。 これにより、Lambda関数が軽量化され、コードの再利用性が向上します。 今回はintdash SDKや依存するPythonパッケージを登録します。 docs.aws.amazon.com API Gatewayとは APIエンドポイントへのアクセス仲介サービスです。 WebリクエストをバックエンドのLambdaやEC2などにルーティングします。 やってみた AWS構築 起動される側(全体構成の右側)から順に構築していきます。 距離算出Lambda カスタムLambdaレイヤー作成 Lambdaレイヤーとして登録するためのZIPファイルを作成します。 ローカルPCでLambdaレイヤーのディレクトリ構造に SDK入門① 、 SDK入門② のPython依存パッケージをインストールします。 3 mkdir -p path/to/workdir/python/lib/python3. 12 /site-packages pip3. 12 install pydantic python-dateutil urllib3 -t path/to/workdir/python/lib/python3. 12 /site-packages pip3. 12 install protobuf -t path/to/workdir/python/lib/python3. 12 /site-packages 依存パッケージインストール 以下をZIPにまとめます。 SDK入門① で生成したintdash SDKパッケージ intdash SDK入門② で生成したProtocol Buffersエンコーダー gen インストールしたPython依存パッケージ cp -r intdash gen path/to/workdir/python/lib/python3. 12 /site-packages cd path/to/workdir find . -name " *.pyc " -delete find . -name " __pycache__ " -type d -exec rm -r {} + zip -r intdash_sdk.zip python ls -l intdash_sdk.zip python LambdaレイヤーZIP作成 ZIPファイルをアップロードしてレイヤーを作成します。 Lambdaレイヤーの作成 Lambda関数作成 サンプルプログラムからLambda関数のZIPファイルを作成します。 今回のサンプルプログラムはLambdaで実行されることを想定しています。 4 cd lesson6/intdash-distance/src find . -name " *.pyc " -delete find . -name " __pycache__ " -type d -exec rm -r {} + zip -r ../deployment_package.zip . 距離算出Lambda ZIPファイル作成 Lambda関数を作成します。 作成したZIPファイルをアップロードします。 距離算出Lambda関数作成 タイムアウト設定がデフォルト3秒だと途中終了してしまうため、5分に延長します。 距離算出Lambda タイムアウト設定 プログラムに渡す環境変数を設定します。 API_TOKEN : サーバー環境にアクセスするAPIトークン API_URL : サーバー環境のURL FETCH_SIZE : データポイントを何件ずつ処理するか ORIGIN_LAT : 基準点(緯度) ORIGIN_LON : 基準点(経度) SLACK_URL : 通知先Slack 距離算出Lambda 環境変数設定 Lambdaレイヤーを追加します。 intdash SDK: 作成したカスタムLambdaレイヤー requests : 公開ARNを指定 Lambdaレイヤーの追加 レスポンス返却Lambda Lambda関数作成 intdashにレスポンスを返却するためのLambda関数を作成します。 lesson6/invoke-distance/src/lambda_function.py の内容を貼り付けます。 レスポンス返却Lambda作成 プログラムに渡す環境変数を設定します。 SECRET_KEY : あとでWebhook設定に登録する任意の文字列 レスポンス返却Lambda 環境変数設定 API Gateway作成 POSTリクエストを受けるAPI Gatewayを作成します。 レスポンス返却Lambdaと統合します。 API Gateway作成 Webhook設定 設定はintdash APIで管理され、SDKでも参照・更新メソッドが提供されます。 ラップするCLIツールも作ってみました。 このツールを使って今回使う設定を登録・確認します。 5 Webhook設定ツール 設定登録 API GatewayにWebhookリクストを送信する設定を追加します。 リクエストボディはこのようなJSONです。 6 { " url ": " https://example.execute-api.ap-northeast-1.amazonaws.com/webhook ", " secret ": " stringstringstringstringstringst ", " edges_event ": false , " measurements_event ": true , " users_event ": false , " edge_connections_event ": false , " project_edges_event ": false , " project_members_event ": false } secret にはレスポンス返却Lambdaの環境変数 SECRET_KEY を設定します。 7 計測イベントを送信するように measurements_event のみ true にします。 8 JSONファイルを src_path に指定します。 python lesson6/cli/src/hook_cli.py --api_url https://example.intdash.jp --api_token < YOUR_API_TOKEN > --project_uuid < YOUR_PROJECT_UUID > import --src_path =< YOUR_SRC_PATH > 設定確認 登録結果を一覧で確認します。 python lesson6/cli/src/hook_cli.py --api_url https://example.intdash.jp --api_token < YOUR_API_TOKEN > --project_uuid < YOUR_PROJECT_UUID > list Webhook設定登録 計測 計測対象 せっかくなので、その場でプログラムを手動実行できない環境で試しました。 iOSアプリ intdash Motion で飛行中のGPSを計測します。 福岡出張の帰路 エアバスA320 の最大巡航速度はマッハ0.82、国内線の高度はおよそ1万mです。 当社がこれまで計測した環境としては最速かつ最高度ではないかと思います。 1回の計測距離として最長かもしれません。 計測開始 iPhoneはフライトモードにしてあるため、計測がオフラインで開始されます。 オフライン計測を開始 機内Wifiが使える機体なら、リアルタイム計測も可能かもしれません。 離陸 計測完了 着陸後、Motionから計測を遅延アップロードします。 遅延アップロード 数十秒ほどでSlackに通知がありました。 Slack通知 PCからData Visualizerにリンクするとプレイバック再生が始まります。 成田空港を基準点とした算出距離が計測とあわせて表示されます。 9 最高時速1,126km、最高高度9,597m、移動距離575km サンプルプログラム説明 Webhook設定ツール 一覧 List Project Hookの結果の items 配列を返します。 return self.api.list_project_webhooks( self.project_uuid, per_page=per_page ).items 取得 List Project Hookで hook_uuid を指定しています。 10 hooks = self.api.list_project_webhooks( self.project_uuid, hook_uuid=[hook_uuid], ) return hooks.items[ 0 ] 登録 引数 hook_uuid の指定有無でCreate/Update Project Hookを使い分けます。 if hook_uuid: hook = self.api.update_project_webhook( self.project_uuid, hook_uuid, hook_project_update_request=hook_src ) else : hook = self.api.create_project_webhook( self.project_uuid, hook_project_create_request=hook_src ) テスト 指定した resource_type 、 action をHookリクエストとして送信します。 11 return self.api.test_project_webhook( self.project_uuid, hook_uuid, hook_test_request={ "resource_type" : resource_type, "action" : action}, ) 距離算出 距離算出プログラム APIアクセス部は SDK入門② と同じです。 Lambdaにあわせてメイン関数を lambda_hander に変更してあります。 定数は環境変数としてLambda設定から与えられるようにしてあります。 api_url = os.getenv( "API_URL" , "https://example.intdash.jp" ) api_token = os.getenv( "API_TOKEN" , "<YOUR_API_TOKEN>" ) fetch_size = int (os.getenv( "FETCH_SIZE" , 100 )) origin_lat = float (os.getenv( "ORIGIN_LAT" , 35.6878973 )) origin_lon = float (os.getenv( "ORIGIN_LON" , 139.7170926 )) origin = (origin_lat, origin_lon) # 会社 slack_url = os.getenv( "SLACK_URL" , "<YOUR_SLACK_WEBHOOK_URL>" ) テストコードから環境変数を与えて起動しています。 12 os.environ[ "API_URL" ] = "https://example.intdash.jp" os.environ[ "API_TOKEN" ] = "<YOUR_API_TOKEN>" os.environ[ "FETCH_SIZE" ] = "100" os.environ[ "ORIGIN_LAT" ] = "35.6878973" os.environ[ "ORIGIN_LON" ] = "139.7170926" os.environ[ "SLACK_URL" ] = "<YOUR_SLACK_WEBHOOK_URL>" なお、距離算出Lambaが計測を完了するときにもWebhookリクエストが送信されます。これにより、距離算出Lambdaがもう一度起動されるため、無限ループの防止が必要です。 位置情報を含むデータポイントだけを取得します。 stream = api.list_project_data_points( project_uuid=self.project_uuid, name=self.meas_uuid, data_id_filter=[ "#:1/gnss_coordinates" ], start=self.start, limit=fetch_size, time_format= "ns" , ) データポイントが0件の場合は作成した計測を削除します。 # 計測削除(GPSデータなし) if not count: self.writer.delete_measurement() logging.info(f "Deleted measurement: {measurement_dst.uuid}" ) return レスポンス返却プログラム intdash APIとは直接関わりません。 距離算出Lambdaを起動します。 response = lambda_client.invoke( FunctionName= "intdash-distance" , InvocationType= "Event" , Payload=json.dumps(body_dict), ) 起動は0.1秒程度で終わり、すぐにレスポンスを返却します。 return { "statusCode" : 200 , "body" : json.dumps({ "message" : "Webhook received and Distance Lambda invoked" }), } おわりに 今回は起動方法を実際の利用シーンに近づけてみました。 intdash SDKのLambdaレイヤーに登録しておけば、複数のLambda関数に適用できて便利です。 なお、Lambdaは最大実行時間が15分のため、もっと長い処理はFargateやEC2インスタンスを利用することになります。 リンク 本シリーズの過去記事はこちらからご覧ください。 SDK入門①〜社用車で走ったとこ全部見せます〜 :REST APIでデータ取得 SDK入門②〜データ移行ツールの作り方〜 :REST APIでデータ送信 SDK入門③〜RTSPで映像配信するぞ〜 :リアルタイムAPIでデータ取得 SDK入門④〜YOLOで物体検知しちゃう〜 :リアルタイムAPIでデータ送信 SDK入門⑤〜iPadでData Visualizerを見る会〜 :リアルタイムAPIでキャプチャデータ送信 10秒以内にレスポンスを返すため、Lambdaを二段構成にしています。intdashはWebhookリクエストのステータスを管理しており、10秒以内に通知先からレスポンスが返るとステータスを成功 succeeded に移行します。 ↩ テストコードは GitHub で公開しています。 ↩ 前回 までにインストールしたパッケージをすべてZIP化すると、Lambdaレイヤーの上限10MBを超えてしまうためです。 ↩ サンプルプログラムは GitHub で公開しています。 ↩ CLIの使い方は GitHub で解説します。 ↩ サンプルプログラム内にテンプレート lesson6/cli/config/hook.json を用意しています。 ↩ HMAC検証 でWebhookリクエストの改ざんを防止します。 ↩ 間違えやすいですが、各項目名は xxx_events ではなく xxx_event です。 ↩ 計測は1時間ほどで終了しています。Motionログイン時にサーバーで払い出すアクセストークンの有効期限によるものです。 ↩ 設定を1件取得する get_project_webhook は現行バージョンでは動作しません。次バージョンにて改修予定です。 ↩ SDK入門① で紹介しているintdash SDK for Python生成の手順では created / updated / deleted 以外の action がエラーになるようです。その場合は、curlコマンドで直接Test Hook APIを叩いて確認します。 ↩ テストコードの使い方は GitHub で解説します。 ↩
aptpod Advent Calendar 2024 12月25日(最終日)の記事です。 CTOの梶田です。 いつもの通り、今年もまたまたあっという間(いつも言ってますね💦)でAdvent Calendar もなんとか走りきれそうです。(今年は7年目にもなりました!) はじめに デジタルツインソリューションでの進展・協業 自動車業界のSDV化と新たな挑戦 2025年に向けて はじめに 2024年、アプトポッドは多岐にわたる取り組みを通じて、タイトルの通り、新たなつながりと共創を推進してきました。 ここ1年、迫る 2025年問題 (労働人口の減少や熟練者の引退による人手不足、技能伝承の難しさ)や、IT業界で言われる 2025年の崖 など、さまざまな課題が浮き彫りになっています。このような背景の中、多くの企業がDX(デジタルトランスフォーメーション)の推進に迫られている状況が感じられる一年でもありました。 こうした時代の変化の中で、アプトポッドの取り組みも進化を続けています。主力である自動車開発向けのソリューション展開に加え、他分野への活用も着実に広がりを見せています。たとえば、 intdash をミドルウェアとして基盤活用いただく事例や、ソリューション連携の事例が増加し、多岐にわたる分野での貢献が進みました。 <2024年初頭のリリース> www.aptpod.co.jp 今回は、こうした進展や取り組みを中心に、この一年を振り返っていきたいと思います! また、今回の AdventCalendar 2024 でも活用事例について以下でいくつか触れられておりますので是非ご覧ください。 11日目: Unity x ROS をこれから始める方へ、開発Tips書いてみた 13日目: intdashの計測データ分析ボードを作成してみた 17日目: EPS32でリアルタイム映像アップストリーム 20日目: SDK入門⑤〜iPadでData Visualizerを見る会〜 デジタルツインソリューションでの進展・協業 昨年(2023年)の振り返りでも触れた日立建機様との取り組みでは、さらなる進展がありました。 アプトポッド、日立建機と第三者割当増資による資本業務提携を実施 この協業の一環として、建設施工リアルタイムデジタルツイン基盤を開発し、第6回建設・測量生産性向上展「CSPI-EXPO」(2024年5月22日~24日)の日立建機ブースにて展示を行いました。 www.aptpod.co.jp この基盤は、建設施工における「人・機械・現場環境」をデジタルツインで統合・管理する技術であり、リアルタイムデータを活用して仮想空間上で現実世界を再現します。これにより、遠隔地からでも建設プロジェクトの進捗状況や安全性を詳細に監視・管理することが可能となります。さらに、少人数での現場運営を実現し、作業効率の大幅な向上が期待されています。 また、新たな取り組みとして、株式会社Liberaware様との協業により、建設施工管理や設備メンテナンス向けのデジタルツインソリューションを発表しました。 www.aptpod.co.jp このソリューションは、 360°動画ストリーミングから3Dデータを自動生成する技術 を活用しており、建設業界における人手不足の解消に向けたロボット化や自動化の推進に貢献します。業界全体が抱える課題解決に向けた重要な一歩と言えるでしょう。 <デモンストレーション動画> www.youtube.com (おまけ)関連情報 デジタルツインに関連する製品の新機能については、以下の技術ブログでも紹介しています。 tech.aptpod.co.jp さらに 「デジタルツイン」 というキーワードは業界内でも注目を集めており、メンテナンス系のイベントでは新たなつながりや協業のきっかけが生まれました。 tech.aptpod.co.jp 自動車業界のSDV化と新たな挑戦 自動車業界では、車両の機能をソフトウェアで定義・制御する SDV(Software-Defined Vehicle) が急速に進展しています。 ハードウェア中心の設計から脱却し、ソフトウェアを中核とした車両開発へのシフトが求められる中、アプトポッドは2024年に以下の取り組みを発表しました。この取り組みを通じ、SDV時代の加速に貢献していきたいと考えています。 <自動車ソリューションパッケージの最新バージョン> www.aptpod.co.jp この発表に記載された「MDF4形式でのデータダウンロード(予定)」については、Advent Calendarの記事でも取り上げています。ぜひご覧ください。 tech.aptpod.co.jp SDV化が進む中、アプトポッドのプラットフォーム intdashは、車両から取得される大量のデータをリアルタイムで収集・解析する機能を提供します。これにより、ドライビングデータやセンサーデータを活用した高速なソフトウェア開発・テストが可能になり、車両開発プロセスの効率化を実現します。 さらに、2024年7月には、株式会社共和電業様と共同で、自動車開発における試験プロセスの遠隔化やデジタルツイン対応を実現するクラウド計測ソリューションを発表しました。これは、SDV時代のニーズに応える重要なステップと位置づけられます。 www.aptpod.co.jp SDVでは、車両機能がソフトウェアによって定義され、開発プロセスは従来のハードウェア主体から、ソフトウェア中心のアプローチへと移行しています。これに伴い、車両開発においても、より柔軟で効率的なデータ活用が求められています。 共和電業様との協業によるソリューションは、クラウドを活用して同社の高品質なセンサーおよびデータロガーを用い、高精度なデータ収集とモデルベース開発環境を実現します。これにより、SDV時代にふさわしい新たな価値を創出し、自動車開発の未来を切り拓く基盤として貢献していきたいと考えています。 2025年に向けて 2024年は、これまで培ってきた基盤をさらに発展させ、新たなパートナーシップや技術革新を通じて、共創の輪を広げる一年となりました。 建設業界、自動車業界、そしてその他の分野におけるDXやデジタルツインの取り組みを推進し、多くの新しいつながりを生み出すことができました。 もちろん、これまで同様に課題もありましたが、その一つひとつに向き合い、チーム全体で成長を続けることができました。振り返ると、人数も少ない中、多くの成果が形になりつつあり、まだお伝えしきれていない事例も含め、まだまだたくさんの可能性を感じています。 改めて、一緒に挑戦を支えてくださったパートナー様、お客様、そしてチームメンバーに心から感謝しています。(今年もお疲れ様でした!) 2025年は、さらに重要な節目の年になると確信しています。 「2025年問題」や「SDVの進展」など、業界が大きな変革を迎える中で、私たちアプトポッドは引き続き、技術で未来を切り拓き、社会課題の解決に貢献していきたいと思います。お客様やパートナー様との共創をさらに深め、新しい価値を生み出す挑戦を続けていきます。 来年も、アプトポッドにどうぞご期待ください! メリークリスマス!🎄 それでは皆様、良いお年をお迎えください!
aptpod Advent Calendar 2024 12月24日の記事を担当します、 intdashグループの宮内です。 先日、筆者のグループ内で「開発環境の紹介」というテーマで意見交換を行いました。 グループ内ではソフト/ハードともに他人の開発環境に興味がある人が多いようで、 とても盛り上がりました。 ただ、その際に、筆者はNeovimを紹介したのですが、時間の都合上全然紹介しきれませんでした。 今回はこの場を借りて、その時の不完全燃焼感を払拭すべく、閑話休題的な形で、 筆者のNeovimについて紹介していきたいと思います。 ちなみに、グループ内はVSCode使いが多いです。 対象読者 筆者の開発環境について 設定のベース プラグイン紹介 プラグイン管理 lazy.nvim mason.nvim & mason-lspconfig mason-tool-installer.nvim コーディング nvim-cmp conform none-ls ThePrimeagen/refactoring.nvim Git gitsign git-blame.nvim diffview.nvim lazygit.nvim 検索置換 telescope.nvim grug-far.nvim text-case.nvim その他 overseer.nvim toggleterm.nvim dashboard-nvim rest.nvim venn.nvim vim-table-mode render-markdown.nvim まとめ 対象読者 これからNeovimを触ってみようと思っている人 Neovimのおすすめのプラグインを知りたい人 Neovimって一体どんなことができるのか知りたい人 筆者の開発環境について Neovimは様々なことができるので他のツールとの棲み分けはとても重要です。 ですから、まずNeovimを語る前に、筆者の開発環境について簡単に紹介します。 筆者はintdashミドルウェア開発のサーバーサイドを担当しています。 業務内では下記の言語やファイルを扱うことが多いです。 Golangのソースコード Pythonのソースコード (簡単な)シェルスクリプト yamlファイル(openapi.yaml、ci設定など) Docker関連(Dockerfile、compose.yamlなど) マークダウン また、エディタを含め次のような環境で開発を行っています。 Wezterm(端末エミュレータ。Rust製で実行環境を選ばないのが気に入っている。) tmux(ターミナルマルチプレクサ。ターミナル内で複数のセッションを管理できる。) Neovim zsh さらに、普段はMacから UbuntuへSSH接続し、開発業務は基本的にUbuntu上で行っています。 WeztermはMacにインストールし、あとはさっさとsshでUbuntuの中に入って引きこもり作業している形です。 Weztermを開く sshでUbuntuへ入る tmuxでセッションを開く(過去のものがあれば作業中のセッションに入る) tmuxペインを設定しNeovimで作業 本当はNeovim以外にも語りたいことはあるのですが今回はNeovimに絞って紹介します。 設定のベース Neovimの大きな魅力の一つは、そのカスタマイズ性の高さにあります。しかしその反面、初期状態では機能が少なく、効率的に使い始めるには設定が必要です。 その課題を解決するために、スターターキットとして使えるテンプレートが多数公開されています。例えば、以下のようなものがあります。 kickstart.nvim LazyVim NvChad AstroNvim LunarVim SpaceVim それぞれ特徴があるので、自分の好みに合わせて選ぶと良いと思います。 カスタマイズはどのテンプレートでも可能ですが、筆者は「設定がほどよく薄く、自由度が高い」という理由でkickstart.nvimを選んでいます。 kickstart.nvimの運用については、公式のREADME.mdに記載がありますが、筆者は以下の手順で管理しています: リポジトリのフォーク 自分のGitHubリポジトリにフォークし、カスタマイズや運用を行いやすくしています。 dotfilesでの管理 フォークしたkickstart.nvimをdotfilesリポジトリ内でsubmoduleとして管理しています。 定期的な同期 フォーク元のリポジトリから最新の変更を定期的にマージし、テンプレートをメンテナンスしています。 以下は具体的な手順です。 GitHub CLI を使用した手順です。: # 最初にkickstart.nvimをフォーク gh repo fork nvim-lua/kickstart.nvim # dotfilesリポジトリにsubmoduleとして追加 cd /path/to/dotfiles git submodule add git@github.com:<ユーザー名>/kickstart.nvim.git ./.config/nvim # フォーク元のリポジトリと定期的に同期 gh repo sync <ユーザー名>/kickstart.nvim プラグイン紹介 筆者はNeovimのプラグインを現在 101 個使用しています。 流石にすべてを紹介することはできないので、ここではメインに使用しているプラグインとその設定についてと、一部おもしろいプラグインを紹介します。 それぞれカテゴリごとに紹介します。 プラグイン管理 lazy.nvim プラグイン管理ツールです。現在、Neovimでのプラグイン管理のデファクトスタンダードとなっている感があります。 例えば、プラグインの読み込みを必要なタイミングに最適化することで、起動速度を速く保つことが可能です。設定も簡単で、多くのユーザーに支持されています。 kickstart.nvimにも組み込まれているのでそのまま使用しています。 mason.nvim & mason-lspconfig LSP(Language Server Protocol)、DAP(デバッグ)、Formatter、Linterのツールを簡単に管理するためのプラグインです。 MasonInstall コマンドを使用すると、ツールが ~/.local/share/nvim/mason/bin/ にインストールされ、Neovim内で使用可能になります。 以下のプラグインと連携すると、さらに便利に使えます。 README.md にある内容です。: LSP : lspconfig & mason-lspconfig.nvim DAP : nvim-dap & nvim-dap-ui Linters : null-ls.nvim or nvim-lint Formatters : null-ls.nvim or formatter.nvim 筆者の設定例では、Formatterとして conform.nvim を使用し、Linterには none-ls.nvim ( null-ls.nvim のフォーク)を採用しています。 mason-tool-installer.nvim このプラグインを使用すると、新しい環境でも再現性を持って同じツールセットをインストールできます。 kickstart.nvimにも雛形設定が含まれているため、簡単に導入できます。 以下はMasonでインストールしているツール一覧と、その設定コードです: require ( 'mason' ).setup() -- Masonでインストールするツールを指定 local ensure_installed = { 'stylua' , -- Luaのフォーマッタ 'gopls' , -- Golangの言語サーバー 'prettier' , -- JS/TSのフォーマッタ 'pyright' , -- Pythonの言語サーバー -- 省略 ... } require ( 'mason-tool-installer' ).setup { ensure_installed = ensure_installed } コーディング nvim-cmp nvim-cmp は、Neovimでのコード補完を提供するプラグインです。コード補完系のプラグインはいくつかありますが、 nvim-cmp はその拡張性と安定性から多くのユーザーに支持されています。 筆者は kickstart.nvim の設定に含まれていたこともあり、そのまま nvim-cmp を使用しています。 以下は、筆者が使用している nvim-cmp の補完ソース一覧です。特に珍しいものはありませんが、必要な補完を網羅しています: L3MON4D3/LuaSnip saadparwaiz1/cmp_luasnip hrsh7th/cmp-nvim-lsp hrsh7th/cmp-path hrsh7th/cmp-nvim-lsp hrsh7th/cmp-nvim-lsp-signature-help hrsh7th/cmp-buffer hrsh7th/cmp-path hrsh7th/cmp-cmdline hrsh7th/cmp-calc hrsh7th/cmp-emoji onsails/lspkind.nvim petertriho/cmp-git 他にも nvim-cmp のソースはたくさんあるので探してみると面白いでしょう。 conform フォーマッタです。 kickstart.nvim に組み込まれているものをそのまま使用しています。 デフォルト設定では保存時に自動フォーマットが有効になっていますが、無効化する場合は設定を変更する必要があります。 Recipe command-to-toggle-format-on-save で紹介されている内容を基本に kickstart用には下記のように読み替えて設定します: -- オプション opts = { format_on_save = function (bufnr) -- Disable with a global or buffer-local variable if vim.g.disable_autoformat or vim.b[bufnr].disable_autoformat then return end - 省略 end , } , -- config関数 config = function (_, opts) vim.api.nvim_create_user_command( 'FormatDisable' , function (args) if args.bang then -- FormatDisable! will disable formatting just for this buffer vim.b.disable_autoformat = true else vim.g.disable_autoformat = true end end , { desc = 'Disable autoformat-on-save' , bang = true , } ) vim.api.nvim_create_user_command( 'FormatEnable' , function () vim.b.disable_autoformat = false vim.g.disable_autoformat = false end , { desc = 'Re-enable autoformat-on-save' , } ) require ( 'conform' ).setup(opts) end none-ls none-ls.nvim は null-ls.nvim のフォークで、 diagnostic, codeaction, formatting, completion, hover の設定が可能です。 ですが、Lspの設定やフォーマッタの設定と重複するものがあるので、筆者はdiagnosticとcodeactionのみを使用しています。 また、インストールについてはMasonと統合するプラグインがあるので、あまり活用できていませんが合わせて使用しています。 config = function () local null_ls = require 'null-ls' null_ls.setup { sources = { null_ls.builtins.diagnostics.golangci_lint, null_ls.builtins.diagnostics.hadolint, null_ls.builtins.diagnostics.rstcheck, null_ls.builtins.diagnostics.markdownlint.with { args = { '--stdin' , '-c' , vim.fn.expand '$HOME/.markdownlintrc' } , } , null_ls.builtins.diagnostics.sqlfluff.with { extra_args = { '--dialect' , 'postgres' } , -- change to your dialect } , require 'none-ls.diagnostics.ruff' , null_ls.builtins.code_actions.refactoring, null_ls.builtins.code_actions.gomodifytags, } , } require ( 'mason-null-ls' ).setup {} end リファレンスとしては「 BUILTINS 」を良く参照するので紹介しておきます。 ThePrimeagen/refactoring.nvim refactoring.nvim は、様々なリファクタリング操作をサポートするNeovim用プラグインです。関数抽出や変数リネームといった一般的なリファクタリングに加え、デバッグプリント機能が非常に便利です。 筆者は、特にデバッグプリントの挿入と削除をよく利用しています。下記の設定例では、次の操作を簡単に行えます: <leader>rp :現在行の上にデバッグプリントを挿入。 <leader>rd :選択した変数のデバッグプリントを挿入。 <leader>rc :挿入済みの全てのデバッグプリントを削除。 以下は設定例です: vim.keymap.set( 'n' , '<leader>rp' , function () require ( 'refactoring' ).debug.printf { below = false } end ) vim.keymap.set( { 'x' , 'n' } , '<leader>rd' , function () require ( 'refactoring' ).debug.print_var() end ) vim.keymap.set( 'n' , '<leader>rc' , function () require ( 'refactoring' ).debug.cleanup {} end ) 例えば、以下のようなコードに対して a をデバッグプリントしてみます。: func add(a int , b int ) int { return a + b } a を選択肢 <leader>rd を押すと、次のようなデバッグプリントが挿入されます: func add(a int , b int ) int { // __AUTO_GENERATED_PRINT_VAR_START__ fmt.Println(fmt.Sprintf( "add a: %v" , a)) // __AUTO_GENERATED_PRINT_VAR_END__ return a + b } <leader>rp を使うと、次のようなデバッグプリントが挿入されます。 func add(a int , b int ) int { // __AUTO_GENERATED_PRINTF_START__ fmt.Println( "add 1" ) // __AUTO_GENERATED_PRINTF_END__ return a + b } Git gitsign gitsign は、NeovimでGitの変更内容を視覚的に表示し、操作を補助するプラグインです。 このプラグインは kickstart.nvim に含まれているため、特別な設定は不要です。 kickstart.nvim では ]c と [c で変更箇所の行き来が可能で、 <Leader>h に hunk を操作するキーバインドが設定されています。 筆者はgitの操作自体は後述する lazygit で行うことが多いので、メインで使っているのは、変更箇所の移動です。 git-blame.nvim git-blame.nvim は、特定の行が誰によって、いつ変更されたのかを表示するプラグインです。 このプラグインを有効にすると、現在編集中の行に変更履歴が表示され、コードレビューや変更理由の確認に役立ちます。 有効にすると、下記のようにBlameがコード上に表示されます。 git-blameを表示中 公式リポジトリのスクリーンショットが分かりやすいため、興味のある方はこちらをご覧ください: 公式リポジトリ diffview.nvim ソースコード編集中にそのファイルの履歴とか、mainブランチとの差分とか見たいときありますよね。 そんなときに活躍するのがこのプラグインです。 マージツールとしても使用できます。 筆者は特に特殊な設定をしておらずデフォルトで使用しています。 あとはマージツールとして使うこと多いのと、下記のコマンドは良く実行します。: :DiffviewOpen <比較先ブランチなど> :DiffviewOpen <比較先ブランチなど> -- % :DiffviewFileHistory :現在のファイルの変更履歴を表示。 lazygit.nvim lazygit.nvim は、Neovim内で lazygit を使用できるプラグインです。このプラグインを導入することで、ターミナルに切り替えることなくGit操作を行うことができます。 筆者は以前、 vim-fugitive や NeoGit なども使用していたのですがが、シェル上での操作と統合が出来ず、 シェル上では lazygit を使うため、このプラグインを選びました。操作を統一できる点が非常に便利です。 後述しますが toggleterm を使用して開くこともできるようです。どちらでもさほど大きな差はないと思います。 lazygit からファイルを編集したり、コミットメッセージをNeovimで書くには、以下の設定を .bashrc に追加します: #### NVIM REMOTE if [ -n " $NVIM " ]; then alias nvim = nvr -cc split --remote-wait + ' set bufhidden=wipe ' fi if [ -n " $NVIM " ]; then export VISUAL =" nvr -cc split --remote-wait +'set bufhidden=wipe' " export EDITOR =" nvr -cc split --remote-wait +'set bufhidden=wipe' " else export VISUAL =" nvim " export EDITOR =" nvim " fi この設定により、Neovim内で lazygit を使用してもファイル編集やコミットメッセージ作成がシームレスに行えます。 lazygit の設定では、以下を追記します: os : editPreset : "nvim-remote" こちらの設定をすれば、プラグインのREADMEのファイル編集設定を変更する必要はない(はず)です。 ただし、筆者の環境だと下記の不具合の現象に遭遇しています。四角い領域が出現し、削除ができなくなります。 現象は「 Blank window overriding code after opening lazygit.nvim on start screen #134 」 に近いです。 コメントにある内容も読んだのですがうまく解消されず、時間があるときに調整してみようと思っています。 検索置換 telescope.nvim telescope.nvim は、Neovimで効率的にファイル、テキスト、バッファ、Git履歴などを検索するためのファジーファインダープラグインです。 筆者は以前 fzf のプラグインを使用していましたが、 telescope.nvim は仕組み上拡張機能が作りやすく、他のプラグインとの連携も豊富なため、こちらに切り替えました。 以下は筆者が使っている telescope.nvim の拡張機能です: 名前 説明 telescope-all-recent.nvim find_files や git_files など通常の選択フィルターに対してスコアリングされた順序で選択できるようになります。 telescope-fzf-native.nvim fzfの表現を統合。fzfユーザーには特に便利です。 telescope-live-grep-args.nvim live_grep に対して、ripgrepのオプションを指定できるようになります。 telescope-recent-files 最近開いたファイル順のフィルターです。 特に telescope-all-recent.nvim はシームレスに統合でき、無意識に恩恵を受けることができるので個人的な感想ですが筋が良いように思います。 ドキュメントにも書いてありますが、次のようにTelescopeのキーバインドを関数で指定する必要があるのでその点は注意しましょう。 vim.keymap.set( 'n' , '<leader>sf' , function () require ( 'telescope.builtin' ).find_files() end , { desc = '[S]earch [F]iles' } ) grug-far.nvim 検索置換のプラグインです。一括置換で重宝します。 似た操作感で nvim-spectre というプラグインもあります。 好みで選ぶと良いと思いますが、筆者はnvim-spectreの検索ペインの操作感にどうしてもなれることができず、 grug-far.nvim を使用しています。 以前はQuickfixと「 quickfix-reflector.vim 」を利用して置換を行っていましたが、手数が多いことが少し気になり、 このプラグインに落ち着きました。 デフォルト設定で快適に使用できます。おすすめです。 text-case.nvim text-case.nvim は、テキストをCamelCase、SnakeCaseなどに変換しつつ、またそれらの賢い置換も可能にするプラグインです。 例: Subs /abc def/ghi jkl/ とコマンドを実行すると、 AbcDef といった文字列も GhiJkL に変換します。 類似プラグインとして tpope/vim-abolish もありますが、筆者は現在両方を試しています: vim-abolish では複数形の置換など特有のルールも持っているため、置換機能としては vim-abolish のほうが高度な印象です。 筆者は状況に応じてどちらを使うか選定中です。 その他 overseer.nvim overseer.nvim は多機能なタスクランナーで、ビルド、テストなどの開発内のタスクをNeovim内で管理できます。 筆者は以前、 vim-dispatch や quickrun を利用していましたが、Neovim環境に最適なタスクランナーを探している中でこのプラグインを見つけました。 いくつかタスクを登録してはいますが、もう少しカジュアルに使用できるように時間があるときに拡張したいと思っています。 公式ドキュメントも充実しており、チュートリアルやレシピが提供されています: チュートリアル レシピ一覧 筆者は vim-dispatch の :Make はよく使っていたので、そのレシピがあったのはとても助かりました。: :Make similar to vim-dispatch toggleterm.nvim toggleterm.nvim は、Neovim内でターミナルウィンドウを簡単に開き、切り替えたり、閉じたりできるプラグインです。 筆者は普段 tmux を使っていますが、「tmuxを開くほどではないちょっとした操作」にはこのプラグインを利用しています。 以下は筆者の設定例です。ターミナルの表示・非表示を <C-z> で切り替え、 <leader>ld で lazydocker を起動します: config = function () require ( 'toggleterm' ).setup { open_mapping = [[<C-z>]] , direction = 'horizontal' , size = 20 , } local lazydocker = require ( 'toggleterm.terminal' ).Terminal:new { cmd = 'lazydocker' , hidden = true , direction = 'float' , } function LazydockerToggle() lazydocker:toggle() end ... 他の設定 vim.api.nvim_set_keymap( 'n' , '<leader>ld' , '<cmd>lua LazydockerToggle()<CR>' , { noremap = true , silent = true } ) end tmux との棲み分けについて、筆者は以下のように使い分けています: toggleterm.nvim :同一プロジェクト内でシェル操作をする際に使用。 tmux :別プロジェクトの操作や、長時間のターミナルセッションを管理する場合に使用。 普段はdockerを使った開発をしているので、いつでもさっとコンテナの状態を見れる、操作できるというのは体験としてとても心地よいです。 dashboard-nvim Neovim起動時に表示されるダッシュボードをカスタマイズできるプラグインです。筆者は、曜日ごとに変わるバナーを設定しています。 筆者のダッシュボード 以下は筆者が登録しているショートカットの設定例です: ダッシュボード上で初期の操作のショートカットが簡単にできるため、特に「最初にやることが決まっている人」におすすめです。 筆者はだいたい決まっているので下記を登録しています。 config = function () require ( 'dashboard' ).setup { theme = 'hyper' , config = { week_header = { enable = true , } , project = { enable = false , } , shortcut = { { desc = 'Update' , group = '@property' , action = 'Lazy update' , key = 'u' } , { icon = '' , icon_hl = '@variable' , desc = 'Files' , group = 'Label' , action = 'Telescope git_files' , key = 'f' , } , { desc = 'Memo' , action = 'Telekasten' , key = 'm' , } , { desc = 'dotfiles' , action = 'e ~/dotfiles/README.md' , key = 'd' , } , } , } , } end rest.nvim rest.nvim は、Neovim内でHTTPリクエストを実行できるプラグインです。 筆者は以前 vim-rest-console を使用していましたが、出力が整形されない問題があったため、こちらに移行しました。 特徴としては次のようなものが上げられます: 環境変数を簡単に切り替え可能( Telescope 連携)。 JetBrainsの HTTP Syntax をサポート。 安定した整形が可能( jq を使用) コマンドはいくつか種類がありますが、筆者は下記の用にシンプルに「 <C-o> で実行する」「環境変数の変更はTelescopeで実施」の 2つだけショートカット設定をしています。基本的にこの2つの機能しか使っていませんが十分満足しています。 整形のオプションだけ、公式から少し追いづらかったのでそちらも合わせて例として記載しています: config = function () vim.api.nvim_create_autocmd( 'FileType' , { pattern = 'json' , callback = function () vim.bo.formatexpr = '' vim.bo.formatprg = 'jq' end , } ) vim.api.nvim_create_autocmd( 'FileType' , { pattern = 'http' , callback = function () vim.api.nvim_set_keymap( 'n' , '<Leader><C-o>' , ':Rest run<CR>' , { noremap = true , silent = true } ) -- first load extension require ( 'telescope' ).load_extension 'rest' -- then use it, you can also use the `:Telescope rest select_env` command vim.api.nvim_set_keymap( 'n' , '<leader>se' , ':Telescope rest select_env<CR>' , { noremap = true , silent = true , desc = '[S]earch select [E]nv' } ) end , } ) end venn.nvim エンジニアの皆さんは図を書くことが多いと思いますが、こちらのプラグインはASCIIアートで簡単に図を作成できるプラグインです。 下記のように簡易的なデータフローを表現する際に役立ちます。 ┌─────┐ ┌───┐ │start│──────────────►│end│ └─────┘ └───┘ 基本的な操作の流れは次のとおりです: :set ve=all とする 文字を書く visual矩形選択などで選択し :VBox<CR> 公式のREADME.mdに設定は書いてあり、それをそのまま使うことが出来ます。 筆者は若干変えてはいますが次のようにしています。 <CR> でボックスができるようにしてある点が気に入っています。: config = function () -- venn.nvim: enable or disable keymappings function _G .Toggle_venn() local venn_enabled = vim.inspect(vim.b.venn_enabled) if venn_enabled == 'nil' then vim.b.venn_enabled = true vim.cmd [[setlocal ve=all]] -- draw a line on HJKL keystokes vim.api.nvim_buf_set_keymap( 0 , 'n' , 'J' , '<C-v>j:VBox<CR>' , { noremap = true } ) vim.api.nvim_buf_set_keymap( 0 , 'n' , 'K' , '<C-v>k:VBox<CR>' , { noremap = true } ) vim.api.nvim_buf_set_keymap( 0 , 'n' , 'L' , '<C-v>l:VBox<CR>' , { noremap = true } ) vim.api.nvim_buf_set_keymap( 0 , 'n' , 'H' , '<C-v>h:VBox<CR>' , { noremap = true } ) -- draw a box by pressing "f" with visual selection vim.api.nvim_buf_set_keymap( 0 , 'v' , '<CR>' , ':VBox<CR>' , { noremap = true } ) print 'venn on' else vim.cmd [[setlocal ve=]] vim.api.nvim_buf_del_keymap( 0 , 'n' , 'J' ) vim.api.nvim_buf_del_keymap( 0 , 'n' , 'K' ) vim.api.nvim_buf_del_keymap( 0 , 'n' , 'L' ) vim.api.nvim_buf_del_keymap( 0 , 'n' , 'H' ) vim.api.nvim_buf_del_keymap( 0 , 'v' , '<CR>' ) vim.b.venn_enabled = nil print 'venn off' end end vim.api.nvim_set_keymap( 'n' , '<leader>tv' , ':lua Toggle_venn()<CR>' , { noremap = true } ) end vim-table-mode Markdownを書いているとき、どうしても辛いのが表を書くときです。 このプラグインを使用することでマークダウンで辛くなりがちなテーブル編集を楽にすることが出来ます。 いくつか機能はありますが、フォーマット機能だけで筆者は十分で、その他は使用していません。 | Column1 | Column2 | Column3 | | --------------- | --------------- | --------------- | | Item1.1 | Item2.1 | Item3.1 | | Item1.2 | Item2.2 | Item3.2 | | Item1.3 | Item2.3 | Item3.3 | | Item1.4 | Item2.4 | Item3.4 | :TableModeRealineを実行すると下記のようになる。 | Column1 | Column2 | Column3 | | --------------- | --------------- | --------------- | | Item1.1 | Item2.1 | Item3.1 | | Item1.2 | Item2.2 | Item3.2 | | Item1.3 | Item2.3 | Item3.3 | | Item1.4 | Item2.4 | Item3.4 | フォーマットを自動で適宜行ったり、その他テーブル編集に特化した、テーブル編集モードの切り替えもあるのですが、 筆者は :TableModeRealine コマンドを適宜実行して使用することが多いです。 render-markdown.nvim render-markdown.nvim は、Neovim内でMarkdownファイルを見やすくレンダリングするプラグインです。 筆者は markdown-preview.nvim も併用していますが、「Neovim内で完結させたい場面」ではこちらを主に使用しています。 最後に紹介する render-markdown.nvim は、Neovim内でMarkdownファイルを見やすくレンダリングするプラグインです。 良く紹介されているのは markdown-preview.nvim かと思うのですが、 筆者はNeovim引きこもり気味なので、外部ブラウザを使わずにプレビューできないかと、探していたところ発見したのがこちらのプラグインになります。 CopilotChatのプラグインの表示でも適用可能なのも気に入っています。 もちろん、ブラウザで確認したいときもあるので markdown-preview.nvim もたまに使っています。 まとめ 環境をカスタマイズすることで、生産性を飛躍的に向上させることができます。 しかし、本当に大事なのは、「効率化して何を成し遂げたいのか」ということだと筆者は思います。 例えば、以下のような目標があるかもしれません: 家族や趣味の時間を増やしたい。 クリエイティブな作業にもっと集中したい。 より多くの成果を短時間で出したい。 どのような目標であれ、開発環境を洗練させることで、日々の無駄な時間を削減し、本当に集中すべきことに時間を使う手助けとなります。 この記事を参考に、ぜひ一つでも便利なツールや設定を取り入れてみてください。 筆者は年末年始に環境の棚卸しをするのですが、ちょうど今が良いタイミングではないでしょうか? そして、より充実したエンジニアライフを送れるように頑張りましょう! 私たちのチームでは、Neovim好きなエンジニアを募集中です。興味のある方、私たちと一緒に働きませんか? ぜひご連絡をお待ちしています! 採用ページ 明日はアドベントカレンダー最終日です。毎年恒例のCTO梶田さんの記事をお楽しみに!
はじめに aptpod Advent Calendar 2024 12月23日の記事です。 ソリューション開発&パートナー支援グループの村松です。弊社では、遠隔計測、操縦の支援を行っております。 通常は、携帯電話網を利用した案件が多いのですが、アンテナが設置されていない場所での計測のご依頼もございます。 弊社独自の 通信プロトコル(iSCP) には、一時的な通信途絶時に収集データをエッジ搭載のSSDに格納し、通信再開後に途絶時のデータを通信の空き容量で再送する機能が搭載されています。 洋上やOEMが保有する山あいのテストコースなど、計測地のネットワークが存在しない場所では、リアルタイムでのモニタや遠隔操作はもちろん、SSDの容量が、計測時間の制限となります。 今回は、昨年2023年7月からサービス提供を開始してる洋上インターネットサービス「Starlink MARITIME」を用いた計測をご紹介します。 はじめに Starlinkとは 本題 Starlinkとは Starlinkは、アメリカの航空宇宙企業スペースXの完全子会社であるスターリンクサービスLLCが運営する衛星インターネットコンステレーションです。コンステレーション(constellation 星座)とは、多数の人工衛星の一群・システムを指し、個々の衛星は他の衛星と連携しネットワークシステムを構築しています。 スターリンクの衛星群は、地球低軌道(LEO: low Earth orbit 地表より2000km以下の軌道)上に展開され、2024年12月時点で5600機を超える小型衛星で構成されています。 STARLINKMAP.ORG - Real-Time Starlink Satellite Tracker 衛星軌道 小型化・量産化により製造と打ち上げのコスト削減を実現した人工衛星を経由して、利用者が所有する専用の無線通信端末キットと各国に設置された地上ステーションを結び、ユーザーの居住地の地上インフラによらない、低価格の衛星インターネットアクセスサービスを提供しています。実際にサービスが提供されるのはスペースXがサービス提供のライセンスを取得した国に限られ、2024年現在91カ国でサービスを提供されています。 日本では、2022年10月11日 アジア初として東日本の一部地域のみ対応エリアとしサービスが開始され、2022年12月に日本全国で利用可能となりました。 Starlink が日本でのサービスを開始しました - アジアでは初めてのサービス国です → https://t.co/slZbTmHdml — SpaceX (@SpaceX) 2022年10月10日 2023年7月3日から、衛星ブロードバンドサービス「Starlink」について、領海内の海上利用向けにサービス提供を開始され、日本領海内航海中にダウンロード速度最大220Mbps(ベストエフォート)の通信環境が可能になりました。 Starlinkを海上利用向けに提供開始 | KDDI News Room 本題 Starlinkを用いた2024年10月16日から18日の3日間の海上通信速度に焦点を絞ってお話を進めたいと思います。 計測項目:  端末1 既設船外カメラ映像 H.264 1920x1080 15fps 機関インジケータ画面 H.264 1920x1080 15fps 船外音声 PCM 16bit GPS NMEA 1Hz 端末2 船橋操船カメラ映像 H.264 1920x1080 15fps 電子海図表示画面 H.264 1920x1080 15fps 船橋音声 PCM 16bit GPS NMEA 1Hz 2台の端末(edgeplant T1)を有線ルータを介し、Starlinkと接続しリアルタイム計測を行いました。 構成図 edge状態をリモートから確認できるように、edgeよりクラウドへ約1Hz周期で、CPU利用率(top),ディスク利用率(df),ネットワーク利用率(netstat)などの情報をクラウドに上げております。 通常のLTE通信によるデータ収集では、RSSIやedgeが掴んでいる通信バンドの確認など、通信障害時に有用な情報がリモート側のVM2M上に表示可能となっております。 今回は、ネットワーク利用率とくに、2台のedgeからクラウドへの上りの速度(wlan0.tx.bps)を用いてアップリンクの通信速度を集計してみました。 2024年10月16日 19:00 (勝浦沖25Km 35°10'55.1"N 140°41'25.2"E) から 2024年10月18日 00:00 (銚子沖90Km 35°38'27.5"N 142°02'56.0"E) まで、 データ点数: 36937データポイント 最大値: 51.46Mbps 平均値: 11.27Mbps 中央値: 11.68Mbps ヒストグラム 今回の海洋計測では、2台のEdge端末のTx合計より、おおむね上り11Mbpsでデータ回収ができていたようです。平均を下回るケースも5375回見うけられ、計測ポイントで14%が10Mbps以下の低速通信となっていました。その反面、20Mbpsを越える通信速度も1.3%、最大速度51.46Mbpsを確認できました。日本国内での契約増加が見込めれば、日本上空を通過する衛星数が増加し、通信速度の改善も期待できるかと考えております。
Data VisualizerはPCでしか動かないと思っているみなさん、 その通りです。 こんにちは、ソリューションアーキテクトの伊勢です。 こちらは aptpod Advent Calendar 2024 12月20日の記事です。 intdashのビューアーであるData Visualizerを スマホやタブレットで利用したいというご要望をいただくことがあります。 今回はintdash SDKを使ってiPadでData Visualizerを"見る"方法をご紹介します。 はじめに VM2M Data Visualizerとは VM2M Stream Videoとは やってみた 全体構成 インストール クライアントライブラリ サンプルプログラム用ライブラリ 実行結果 サンプルプログラム おわりに リンク はじめに VM2M Data Visualizerとは 時系列データを可視化するダッシュボードアプリケーションです。 www.aptpod.co.jp エッジからintdashサーバーに送られるデータのリアルタイムに可視化や、サーバーに保存された過去データのプレイバックができます。 ダッシュボードは可視化パーツを使ってユーザー自身でレイアウト可能です。 Data VisualizerはMicrosoft EdgeやGoogle Chromeなどのブラウザで動作します。 PCでの細かな設定操作が必要なため、スマホやタブレットには対応していません。 そこで今回はiOSアプリのVM2M Stream Videoを使います。 VM2M Stream Videoとは iPhoneやiPadで利用できるintdashのビューアーです。 Data Visualizerほどのカスタマイズ性はありませんが、1つの動画と1つの音声を手軽にLIVE再生/プレイバック再生できます。 VM2M Stream Video V2 Aptpod Lab ビジネス 無料 apps.apple.com やってみた 全体構成 Data Visualizerの画面自体を映像データとしてストリームします。 全体構成図 計測データをData Visualizerで再生し、PC画面をキャプチャしてリアルタイムAPI用intdash SDKでアップストリームします。 キャプチャ映像をStream Videoでダウンストリームします。 これでData Visualizerと同じレイアウトで計測データを見ることができます。 1 あわせて、元計測の音声も再生します。 インストール クライアントライブラリ SDK入門③ のリアルタイムAPI用クライアントライブラリを利用します。 サンプルプログラム用ライブラリ SDK入門④ の映像加工・エンコード用のライブラリを利用します。 OpenCV Gstreamer PyGObject 画面キャプチャのため、MSS(multiple screenshots)をインストールします。 pip install mss 実行結果 エッジで計測を開始し、PCのData VisualizerでLIVE再生します。 今回は車載エッジのGPS、カメラ映像、CANデータをレイアウトしてみました。 PCでData VisualizerのLIVE再生 サンプルプログラムを起動します。 2 python lesson5/src/caputure_screen.py --api_url https://example.intdash.jp --api_token < YOUR_API_TOKEN > --project_uuid < YOUR_PROJECT_UUID > --edge_uuid < YOUR_EDGE_UUID > edge_uuid : 画面キャプチャをアップストリームするエッジ サンプルプログラム起動 Stream Videoで映像と音声を指定して再生を開始します。 Video Edge: 画面キャプチャをアップストリームするエッジ Data Type: h264_frame Data Name: 10/h264 Audio Edge: 元計測のエッジ Data Type: pcm Data Name: 150/pcm iPadでVM2M Stream VideoのLIVE再生 VM2M Stream Video画面 Data Visualizer〜Stream Videoの遅延はどのぐらいでしょうか。 Data Visualizerスクリーンと再生映像の表示時刻を比較しました。 表示時刻を比較 遅延時間を確認 179ミリ秒でした。目視での遅延はほぼ感じられません。 3 サンプルプログラム intdash APIアクセス部分は 前回 と同じため、あまり説明するところはありません。 今回は計測を完了するタイミングをCtrl+Cのプログラム停止時にしています。 except asyncio.CancelledError: self.writer.complete_measurement(measurement.uuid) logging.info(f "Completed measurement: {measurement.uuid}" ) おわりに 今回はAdvent Calendarということでやや軽めの内容です。 前回のリアルタイム送信を応用して、製品機能の利用範囲を広げてみました。 intdash以外のソフトウェア画面をアップストリームして計測データとあわせて可視化したり、活用の幅が色々と考えられそうです。 リンク おかげさまでSDK入門シリーズも5つ目の記事となりました。 intdash SDKをもっと知りたい!という方はこちらからご覧ください。 SDK入門①〜社用車で走ったとこ全部見せます〜 :REST APIでデータ取得 SDK入門②〜データ移行ツールの作り方〜 :REST APIでデータ送信 SDK入門③〜RTSPで映像配信するぞ〜 :リアルタイムAPIでデータ取得 SDK入門④〜YOLOで物体検知しちゃう〜 :リアルタイムAPIでデータ送信 ダウンストリームされるのはキャプチャ映像であり、Stream Videoでは参照のみできます。レイアウトの変更はできません。 ↩ サンプルプログラムは GitHub で公開しています。 ↩ 自宅のWifi環境で計測しました。キャプチャとエンコードをするPC性能にも依存します。 ↩
aptpod Advent Calendar 2024 12月19日の記事を担当します、intdashグループの野本です。 普段からエッジデバイスでのコンテナ化やAIモデルの利用に携わっており、その調査を兼ねてIntel® Deep Learning Streamer(以下、DL Streamer)を試してみました。 特に、最近Dockerでのインストールがサポートされたとのことで、手軽に始められるようになった点にも注目しています。 *1 本記事では、このDL Streamerを使った映像推論の手順や実践例をご紹介します。 Intel® Deep Learning Streamerとは DL Streamerを使ってみる 事前準備 インストール モデルのダウンロード コンテナの起動 物体検知の実行 Pythonで後処理する その他のできること まとめ Intel® Deep Learning Streamerとは Intel® Deep Learning Streamer は、GStreamerをベースとしたオープンソースのストリーミングメディア分析フレームワークで、ディープラーニング(深層学習)アプリケーションの開発、デプロイ、および最適化を容易にするためのフレームワークです。基本的には、IntelのCPU、GPU、NPUで使用することができます。 DL Streamer ソフトウェアスタック アプリケーションとしてはGstreamerのプラグインで提供されており、内部ではVA-API、oneAPI、OpenVINO、OpenCVなどの依存ライブラリなどが使用されています。 DL Streamerを使ってみる 今回は映像推論の中でも代表的な物体検知を試します。 HDMI-USBキャプチャーから映像を入力し、車検知モデルを使用したgstreamerパイプラインを動作させ、検知結果の重畳映像をUDPで出力します。 また、検知結果の後処理として、フィルター処理をPythonスクリプトで実装します(詳細は後述します)。 全体構成 ホストマシン構成 CPU: Intel(R) Core(TM) i7-10510U GPU: Intel UHD Graphics (iGPU) OS: Ubuntu 22.04 ※ 以下の手順は、2024/12 時点の情報となります。最新の情報については 公式ドキュメント を参照ください。 事前準備 ホストに、あらかじめ前提条件のドライバをインストールします。 スクリプトをダウンロード mkdir -p ~/intel/dlstreamer_gst cd ~/intel/dlstreamer_gst/ wget https://github.com/dlstreamer/dlstreamer/raw/master/scripts/DLS_install_prerequisites.sh 実行権限をつけて実行 sudo chmod +x DLS_install_prerequisites.sh ./DLS_install_prerequisites.sh インストール完了後、ディレクトリを削除 rm -rf ~/intel/dlstreamer_gst インストール DL Streamerは、aptリポジトリからインストールする方法と、Dockerイメージでインストールする方法があります。 今回はDockerイメージでインストールします。 Ubuntuのバージョンによって使用するイメージが異なります。今回は Ubuntu 22.04ですので、22.04向けのイメージを選択します。 docker pull intel/dlstreamer:2024. 1 .2-ubuntu22 コンテナ内で、DL Streamerのgstreamerのエレメントが認識されていれば、インストール完了です。 docker run -it --rm intel/dlstreamer:2024. 1 .2-ubuntu22 $ gst-inspect-1. 0 gvadetect ... Factory Details: Rank none ( 0 ) Long-name Object detection ( generates GstVideoRegionOfInterestMeta ) Klass Video Description Performs object detection using SSD-like ( including MobileNet-V1/V2 and ResNet ) , YoloV2/YoloV3/YoloV2-tiny/YoloV3-tiny and FasterRCNN-like object detection models. Author Intel Corporation ... モデルのダウンロード 推論に使用するモデルを、 ホストに ダウンロードします。取得したモデルは後でコンテナにマウントして使用します。 ホストで、 ツールをインストール sudo apt-get install python3-pip python3 -m pip install openvino-dev [ onnx,tensorflow,pytorch ] DL Streamerリポジトリをクローン mkdir -p ~/intel git clone --recursive https://github.com/dlstreamer/dlstreamer.git ~/intel/dlstreamer_gst モデルの格納場所を環境変数に設定 export MODELS_PATH =/home/ ${USER} /models モデルのダウンロード ※ 時間がかかります cd ~/intel/dlstreamer_gst/samples ./download_omz_models.sh 上記は samples/models_omz_samples.lst に掲載されているモデルしかダウンロードしないため、これら以外のモデルを利用したい場合は個別でダウンロードする必要があります。 例: vehicle-detection-0200 (FP16-INT8) omz_downloader --name vehicle-detection-0200 --precisions FP16-INT8 -o $MODELS_PATH 利用可能なモデルの一覧は以下を参照してください。 参考: Supported Models — Intel® Deep Learning Streamer (Intel® DL Streamer) documentation コンテナの起動 ダウンロードしたモデルをマウントして、コンテナを起動します。今回は簡易検証のため、特権/rootかつホストのネットワーク設定で起動します。 docker run -it --rm --net host --user 0:0 --privileged \ -v /dev:/dev \ -v ${MODELS_PATH} :/home/dlstreamer/models \ --env MODELS_PATH =/home/dlstreamer/models \ intel/dlstreamer:2024. 1 .2-ubuntu22 物体検知の実行 準備ができたので物体検知を実行します。 今回は、 vehicle-detection-0200 モデルを利用して、車を検知します。 物体検知は gvadetect エレメントで行い、 model および model_proc プロパティでモデルを指定します。 gvawatermark で推論結果を映像に重畳します。 gvafpscounter は、標準出力にFPS情報を表示します。 例: カメラ映像入力(MJPEG 1280x720 30fps) モデル: vehicle-detection-0200 FP16-INT8 GPU推論 推論映像はH.264に変換して127.0.0.1:5000に配信 #!/bin/bash -eu CAMERA_PATH = ${CAMERA_PATH :- /dev/video0 } CAMERA_WIDTH = ${CAMERA_WIDTH :- 1280 } CAMERA_HEIGHT = ${CAMERA_HEIGHT :- 720 } CAMERA_FPS = ${CAMERA_FPS :- 30 } CAMERA_BITRATE = ${CAMERA_BITRATE :- 2000 } DETECTION_MODEL_NAME = ${DETECTION_MODEL_NAME :- vehicle-detection-0200 } DETECTION_MODEL = ${MODELS_PATH} /intel/ ${DETECTION_MODEL_NAME} /FP16-INT8/ ${DETECTION_MODEL_NAME} .xml DETECTION_MODEL_PROC =/opt/intel/dlstreamer/samples/gstreamer/model_proc/intel/ ${DETECTION_MODEL_NAME} .json INFERENCE_DEVICE = ${INFERENCE_DEVICE :- GPU } DETECTION_THRESHOLD = ${DETECTION_THRESHOLD :- 0.4 } OUT_PORT = ${OUT_PORT :- 5000 } gst-launch-1. 0 \ v4l2src device = ${CAMERA_PATH} ! \ videorate ! \ image/jpeg, width = ${CAMERA_WIDTH} , height = ${CAMERA_HEIGHT} , framerate = ${CAMERA_FPS} / 1 ! \ vaapijpegdec ! \ video/x-raw \( memory:VASurface \) , width = ${CAMERA_WIDTH} , height = ${CAMERA_HEIGHT} , framerate = ${CAMERA_FPS} / 1 ! \ queue ! \ gvadetect model = ${DETECTION_MODEL} \ model-proc = ${DETECTION_MODEL_PROC} \ device = ${INFERENCE_DEVICE} \ threshold = ${DETECTION_THRESHOLD} \ pre-process-backend = vaapi-surface-sharing ! \ queue ! \ gvawatermark ! \ gvafpscounter ! \ vaapih264enc rate-control = 2 bitrate = ${CAMERA_BITRATE} max-bframes = 0 keyframe-period = ${CAMERA_FPS} ! \ video/x-h264,stream-format = byte-stream ! \ queue ! \ h264parse ! \ queue ! \ rtph264pay ! udpsink host = 127 . 0 . 0 . 1 port = ${OUT_PORT} 以下のコマンドでUDPで送信された映像を表示します。 gst-launch-1. 0 -q \ udpsrc \ port = 5000 \ caps = ' application/x-rtp, media=(string)video, clock-rate=(int)90000, encoding-name=(string)H264 ' ! \ rtph264depay ! \ avdec_h264 ! \ videoconvert \ ! autovideosink DL Streamerを利用して、車を検知できました! vehicle-detection-0200で車を検知( 動画素材 ) Pythonで後処理する 以下のような動画では車ではない物体を誤検知してしまっています。 車を誤検知している例( 動画素材 ) gvapython エレメントで、推論結果を利用した後処理をPythonで記述可能です。 今回は、各フレームの物体検知結果の矩形領域(関心領域=Region of Interest、ROI)を取得し、一定以上のサイズのROIを削除する処理を追加してみます。 gstreamerパイプラインで、 gvadetect で物体検知した後に、 gvapython エレメントを追加します。 module プロパティでPythonスクリプトのパスを、 kwarg プロパティで設定ファイルを渡します。 + PYTHON_SCRIPT_ROI_FILTER=/usr/bin/roi_filter.py + PYTHON_SCRIPT_ROI_FILTER_CONFIG=/etc/roi_filter.ini ...略... gvadetect model=${DETECTION_MODEL} \ model-proc=${DETECTION_MODEL_PROC} \ device=${INFERENCE_DEVICE} \ threshold=${DETECTION_THRESHOLD} \ pre-process-backend=vaapi-surface-sharing ! \ queue ! \ + gvapython module=${PYTHON_SCRIPT_ROI_FILTER} class=ROIFilter function=process_frame kwarg={\"config_file_path\":\"${PYTHON_SCRIPT_ROI_FILTER_CONFIG}\"} ! \ gvawatermark ! \ Pythonスクリプトでは、設定ファイルからROIの設定を読み込み、一定以上のサイズのROIを削除します。 roi_filter.py from gstgva import VideoFrame import configparser class ROIFilter : def __init__ (self, config_file_path): self.config = configparser.ConfigParser() self.config.read(config_file_path, encoding= "utf-8" ) self.roi_max_width = int (self.config[ "roi" ][ "max_width" ]) self.roi_max_height = int (self.config[ "roi" ][ "max_height" ]) self.log_interval = int (self.config[ "log" ][ "interval" ]) self.frame_count = 0 def process_frame (self, frame: VideoFrame) -> bool : roi_to_be_removed = [] for roi in frame.regions(): rect = roi.rect() if rect.w > self.roi_max_width or rect.h > self.roi_max_height: roi_to_be_removed.append(roi) for roi in roi_to_be_removed: rect = roi.rect() if self.frame_count % self.log_interval == 0 : print ( f "ROI removed: " f "{roi.label()} " f "({rect.x},{rect.y}) {rect.w}x{rect.h}" ) frame.remove_region(roi) self.frame_count += 1 return True roi_filter.ini [roi] max_width = 640 max_height = 360 [log] interval = 60 上記を適用して実行します。 ROIフィルターで一定サイズ以上の検知結果を削除( 動画素材 ) Pythonスクリプトで記述した処理が実行され、一定サイズ以上のROIが削除されて正しく車を検知することができました! その他のできること DL Streamerには、今回紹介した物体検知の他にも、姿勢推定、セグメンテーションなどにも対応しており、以下のGstreamerエレメントが含まれています。 例えば、 gvametapublish は、推論結果のメタデータをファイル出力することができます。 エレメント名 説明 gvadetect オブジェクト検出を実行します。 gvaclassify オブジェクトの分類を実行します。 gvainference 任意の推論モデルを実行し、生の結果を出力します(データの解釈やメタデータの生成は行いません)。 gvaaudiodetect オーディオイベント検出を実行します。 gvatrack ビデオフレーム間でオブジェクトを追跡します。 gvametaconvert メタデータ構造をJSONまたは生テキスト形式に変換します。 gvametapublish JSONメタデータを出力します。 gvametaaggregate 複数のパイプラインブランチからの推論結果を集約します。 gvapython 各フレームでユーザー定義のPython関数を実行するコールバックを提供し、メタデータの変換や推論後処理などに使用されます。 gvawatermark メタデータをビデオフレームに重畳し、推論結果を可視化します。 gvafpscounter ビデオストリームのフレーム毎秒(FPS)を測定します。 gvaattachroi ユーザー定義の関心領域(ROI)を追加し、その領域で推論を実行します。 python_object_association ROIに一意のIDを割り当てます。 参考: Elements — Intel® Deep Learning Streamer (Intel® DL Streamer) documentation まとめ 本記事では、Intel® Deep Learning Streamerを使った映像推論の導入から実践までをご紹介しました。手順を追いながら、物体検知や誤検知への対応、Pythonでの後処理といった具体的な例も交えて解説しましたが、いかがでしたでしょうか? DL Streamerは、Intelのハードウェアを活用した映像処理にとても便利なツールで、柔軟性や拡張性にも優れています。特に、GStreamerエレメントを組み合わせることで、自分のニーズに合ったパイプラインを構築できる点が魅力的です。 また、今回はUbuntu 22.04での確認でしたが、Docker上で動作しますので、弊社がYoctoで作成したLinuxディストリビューション Terminal System OS 2 のDocker環境にもサクッと組み込むことが可能です。 この記事が、DL Streamerを使ってみるきっかけになれば幸いです。少しでも興味を持たれた方は、 サンプル も豊富ですので、ぜひ公式ドキュメントなどを参考にして、独自の映像分析パイプラインを作ってみてください!最後まで読んでいただき、ありがとうございました! *1 : 2024/5頃にはDockerイメージでインストールする方法が無かったと思うのですが、最近サポートされたようです。