TECH PLAY

アプトポッド

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

248

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イメージでインストールする方法が無かったと思うのですが、最近サポートされたようです。
アバター
aptpod Advent Calendar 2024 12月18日の記事を担当します、Roboticsグループの久保田です。 今回は、AWS EC2インスタンス間でのROS2通信を可能にする解決策として、FastDDS Discovery Serverを取り上げます。Discovery Serverは、ROS2のデフォルトのディスカバリープロトコルが抱える課題を克服し、マルチキャストパケットが利用できない環境や、LiDARデータや動画データといった大容量データを扱う高負荷なネットワークでも、効率的かつ信頼性の高い通信を可能にします。 概要 Discovery Server AWS EC2インスタンスで使用する 構成 AWS EC2インスタンス設定 リソースベースのホスト名へ変更 セキュリティグループでのUDPインバウンドを許可 FastDDS設定 Server Client 実行手順 Discovery Server起動 ROSトピックをPublish ROSトピックをSubscribe まとめ 概要 ROS2では通信相手を検出するためにDiscoveryプロトコルを使用します。このDiscoveryプロトコルはマルチキャストパケットを使用しており、ROS1のような単一障害点を持たないという利点があります。 一方で、いくつかの課題があります。 新しいノードが追加されるたびに発生するパケット数が増加し、ネットワーク負荷が高まるため、効率的なスケーリングが困難となる。 WiFiネットワーク環境やLiDARデータや動画データなどを通信する高負荷なネットワークでは、通信のパフォーマンスが低下する可能性がある。 クラウド環境や一部のネットワーク構成では、マルチキャスト通信がサポートされていない場合がある。 WiFiなどの環境では、マルチキャスト通信が安定して動作しないケースが多い。 AWS EC2インスタンス間では、マルチキャストおよびブロードキャスト通信がデフォルトではサポートされていません。これにより、ROS2のデフォルトDiscoveryプロトコルが使用するマルチキャスト通信による相手検出が機能しなくなります。この制限はAWSの仮想プライベートクラウド(VPC)の設計に起因しており、VPC内ではマルチキャストトラフィックが意図的にブロックされています。一方、AWS Transit Gatewayを利用することで、限定的にマルチキャスト通信を有効化することが可能です。ただし、この方法は高度なネットワーク設定を伴い、構成の複雑さが課題となります。これらの理由から、AWS環境でROS2のマルチキャスト通信を実現する際には、設定の複雑さと技術的制約を十分に考慮する必要があります。 そこで、FastDDSがDiscoverプロトコルの代替として用意しているDiscovery Serverを使用します。Discovery Serverは、ROS2ノード間の通信を管理するための集中型サーバーとして機能します。このサーバーは、各ノードのメタデータ(場所、アドレス、ポート情報など)を保存し、他のノードが必要な情報を効率的に取得できるようにします。 Discovery Server ROS 2におけるDiscovery Serverは、ネットワーク上のノード間の発見と通信を効率化するための集中型メカニズムです。Fast DDSが提供するDiscovery Serverは、従来の分散型Discoveryプロトコルに代わり、クライアント-サーバーアーキテクチャを採用しています。 docs.ros.org Discovery Serverを使用する以下の利点があります ネットワークトラフィックの削減 : デフォルトのDiscoveryプロトコルが生成する大量のマルチキャストトラフィックを削減し、ネットワークの負荷を軽減します。 マルチキャスト非対応環境での利用 : AWS VPCやその他のマルチキャスト非対応の環境でも動作可能です。 一方で、デメリットも留意する必要はあります 単一障害点のリスク : Discovery Serverは単一障害点となる可能性があり、冗長構成を考慮する必要があります。 負荷の集中 : Discovery Serverに負荷が集中するため、適切なリソース(CPU、メモリ、ネットワーク帯域など)を割り当てることが推奨されます。 管理の手間 : サーバーの監視や障害対応のために、追加の管理作業が必要となります。 AWS EC2インスタンスで使用する 構成 AWS EC2インスタンス設定 リソースベースのホスト名へ変更 Discovery ServerのIPアドレスをLocal DNSから取得するためにリソースベースのホスト名へ変更しておくと便利です。これにより、DNSリゾルバを利用してIPアドレスを動的に管理できるため、固定IPアドレスの手動設定が不要となります。 「アクション」=> 「インスタンスの設定」=> 「リソースベースの命名オプションを変更」 リソースベースの命名オプションを変更 セキュリティグループでのUDPインバウンドを許可 Discovery Serverとの通信のために、UDPプロトコルのインバウンド通信を許可しておきます。これは、ROS2ノード間でのDiscovery Serverとのメタデータ交換を可能にするために必要です。 「インスタンス」=> 「セキュリティ」タブ=>「セキュリティグループ」=>「インバウンドのルールを編集」 インバウンドのルールを編集 FastDDS設定 Discovery Serverを使用するために、Server/ClientそれぞれにFastDDSの設定が必要です。Fast DDSの設定は、設定ファイルfastrtps-profile.xmlを作成し、環境変数 (FASTRTPS_DEFAULT_PROFILES_FILE) で指定します。 通信相手を検出するため、Discovery ServerのIPアドレス(ホスト名)および使用するポート番号を設定ファイルに記載してください。 Server fastrtps-profile.xml <? xml version = "1.0" encoding = "UTF-8" ?> <profiles xmlns = "http://www.eprosima.com/XMLSchemas/fastRTPS_Profiles" > <transport_descriptors> <transport_descriptor> <transport_id> CustomUdpTransport </transport_id> <type> UDPv4 </type> </transport_descriptor> </transport_descriptors> <participant profile_name = "participant_profile" is_default_profile = "true" > <rtps> <userTransports> <transport_id> CustomUdpTransport </transport_id> </userTransports> <useBuiltinTransports> false </useBuiltinTransports> <prefix> 44.53.00.5f.45.50.52.4f.53.49.4d.41 </prefix> <builtin> <discovery_config> <discoveryProtocol> SERVER </discoveryProtocol> </discovery_config> <metatrafficUnicastLocatorList> <locator> <udpv4> <address> i-05a0c3018209bc88b.ap-northeast-1.compute.internal </address> <port> 11811 </port> </udpv4> </locator> </metatrafficUnicastLocatorList> </builtin> <sendSocketBufferSize> 31457280 </sendSocketBufferSize> <listenSocketBufferSize> 31457280 </listenSocketBufferSize> </rtps> </participant> </profiles> Client fastrtps-profile.xml <? xml version = "1.0" encoding = "UTF-8" ?> <profiles xmlns = "http://www.eprosima.com/XMLSchemas/fastRTPS_Profiles" > <transport_descriptors> <transport_descriptor> <transport_id> CustomUdpTransport </transport_id> <type> UDPv4 </type> </transport_descriptor> </transport_descriptors> <participant profile_name = "participant_profile" is_default_profile = "true" > <rtps> <userTransports> <transport_id> CustomUdpTransport </transport_id> </userTransports> <useBuiltinTransports> false </useBuiltinTransports> <builtin> <discovery_config> <discoveryProtocol> SUPER_CLIENT </discoveryProtocol> <discoveryServersList> <RemoteServer prefix = "44.53.00.5f.45.50.52.4f.53.49.4d.41" > <metatrafficUnicastLocatorList> <locator> <udpv4> <address> i-05a0c3018209bc88b.ap-northeast-1.compute.internal </address> <port> 11811 </port> </udpv4> </locator> </metatrafficUnicastLocatorList> </RemoteServer> </discoveryServersList> </discovery_config> </builtin> <sendSocketBufferSize> 31457280 </sendSocketBufferSize> <listenSocketBufferSize> 31457280 </listenSocketBufferSize> </rtps> </participant> </profiles> XMLタグの説明 タグ名 説明 <transport_descriptors> 通信に使用するトランスポートの設定を指定します。 <transport_descriptor> トランスポートの詳細(IDやタイプなど)を設定します。 ここではUDPを指定しています <participant> ROS2ノードのプロファイル設定を指定します。この設定には、トランスポート、バッファサイズ、Discoveryプロトコルなどが含まれます。 <prefix> Discovery ServerのGUIDをしていします。 <discovery_config> Discovery Serverのプロトコルやサーバー情報を設定します。このタグを使用して通信方式(SERVER/SUPER_CLIENTなど)やリモートサーバーリストを定義します。 <discoveryProtocol> Discovery Serverの動作モードを定義します(例: SERVERはサーバーとして、SUPER_CLIENTはクライアントとして機能)。 <discoveryServersList> Discovery Serverのリストを定義します。これにより、クライアントノードがどのサーバーに接続するかを指定できます。 <metatrafficUnicastLocatorList> メタトラフィック通信に使用するロケータリストを指定します。このロケータリストは、Discovery Serverがクライアントノードと通信するためのIPアドレスやポート番号を定義します。これにより、特定のネットワーク設定に基づいて通信経路を明示的に管理できます。 実行手順 AWS EC2インスタンスを構築後、動作を確認していきます。 Discovery Server起動 Discovery Serverでの通信相手の検出のために、まずDiscovery Serverを起動します。起動時には、ROS DOMAIN IDや通信相手検出の通信のためのポート番号などが設定できます。 $ docker run -it --rm --name ros-server \ --net=host \ -e FASTRTPS_DEFAULT_PROFILES_FILE=/tmp/fastrtps-profile.xml \ -v ./fastrtps-profile.xml:/tmp/fastrtps-profile.xml \ ros:humble \ fastdds discovery --server-id 0 ### Server is running ### Participant Type: SERVER Server ID: 0 Server GUID prefix: 44.53.00.5f.45.50.52.4f.53.49.4d.41 Server Addresses: UDPv4:[0.0.0.0]:11811 ROSトピックをPublish トピックをPublishするために、FastDDS設定が必要です。環境変数 (FASTRTPS_DEFAULT_PROFILES_FILE) で指定してください。 $ docker run -it --rm --name rospub \ --net=host \ -e FASTRTPS_DEFAULT_PROFILES_FILE=/tmp/fastrtps-profile.xml \ -v ./fastrtps-profile.xml:/tmp/fastrtps-profile.xml \ ros:humble \ ros2 topic pub /my_topic std_msgs/msg/String '{data: "hello"}' publisher: beginning loop publishing #1: std_msgs.msg.String(data='hello') publishing #2: std_msgs.msg.String(data='hello') publishing #3: std_msgs.msg.String(data='hello') ROSトピックをSubscribe トピックをSubscribeするために、FastDDS設定が必要です。環境変数 (FASTRTPS_DEFAULT_PROFILES_FILE) で指定してください。 $ docker run -it --rm --name rossub \ --net=host \ -e FASTRTPS_DEFAULT_PROFILES_FILE=/tmp/fastrtps-profile.xml \ -v ./fastrtps-profile.xml:/tmp/fastrtps-profile.xml \ ros:humble \ ros2 topic echo /my_topic data: hello --- data: hello --- data: hello --- SubscribeしたROSトピックが表示され、ROS2通信が問題なく動作しました。Discovery Serverを使うことで、AWS EC2インスタンス間でもROS2通信が実現できることが確認できました。 まとめ 今回は、AWS EC2インスタンス間でのROS2通信を実現する方法として、FastDDS Discovery Serverを活用する手法を紹介しました。このソリューションは、マルチキャストパケットが使用できない環境において有効であるだけでなく、LiDARデータや動画データの通信時にネットワーク負荷を低減する効果も期待できます。ROS2の通信性能や動作環境の最適化を目指す際に、ぜひ参考にしてみてください。
アバター
aptpod Advent Calendar 2024 12月17日の記事です。 RoboticsグループでROSやロボット関連の開発を担当している影山です。 今日は、REST APIを利用して、リソースの限られた組み込みデバイスから、弊社のintdashへリアルタイムで映像をアップロードしてそれをブラウザで確認する方法について紹介したいと思います。 概要 利用するエッジデバイスについて ESP32を利用する理由 Timer Camera X の開発環境 Timer Camera Xのサンプルコードのビルド REST APIによるアップストリーム ESP32上での実装 実装時の注意点 動かしてたみた様子 まとめ 参考:JPEG送信部分のC++コード抜粋 概要 intdashを利用するために、弊社はPythonやTypeScript、Rustなど色々な言語に対応した SDK を準備してます。 SDKを利用するには、基本的にそれぞれの言語やビルドしたバイナリが実行できる環境が必要になります。 そのため基本的にはPCやJetsonのようなLinuxが動作するデバイス上での利用が前提となります。 弊社では、プログラミングによるSDKの他にもREST APIを利用してintdashサーバとのデータの送受信を行う方法も提供しています。 REST APIであれば、よりリソースの限られたデバイスでも利用できる可能が広がります。今回は、その一例として、ESP32を搭載した小さなカメラを使って、撮影した映像をリアルタイムでintdashに送信して、ブラウザで映像を確認してみたいと思います。 利用するエッジデバイスについて TimerCamera X 今回は、ESP32を搭載したTimer Camera X を利用して、映像のアップストリームを確認してきたいと思います。 Timer Camera Xは、 Amazon や Switch Science などで販売しています。 ESP32を利用する理由 ESP32は、WiFi機能を搭載しており、HTTPS通信を始めとした、各種APIに対応したSDK( ESP-IDF )を提供しています。 intdashとREST API通信するには、HTTPSを用いるので、ESP32のSDKを使えばintdashとの接続が実現できそうなので、選択しました。 今回はESP32とカメラが一体化したTimer Camera Xを利用しましたが、ESP32は、I2CやSPIに対応しており、カメラ以外の色々なセンサやデバイスと組み合わせ使うことも容易です。 Timer Camera X の開発環境 今回はESP-IDFを用いて開発していきます。 Timer Camera Xについての詳細は、 公式のドキュメント が参考になります。 ビルドやテスト環境にはDockerを利用しています。開発環境の話については筆者の ブログ で触れていますので、興味があればご参照ください。 Timer Camera Xのサンプルコードのビルド まずはサンプルコードで動作を確認します。 検索するといくつかTimer Camera X向けのサンプルが見つかりますが、古いものもあるので、現在は、以下のサンプルを利用するのが良いようです。 github.com ESP-IDF環境でhttp-streamというサンプルをビルドします。 最新のESP-IDFではビルド時にエラーが起きたので、 v4.4.8 を利用しています。 ビルドとフラッシュが上手くいくと、Timer Camera Xが起動したHTTPサーバのアドレスをブラウザで開くことで、リアルタイムでカメラの映像を確認できます。 今回はこのサンプルをベースにREST API over HTTPSで、撮影した画像をリアルタイムでintdashに送信していきます。 REST APIによるアップストリーム 基本的なREST APIの使い方については、別の記事で ATOM Lite 上でMicroPythonを用いた例を紹介しているので、そちらをご参照ください。 tech.aptpod.co.jp まずはcurlコマンドを使ったシェルスクリプトでJPEGを送信する動作を確認してから、それをESP32に移植していきます。 画像はBASE64エンコードする必要ある点に注意必要です。以下は2枚のJPEG画像を交互に送信する処理を抜粋したサンプルです。 function send_chunk_jpg() { local base_time=$1 local stream_id=$2 local jpg_file="./1.jpg" for i in {1..10}; do if (( i % 2 == 1 )); then jpg_file="./1.jpg" else jpg_file="./2.jpg" fi echo "$jpg_file" local encoded_jpg=$(base64 -w 0 "$jpg_file") local body_file=$(mktemp) local send_time send_time=$(date +%s%N) cat <<EOF > "$body_file" { "data_point_groups": [ { "data_id": { "type": "jpeg", "name": "10/image" }, "data_points": [ { "elapsed_time": $((send_time - base_time)), "payload": "$encoded_jpg" } ] } ] } EOF curl \ -H "Content-Type: application/json" \ -H "Authorization: Bearer $access_token" \ -X POST \ --data @"$body_file" "${base_url}/api/iscp/projects/${project_uuid}/upstreams/${stream_id}/chunks" | jq . sleep 0.5 done } ESP32上での実装 先ほどのcurlを使った手順を参考に、ESP-IDFのマニュアルを参照しつつ、ESP-IDFのAPIを使った実装にしていきます。 今回、使用している主なESP32のHTTPSに関係するAPIは以下の通りです。使い方は マニュアル に記載があります。 esp_http_client_init() esp_http_client_set_header() esp_http_client_set_post_field() esp_http_client_open() esp_http_client_write() esp_http_client_fetch_headers() esp_http_client_read_response() esp_http_client_cleanup() 基本的には、HTTPヘッダの設定、HTTPS接続、Bodyの書き込み、レスポンスの解析、終了処理、という順番で処理していきます。 コードの全体は掲載するには長いので、データ送信部分を抜粋したサンプルコードを記事の末尾に記載してます。 実装時の注意点 ESP32での実装時、以下のようなポイントに注意が必要です。 カメラの映像はサイズが大きいので、menuconfigで、ESP32のPSRAM機能を有効にすることが必要です。 Timer Camera XにはPSRAM 8Mが搭載されており、ESP32の内蔵SRAM 512KBよりも大幅に多くのメモリを利用できますが、アクセス速度が遅い点には留意が必要です 画像の送信時には、タイムスタンプを設定する必要があります。そのため今回はESP-IDFが提供する esp_sntp.h を利用しています。 動かしてたみた様子 実際にリアルタイムで撮影してみた様子です。 パソコンの前でTimer Camera Xを構えて、現在時刻が表示されたData Visualizerの画面を撮影しています。 アップストリーム動作確認 動画内の画面右枠に表示されているのが、Timer Camera Xからアップストリームされた映像です。 Data Visualizer上でのTimer Camera Xで撮影した映像表示 実際に試してみると1枚のJPEGの送信に時間がかかるため、滑らかな表示とまではいきませんでしたが、定期的な映像のアップストリームが確認できました。 まとめ ESP32を搭載したカメラデバイスを使って、intdashにリアルタイムで画像を送るサンプルを実装しました。 滑らかな動画を送ることは難しかったですが、一定間隔で撮影した画像をパラパラアニメのような感じで送信することには使えそうでした。 高性能なエッジデバイスを準備しなくても、intdashとの連携ができるので、REST APIを利用することで、ユースケースの幅を広げることができると思います。 この記事を見て、エッジデバイスとクラウドの連携技術について、ご興味を持たれた方は窓口からご相談頂ければ幸いです。 www.aptpod.co.jp 参考:JPEG送信部分のC++コード抜粋 void send_chunk(const char *base_url, const char *project_uuid, const char *stream_id, int64_t base_time) { char url[256]; snprintf(url, sizeof(url), "%s/api/iscp/projects/%s/upstreams/%s/chunks", base_url, project_uuid, stream_id); camera_fb_t *fb = NULL; size_t _jpg_buf_len; uint8_t *_jpg_buf; int err_count = 0; char *base64_buf = NULL; size_t base64_len; for (int i = 1; i <= 100; i++) { //100枚送信する int64_t send_time = esp_timer_get_time() * 1000; // マイクロ秒をナノ秒に変換 // カメラのフレームバッファ取得 fb = esp_camera_fb_get(); if (!fb) { ESP_LOGE(TAG, "Camera capture failed"); err_count++; if(err_count>10){ return; }else{ vTaskDelay(500 / portTICK_PERIOD_MS); continue; } } if (fb->format != PIXFORMAT_JPEG) { bool jpeg_converted = frame2jpg(fb, 80, &_jpg_buf, &_jpg_buf_len); if (!jpeg_converted) { ESP_LOGE(TAG, "JPEG compression failed"); esp_camera_fb_return(fb); return; } } else { _jpg_buf_len = fb->len; _jpg_buf = fb->buf; } // Base64エンコード用のバッファを確保 size_t encoded_len = 4 * ((_jpg_buf_len + 2) / 3) + 1; base64_buf = (char *)malloc(encoded_len); if (!base64_buf) { ESP_LOGE(TAG, "Failed to allocate memory for Base64 buffer"); if (fb->format != PIXFORMAT_JPEG) { free(_jpg_buf); } esp_camera_fb_return(fb); return; } // Base64エンコード int ret = mbedtls_base64_encode((unsigned char *)base64_buf, encoded_len, &base64_len, _jpg_buf, _jpg_buf_len); if (ret != 0) { ESP_LOGE(TAG, "Base64 encoding failed with error code: %d", ret); free(base64_buf); if (fb->format != PIXFORMAT_JPEG) { free(_jpg_buf); } esp_camera_fb_return(fb); return; } // 送信 // JSON全体のサイズを計算してメモリを確保 size_t json_size = snprintf(NULL, 0, JSON_FORMAT, send_time - base_time, base64_buf) + 1; char *body = (char *)malloc(json_size); if (!body) { ESP_LOGE(TAG, "Failed to allocate memory for JSON body"); free(base64_buf); if (fb->format != PIXFORMAT_JPEG) { free(_jpg_buf); } esp_camera_fb_return(fb); return; } snprintf(body, json_size, JSON_FORMAT, send_time - base_time, base64_buf); esp_http_client_config_t config = { .url = url, .crt_bundle_attach = esp_crt_bundle_attach, .buffer_size = 2048, .buffer_size_tx = 2048, .method = HTTP_METHOD_POST, }; esp_http_client_handle_t client = esp_http_client_init(&config); esp_http_client_set_header(client, "Content-Type", "application/json"); esp_http_client_set_header(client, "Accept-Encoding", "identity"); esp_http_client_set_header(client, "Authorization", access_token); esp_http_client_set_post_field(client, body, strlen(body)); esp_err_t err = esp_http_client_open(client,strlen(body)); if( err != ESP_OK) { ESP_LOGE(TAG, "Failed to open HTTP connection: %s", esp_err_to_name(err)); esp_http_client_cleanup(client); free(base64_buf); free(body); if (fb->format != PIXFORMAT_JPEG) { free(_jpg_buf); } esp_camera_fb_return(fb); continue; } int wlen = esp_http_client_write(client, body, strlen(body)); if (wlen >= 0) { ESP_LOGI(TAG, "Chunk %d sent successfully, elapsed:%lld", i, send_time - base_time); } else { ESP_LOGE(TAG, "HTTP request failed: %s", esp_err_to_name(err)); } // メモリ開放 esp_http_client_cleanup(client); free(base64_buf); free(body); if (fb->format != PIXFORMAT_JPEG) { free(_jpg_buf); } esp_camera_fb_return(fb); } }
アバター
aptpod Advent Calendar 2024 12月16日を担当するintdashグループの呉羽です。 弊社が提供する intdash は動画データをアップロードすることで、HLSやMP4への変換や、Webブラウザ上での閲覧機能を提供しています。 そこで今回は動画を使ったネタとして『 Pythonを使って動画ファイルから顔を検出し、人物ごとにグループ分けするプログラム 』をご紹介します。 動画内の顔を認識して分類することで、誰がどのシーンに現れるかを把握することが可能です。 Pythonライブラリ face_recognition について プログラム全体の流れ 動画ファイルからフレームを順に読み取る。 フレームから顔の検出を行う。 過去に検出した顔と比較し、同一人物かどうかを判定する。 検出した顔の画像を保存する。 まとめ Pythonライブラリ face_recognition について 今回用いる face_recognition は、Pythonで顔認識を行うためのライブラリです。このライブラリは、 dlib という機械学習ライブラリの顔認識モデルをベースにしており、以下の機能を提供します。 顔の検出(位置の特定) 顔のエンコード(特徴量の抽出) 顔同士の類似度計算(同一人物の判定) インストール方法は face_recognitionのGitHubリポジトリ を参考にします。基本的にはPythonのパッケージ管理ツール pip でインストールするだけです。今回は v1.2.2 を用います。 プログラム全体の流れ 以下に、プログラムの流れを説明します。 動画ファイルからフレームを順に読み取る。 フレームから顔の検出を行う。 過去に検出した顔と比較し、同一人物かどうかを判定する。 検出した顔の画像を保存する。 実装したコードはGitHubで公開しています。 github.com 今回はサンプル動画として、フリー素材として公開されているこちらの動画を利用します。動画内でいくつかの人物がディスカッションしている様子が伺えます。 pixabay.com 動画ファイルからフレームを順に読み取る。 Pythonで動画ファイルのフレームを読み取るために opencv-python を使います。以下のようにフレームを順に読み取れます。 import cv2 path_to_video = "./xxx.mp4" video_capture = cv2.VideoCapture(path_to_video) while video_capture.isOpened(): ret, raw_frame = video_capture.read() if not ret: print ( "Video file ended" ) break 全てのフレームを取得すると、例えば30FPSかつ5分間の動画のフレーム数はおよそ9,000になります。ここでは処理の軽量化のため、以下のように約2秒間隔のフレームごとに処理します。 fps = video_capture.get(cv2.CAP_PROP_FPS) frame_count = 0 while video_capture.isOpened(): frame_count += 1 # take a frame every 2 seconds if frame_count % int (fps* 2 ) != 0 : continue フレームから顔の検出を行う。 face_recognition.face_locations() にフレームを渡すことで、そのフレーム内の全ての顔の位置を検出できます。以下はフレーム内の顔の全ての位置情報を出力するコードです。 import face_recognition face_locations = face_recognition.face_locations(frame) print ( "Found {} face(s) in frame #{}." .format( len (face_locations), frame_count)) for i in range ( len (face_locations)): face_location = face_locations[i] top, right, bottom, left = face_location face_size = (right - left) * (bottom - top) print ( " - A face is located at pixel location Top: {}, Left: {}, Bottom: {}, Right: {}, Size: {}" .format(top, left, bottom, right, face_size)) 過去に検出した顔と比較し、同一人物かどうかを判定する。 次に face_recognition.face_encodings() を使い、顔を比較するための特徴量を計算します。そして face_recognition.face_distance() を使うことで、2つ顔の特徴量の距離 [0,1] (小さいほど類似している)を計算できます。 これを用いて、ある閾値(ここでは 0.6 )以下の場合に同一人物と判定し、グループ分けします。 face_groups = [] # list of face encodings face_encodings = face_recognition.face_encodings(frame, face_locations) for i in range ( len (face_locations)): face_location = face_locations[i] face_encoding = face_encodings[i] group_id = - 1 if len (face_groups) > 0 : distances = face_recognition.face_distance(face_groups, face_encoding) if np.min(distances) < 0.6 : # threshold to consider the face as the same person group_id = np.argmin(distances) if group_id == - 1 : # create a new group face_groups.append(face_encoding) group_id = len (face_groups) - 1 検出した顔の画像を保存する。 検出した顔の画像を、人物(グループ)ごとにディレクトリに保存します。分かりやすいように、フレームの経過時間をファイル名として保存しています。 name = "./output/{}/{}/{}.jpg" .format(output_dir, group_id, time.strftime( "%H_%M_%S" , frame_time)) os.makedirs(os.path.dirname(name), exist_ok= True ) face = raw_frame[top:bottom, left:right] cv2.imwrite(name, face, [ int (cv2.IMWRITE_JPEG_QUALITY), 95 ]) サンプル動画では5人の人物が検知されました。例えば、ある一つのディレクトリに保存された画像は以下のようになりました。 結果の例 他のディレクトリを見てみると、同一人物の誤判定があるようでした。これを解消するためには、手動で閾値を調整する必要があります。 他の人物と混同している例 まとめ 本記事では、Pythonを使った動画内の顔検出・分類プログラムを解説しました。このプログラムをさらに改善・発展させるには、以下のような方法が考えられます。 GPUを使った高速な処理 dlib をインストールする際にNVIDIA CUDAを有効化すればより高速に処理ができます。 高度なグループ分け k-means法を使えば、人物数(グループ数)を指定しつつ精度良く分類できます。 リアルタイム処理への対応 Webカメラなどのライブ映像から直接顔を検出するように変更することで、リアルタイムでの分析が可能になります。 また弊社が提供する intdash を活用することで、intdashからの動画ストリーミングをリアルタイム処理したり、得られたデータを別途保存したりすることが可能です。ぜひこのプログラムを参考にオリジナルのアプリケーション開発に挑戦してみてください。
アバター
aptpod Advent Calendar 2024 12月13日の記事を担当します、ソリューションアーキテクトの門脇です。 今回はintdash を活用し、取得した時系列データの分析にフォーカスします。簡易的な例として計測データの傾向を可視化するための分析ボード 構築手法を共有します。 そして計測から分析可視化までのプロセスを自動化します。 今回の要件 概要構成 intdashとは? intdash Motionとは? 分析ボードの構築プロセス intdash APIを使ったデータ取得 データ分析 データアップロード 分析ボード作成 結果とメリット おわりに 今回の要件 1週間の歩行イベントにおける、5名の歩行距離を可視化したい。 計測>分析>可視化のプロセスを、出来る限りシンプルな構成で自動化したい。 概要構成 概要構成を示します。 計測はiPhoneにインストールした indash Motion V2 で行います。 分析したデータの可視化ツール(BIツール)には LookerStudio を使用します。 概要構成 intdashとは? intdash は、様々なIoTデータを低遅延に伝送するハイパフォーマンスなデータ伝送ミドルウェアです。産業用バスなどの秒間数百〜数千点にもなる大量データにも対応。独自開発のプロトコルにより、帯域の細いモバイル回線でも確実かつリアルタイムにデータ伝送が可能です。 intdash Motionとは? intdash Motion は、本格的なIoTデバイス導入前のPoCやトライアル用途でご利用いただける、簡易データ収集用スマートフォンアプリです。スマートフォンに搭載された加速度センサーやジャイロスコープ、GPS、カメラやマイクといった各種センサーを利用して、簡易的な実験を行うことができます。 分析ボードの構築プロセス 今回のプロジェクトは以下の流れで進めます。 intdash APIを使ったデータ取得 データ分析 データアップロード 分析ボード作成 intdash APIを使ったデータ取得 分析には、intdash Motion V2アプリから送信されるGNSSデータを利用します。 GNSSデータ intdash APIで計測データを取得します。 # 計測の取得 def get_measurements (edge_uuid: str , start: pd.Timestamp, end: pd.Timestamp) -> list [ dict ]: measurements = [] page = 1 while True : resp = get( path=f "/v1/projects/{PROJECT_UUID}/measurements" , params={ "edge_uuid" : edge_uuid, "start" : start.tz_convert( 'utc' ).strftime( "%Y-%m-%dT%H:%M:%S.%fZ" ), "end" : end.tz_convert( 'utc' ).strftime( "%Y-%m-%dT%H:%M:%S.%fZ" ), "page" : page, }, ) for meas in resp[ "items" ]: measurements.append(meas) if resp[ "page" ][ "next" ]: page += 1 else : break return measurements # 時系列データの取得 def get_data_points (meas_uuid: str , idq: list [ str ]) -> list [ dict ]: resp = requests.get( url=INTDASH_URL + f "/api/v1/projects/{PROJECT_UUID}/data" , headers=HEADERS, params={ "name" : meas_uuid, "idq" : idq, "time_format" : "ns" , }, stream= True , ) resp.raise_for_status() data_points = [] received = "" for chunk in resp.iter_content(chunk_size= None , decode_unicode= True ): received += chunk for line in received.split( " \n " ): try : decoded = json.loads(line) data_points.append(decoded) except ValueError : received = line break return data_points # DataFrameに変換 def convert (data_point: dict ) -> list [ dict ]: match data_point[ "data_name" ]: case "0/gnss_speed" : bin = base64.b64decode(data_point[ "data" ][ "d" ]) value = struct.unpack( ">d" , bin )[ 0 ] return [{ "time" : data_point[ "time" ], "name" : "GNSS_Speed" , "value" : value, }] case _: raise ValueError (f "Unsupported data_type: {data_point['data_type']}" ) データ分析 次に、各計測ごとにデータ分析を行います。 速度の分析値と、速度を基にした移動距離を計算しています。 def analyze_gnss_speed (df: pd.DataFrame) -> dict : # タイムスタンプをdatetime型に変換 df.index = pd.to_datetime(df.index) # 開始時刻と終了時刻 start_time = df.index.min() end_time = df.index.max() # 時間間隔を計算(秒単位から時間単位に変換) time_deltas = df.index.to_series().diff().dt.total_seconds() time_deltas_in_hours = time_deltas / 3600 # 時間単位に変換 # 移動距離の計算 distances = df[ "GNSS_Speed" ] * time_deltas_in_hours # km/h × 時間 = km total_distance = distances.sum() # スピードの分析値 speed_stats = { "mean_speed" : df[ "GNSS_Speed" ].mean(), "median_speed" : df[ "GNSS_Speed" ].median(), "max_speed" : df[ "GNSS_Speed" ].max(), "min_speed" : df[ "GNSS_Speed" ].min(), "range_speed" : df[ "GNSS_Speed" ].max() - df[ "GNSS_Speed" ].min(), "std_speed" : df[ "GNSS_Speed" ].std(), "time_of_peak_speed" : df[ "GNSS_Speed" ].idxmax(), } # 分析結果のまとめ analysis = { "start_time" : start_time, "end_time" : end_time, "total_distance" : total_distance, **speed_stats, } return analysis データアップロード 今回はGoogle スプレッドシートをデータソースにしてLookerStudioで可視化を行います。 スプレッドシートへのデータアップロードは GoogleAPI を使います。 プロセス図 1行1計測で集約した分析データをデータソースにします。 分析データ 分析ボード作成 Looker Studioで歩行傾向を可視化します。 作成した分析ボード1 作成した分析ボード2 結果とメリット 完成した分析ボードでは、以下の成果が得られました。 データの即時可視化: 最新の計測データがダッシュボードで即座に確認可能。 コラボレーションの向上: Looker Studioで共有機能を利用し、チーム全体でデータを分析。 自動化の実現: 定期的なデータ更新が自動化され、作業時間を大幅に削減。参加者が何人増えても集計分析の手間は増えません。 おわりに 今回のプロジェクトを通じて、計測したデータを自動で可視化する仕組みを構築できました。 intdash を使う事で、IoTデータ活用の可能性がさらに広がります。ぜひ、貴社の課題解決にもご活用ください。 ご興味のある方は、 intdash 無償トライアル からお申込みいただき、実際にその効果を体験してみてください。
アバター