TECH PLAY

アプトポッド

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

248

Aptpod Advent Calendar 2022 23日目の記事です。(※土日休みにしているので最終日です) CTOの梶田です。 今年もまたあっという間(いつも言ってますね💦)でAdvent Calendar もなんとか走りきれそうです。 (昨年に引き続き継続するのは大変だなーと痛感していますが、なんとかみんな頑張った💪) 今年はAdvent Calendar も5年目となり、なんか新しいカタチにしようかどうか悩んだのですが、今年も例年通り、 1日目の神前の記事 でも触れられていますが。。。 1日目の記事抜粋 12月ですし、年末ネタとして(勝手に)定着させようとしているので2022年も 昨年 と同様に振り返ろうと思います! ではでは始めます。 (ちょっとタイトルの "また" が多いなw) はじめに MVV パートナー活動 Amazon販売 ソリューションパッケージ 2023年に向けて はじめに 2022年も昨年に引き続き、COVID-19は終息することなく、新しい働き方が標準になりつつあります。 (といってもTwitter社のようにリモートワークは終焉し、出社が強制みたいなところも出てきつつありますね💦) 2022年は、ロシアのウクライナ侵攻と関連する材料/資源不足、物価高(まだまだ高くなりそうですが。。)、為替変動、円安。。。と(他にもいろんなことありましたが) 社会の不安定感が増すなか、弊社としてもなかなか難しい局面は続き、攻めというよりはさらなる守り(投資の抑制、財務の健全化等々)へのシフト。。。 となかなか痺れる1年だったのですが、 5月、6月ぐらいにスタートアップに冬の時代がやってきたというのがちらほら出始めていたころ、、 SmartHR創業者の宮田さんの記事 blog.shojimiyata.com には、特に走り続けるチカラをもらいました💪 (社内でも "全員必読" みたいなかたちで少しだけ広まりましたw 😅) 中でも 変化に適応し続ける奴が一番強い というところと スタートアップがキーを打っている最中に死ぬことはめったにないのだ。だからキーを打ち続けよう! というところは、特に自分の中では心に留めています。 といったところで、 今年のトピックをいくつかピックアップして書いていきます。 MVV パートナー活動 Amazon販売 ソリューションパッケージ MVV 会社として、いわゆるMVV(ミッション・ビジョン・バリュー)を今年公開し、HP(ホームページ)を刷新しました。 youtu.be もともと内部的にはうっすらしてたものですが、言語化され公開されたことで意識しやすくなり、 また、バリューの浸透も含めての施策もいくつかされて、意識することも増えたのかなと感じてはいます。 (なかなか策定や公開までも紆余曲折ありつつ、まつわる施策についても試行錯誤の連続で。。。これだけの言葉だけで終わるのもなんともですが😓) パートナー活動 今年は特にこのパートナー各社様との協業、共創活動へのシフトを意識しました。 リリースとしても、 2022.05.30 アプトポッド、様々な分野のパートナーとの協業で産業DX支援を加速 を中心に各社様との活動をリリースさせていただきました。 2022.01.11 ax株式会社のAIソリューション「ailia」がintdashに対応 2022.02.02 アプトポッドとアクロクエストテクノロジー マルチモーダルデータによるAI/IoTソリューション提供で協業 2022.09.07 アプトポッドとオルフェ 動作分析ソリューション提供で協業 2022.10.20 アプトポッド、NECと5Gを活用したユースケースの創出に向けて連携 また、技術面においては、NTTコミュニケーションズ様やマクニカ様とも技術的な共創活動も今年から始めており、来年以降のどこかでお知らせできることを楽しみにしています。 マクニカ様においては、今回のAdvent Calendar2022の岩田の記事 tech.aptpod.co.jp でも触れられています MET2022(Macnica Exponential Technology 2022) というオンラインイベントにおいても弊社との取り組みをご紹介させていただいています。 内容は下記をご覧ください。 met.macnica.co.jp Amazon販売 ちょっと毛色の違うところで軽いものを。 新しい試みとして、こちらのリリースの通り、 2022.05.09 アプトポッド、推論や機械学習の実行環境に最適なエッジコンピュータ EDGEPLANT T1 を、Amazon で販売開始 昨年販売開始をした EDGEPLANT T1 を今年Amazonのプラットフォームで買えるようにしました。 www.amazon.co.jp こういうかたちで見えるとより身近な感じがしてよいですね! 買う敷居が下がり、こちらをきっかけに使っていただく機会が広がってきつつあるのは嬉しい限りです。 ソリューションパッケージ 今年の試みとして大きなもので最近発表しています 2022.12.06 アプトポッド、モビリティやロボットの群管理・遠隔制御の ソリューションフレームワークをベータリリース にありますようにintdashをバックエンドに使用したソリューションとして、最近新しいプロダクトをいくつか発表しました。 よりワークフローやユースケースに寄り添ったソリューションでお客様やパートナー様へ活用しやすくする狙いで進めています。 今回のAdvent Calendar 2022でも記事となっておりますので是非ご覧ください。 13日目:【intdash AUTOMOTIVE PRO REMOTE CAL】ECU遠隔適合システムのご紹介 tech.aptpod.co.jp 15日目:モビリティ管制制御システム向けソリューション「intdash CONTROL CENTER」を紹介します tech.aptpod.co.jp 2023年に向けて 2022年もまた期待の通りというわけではなく、むしろ大きな変化の荒波に対してどう対峙していくかといったところが試されたような気がしています。 やることすべてが必ずしもうまくいかず、パートナー様との共創活動も含め、なかなか難しいことも多かった年ではありましたが、少しづつ芽となっているものもあり、また製品としては進化しているところもたくさんあります。 2023年はさらなる広がりに向けて、お客様およびパートナー様との共創をさらに深く、広げていきたいと思っております。 何か自社の製品と連携できそうとかこんな困りごとがあるといったお客様やパートナー様は以下からお問い合わせいただけると幸いです。 aptpod,Inc. Contact aptpod,Inc. Contact for Partners 再掲になりますが、上記の宮田さんの記事の 変化に適応し続ける奴が一番強い というところと スタートアップがキーを打っている最中に死ぬことはめったにないのだ。だからキーを打ち続けよう! というところを意識しつつ2023年も走り続けていきたいと思っています💪 来年もまたアプトポッドにご期待ください!! メリークリスマス!🎄
アバター
aptpod Advent Calendar 2022 も、22日目になりました。本日は、ドキュメント担当の篠崎がお届けします。 私は、社内で1人だけの「ドキュメント担当」 *1 として、社外に公開するマニュアルや技術ドキュメントの制作を行っています。 ドキュメントは新製品・新機能のリリースに合わせて制作しますので、私は、新製品・新機能の開発担当者 *2 と常にコミュニケーションをとりながらリリースまでの作業を進めています。 そこで、この記事では、テクニカルコミュニケーターとしてのドキュメント担当が、製品開発担当者とどのようにコミュニケーションをとりながら仕事を進めているか、書いてみたいと思います。 *3 (なお、ここでご紹介するやり方は、弊社内で「このようなドキュメントだったらこのようなやり方をする」といういくつかのパターンのうちの1つです。すべてのドキュメントを同じ方法で制作しているわけではありません。) この記事で例にするドキュメント 制作の体制と流れ ドキュメントのキックオフミーティング 目次を作成して提案 開発担当者によるレビュー ライターはどこまで自分で悩むべきか 疑問点解決のためのミーティング おわりに この記事で例にするドキュメント この記事では実際の例として、最近公開した「intdash Edge Agent 2 デベロッパーガイド」( PDF版 および HTML版 )の制作を振り返りながら書いてみたいと思います。 「intdash Edge Agent 2 デベロッパーガイド」は、弊社ソフトウェア製品である「intdash Edge Agent 2」を活用いただくための、開発者向けガイドです。 本製品をLinux PCにインストールすると、そのPCはデータ伝送プラットフォーム intdash のクライアント(エッジ)として動作するようになります。 本製品は、従来からある同等の製品「intdash Edge Agent(末尾に2が付かない)」を使いやすくリニューアルしたものであるため、デベロッパーガイドも完全にリニューアルし、一から作ることにしました。 なお、ドキュメント制作に使用しているツールは Sphinx です。また、原稿データは社内GitLabリポジトリで管理しています。 制作の体制と流れ このドキュメントの制作には、主に以下の3名が携わりました。 ライター1名(私) 当該製品の開発担当者1名(ただし、これ以外の開発メンバーにも要所要所で助けてもらっています) プロダクト開発責任者(かつライターの上司でもある) また、スケジュールは、開発日程との関係、また、ライターの他の作業との関係から、以下のようになりました。 7月中旬:ドキュメントのキックオフミーティング 8月上旬:開発担当者の原案をもとにライターが作業開始 8月下旬:原案を整理し、ライターにて新しい目次を提案、OKをもらう 9月下旬:第1回レビュー(開発担当者およびプロダクト開発責任者がレビューする。以降、レビューを重ね、その都度修正する。) 12月上旬:第5回(最終)レビュー 12月中旬:公開 ライターは7月から12月までずっとこの作業をしているわけではなく、他のドキュメントの制作も同時に進めています。 レビュー日程は作業の進捗に応じてその都度設定する形としました。 ドキュメントのキックオフミーティング まず、7月中旬に今回のドキュメント制作に関するキックオフミーティングを行いました。 ここでは、開発担当者から「このようなドキュメントをつくってほしい」という要望をもらい、以下のことについて説明を受けました。 intdash Edge Agent 2とは何か(特に、既存製品との違い、ユーザー像) 開発スケジュールとドキュメント制作スケジュール ユーザーに説明しなければならないことの一覧 社内にある関連資料(設計関連のドキュメント、インストール用パッケージなど)のありか 今回の場合、このキックオフミーティングを受けて、上記の「ユーザーに説明しなければならないこと」は、開発担当者にて原案を書いてもらうよう依頼しました。 「誰が執筆工程を担当するか」については以下のように役割分担をしているのですが *4 、今回は、上から2番目の「開発者向け製品マニュアル」の方法を採用したということになります。 開発担当者とライターの役割分担 目次を作成して提案 8月上旬、予定通り、十分な情報がしっかりとつまった原案を開発担当者からもらいました。 原案を読み込み、以下のように大きく3部に分けて整理することにしました。 まず動かしてみるためのチュートリアル 目的に応じてやり方を参照するためのガイド 網羅的リファレンス(ここに、設定レシピ集も入れる) これは、これまでの別ドキュメントでの反省をふまえ、また、Divio Technologies社の The Documentation System などのベストプラクティスを参考にしたものです。 目次案 新しい目次について開発担当者やプロダクト開発責任者から承認を得られたら、実際にリライトおよび執筆に入っていきます。 開発担当者によるレビュー 8月下旬以降、説明対象のソフトウェアを実際に操作し、調査や実験をしながら、文章を書いていきます。今回は開発担当者が書いた原案があるので、原案を利用できるところは利用しながらリライト、原案がない部分は自分で一から書きます。 ある程度形になったら、開発担当者やプロダクト開発責任者にレビューしてもらいます。 このレビューは、技術的側面から正しい記述になっているかを確認してもらうのが主な目的です。 レビュー結果を書き込んでもらう方法としては以下の2つを使いました。 機能追加等により、まとまった修正が必要な時は社内GitLab上のマージリクエスト 細かい指摘はGoogleドライブ上のPDFにコメント テキストが主体のドキュメントであれば、細かい指摘もマージリクエストでやり取りをしますが、今回のドキュメントは図や表がたくさんあることから、PDFをGoogleドライブで共有し、そこにコメントをつけてもらう方法を使用しました。 基本的に、レビューコメントを付けてくれるのは開発担当者とプロダクト開発責任者ですが、必要に応じて関連する人がメンションされて呼び出され、議論に加わってくれるという形で進みました。 PDFでのレビュー(開発者がメンションされて呼ばれてきたところ) ライターはどこまで自分で悩むべきか 説明を書いていると、たびたび仕様についての疑問が生じるのですが、どのくらい悩んでから開発担当者に質問すべきか迷います。 私はだいたい、「もう行き詰まった」と思うところまで頑張って一人で悩むようにしています。同時に、「行き詰まった」と感じるところまでできるだけ早く行くように心がけています。 これは、社内のライターとして、自分で答えを探すために必要な材料が十分に与えられているためです。 今回の場合は、手元のDocker環境で、説明対象のソフトウェアを動作させ、実験をすることができました。 実験用のintdashサーバーも自由に使えるため、設定を変えて好きなだけデータの送受信を試してみることができます。 また、社内WikiやGoogleドライブに保存されている設計段階の多くの資料も見ることができます。 (逆に言うと、自分で実験できない場合や資料へのアクセスがない場合は、早く聞くしかないということになります。) 実験環境や社内資料など、情報へのアクセスが十分にあるところでしっかり一人で悩んでおくことは、無駄にはなりません。 一人で考えて行き詰まったとしても、開発担当者に質問するときには、最終的に行き詰まった地点を示し、なぜその道筋をたどったのかを添えて質問すると、開発担当者は返答をしやすくなる(はず)。 自分が行き詰まったということは、これからドキュメントを読むユーザーも同様に行き詰まる可能性が高い。その道筋を自分で体験していれば、それを避けるように説明ができる。 例を挙げてみます。以下は、なんらかの設定項目(ここでは設定項目Xとします)の機能について説明を書こうとして疑問が生じたケースです。ここでは、「このまま考えたら矛盾することが分かった」というのが「行き詰まり」であり、それをもとに質問しました: 設定項目Xの機能はAということであると考えました。 しかし、他に設定項目Yがあるので、Xの機能がAとするとXとYの設定が矛盾することになります。 もしかして、Xの機能はBでしょうか。 開発担当者の返答は、だいたい以下のいずれかになります: (例1)Xの機能はAという理解で正しいです。Yの機能は特別なケースのための設定で、... Aという理解で正しかったということで安心です。でも、悩んだ甲斐がありました。Xについて悩むことでXについて正確に理解しているので、「Xとは異なるY」をどのように説明すればよいか、見えてくるからです。 あるいは以下のような返答もありえます。 (例2)そうです、Xの機能は実はBなんです。ちょっと分かりにくいかもしれませんね、そもそもXがなぜ存在するかというと.... うーむ、Xの機能はAだと予想したのは間違いだったようです。でも、悩んだ甲斐がありました。自分がこのように予想したということは、ユーザーもそのように予想する可能性が高いからです。なぜ自分がそう予想したかを念頭に入れて、Xの「そもそも」のところを説明する必要がありそうです。それにより、Xの位置づけがスムーズに説明できるとよいです。 さらには、以下のような返答もあるかもしれません。 (例3)いいえ、Xの機能は、AでもBでもなく、Cです。どういうことかというと... 予想していなかった第3の答えでした。でも、悩んだ甲斐がありました。これまでAとBを念頭に置いて悩んできたわけですが、ここでも、「Aはでなく、Bでもない」ということがCを理解するための支えになります。 例2や例3のように理解や予想がしにくい機能は、説明を書くと長く複雑なものになってしまうことがあります。そんなとき、場合によっては、「こんなに説明が難しくなってしまうということは、この仕様は見直したほうがよいかも」「設定項目の名前を変えたほうがよいかも」という話になり、ドキュメント化がきっかけで仕様の見直しにまで進むことがあります。 こういうことができるのは、製品開発とドキュメントの制作が社内で緊密に連携しながら進んでいるからこそだと思います。 なかなか複雑なやりとりになってきました。PDFやマージリクエスト上のコメント上で会話を続けて解決すればよいですが、例2や例3のようなケースでは、詳細なコミュニケーションが必要になります。 そんなときは、ライターが主催して、疑問点を解決するためのミーティングをします。 疑問点解決のためのミーティング 疑問点解決のためのミーティングでは、ライターは聞きたいこと(時によって1個から20個ぐらい)を書いた資料を用意しておいて、ひとつひとつ開発担当者に聞きながら解決していきます。 今回のドキュメントでは、開発担当者と7~8回のミーティング(各回1時間ぐらい)をおこなったと思います。 通常、もっと小さなドキュメントや、既存ドキュメントの改版の場合はこんなに多くのミーティングはおこないませんが、前述のとおり、今回は一から新しく制作したため、頻繁におこないました。 *5 ちなみに、普段私はリモートワークをしているのですが、たまたまオフィスに出社した日に開発担当者も出社していて、「せっかくなのでマニュアルの疑問点を解決しましょう」ということになって、オフィスの片隅でミーティングをおこなったこともありました。 対面でミーティングをすると、マウスポインターではなく自分の指を使って「ここの説明が...」と指し示したり、手元の紙に簡単な絵を描いたりしながら話ができ、やはりはかどります。 以上のような工程を経て、最終レビューを通過したら、公開することができます。 ひと段落、ではありますが、ここから先も、「このことが書かれていない」「こう書いてほしい」といった要望をもらうことになると思います。終わりはありません。 おわりに どんなふうにドキュメントを作っているのか、今回は社内での開発者とのコミュニケーションに焦点をあてて、一端をご紹介してみました。 ドキュメントを作るテクニカルライターは、ドキュメントをただ「きれいに」してくれる人というわけではなくて *6 、もっといろんなところで役に立つことができるはず、と思っています。 テクニカルライティングはテクニカルコミュニケーションの一分野であり、今回は、社外の方々に対して「コミュニケーション」をするためのドキュメントを作ったわけですが、そのために社内でも、いわば仕込みの段階で、開発担当者と「テクニカルなコミュニケーション」を繰り返しています。 このような社内コミュニケーションの成果が、例えば上記のような「仕様自体を見直そう」という動きになったり、「ここのところは詳しく説明しよう」という話になったりして、社外にお届けする製品およびドキュメントの改善につながります。そのようなことをめざして、働いています。 *1 : 弊社のドキュメント担当の仕事については、以前 「ひとりドキュメント担当」の仕事 でもご紹介しました。 *2 : テクニカルライティング業界だと、ドキュメント制作におけるこの立ち位置はSME (Subject Matter Expert)と呼ばれます。 *3 : 実は、「私と同じようにドキュメントを内製されている方はどうされているのかな、どのようなやり方がよいのかな」といつも気になっています。「知りたいことがあるときは、まず自分のことを書いてみよう」と思ったのでした。 *4 : この表は以前LINE Technical Writing Meetup vol. 11で発表させていただいたときの スライド から流用しました。 *5 : 弊社内のコミュニケーションガイドラインでは、「翌営業日以降なら事前確認なしに空いているところにミーティングを入れてもよい」となっているので、「うーん、これは聞かないといけないな」となったら、翌日のGoogleカレンダーにポンとミーティングスケジュールを入れます。 *6 : テクニカルライターはドキュメントをきれいにしてくれるだけの人と思われてしまう件については こちら に興味深い記事があります。
アバター
本記事のタイトルはいわゆる「釣り」です。MQTTは、最近ではMQTT5がリリースされるなど現在でも進化を続けている、とても洗練された使いやすいプロトコルです(本記事にMQTTを貶める意図は一切ありません)。 弊社アプトポッドでは、 MQTTよりもターゲットを絞ったニッチな領域に向けた独自プロトコル “iSCP” を開発しております。本記事では、せっかく釣られてくださった皆様に、その “iSCP” の魅力について少しばかりご紹介できればと思います。 なお、本記事は aptpod Advent Calender 2022 の 21日目としてお送りします。 はじめに お久しぶりです。VPoPの岩田です。昨年1月末に QUIC DATAGRAMに関する記事 を書いてから、忙しさにかまけてテックブログ投稿をサボっていたら、なんと2年弱もの長い年月が過ぎ去っていました。これはイカンということで、重い腰を上げて久しぶりに記事を書いてみることにします。 肝心の記事の内容についてですが、実は先日12月5日、弊社の業務提携先で出資元でもある株式会社マクニカ様が開催された MET2022(Macnica Exponential Technology 2022) というオンラインイベントに、弊社CTOの梶田と一緒に登壇しましたので、そのときにお話しした内容を再構成してご紹介したいと思います。 met2022.macnica.co.jp 内容はズバリ 「弊社の独自開発プロトコル iSCP(intdash Stream Control Protocol)とはナニモノか」 になります。MET2022では、マクニカ様が企画・開発されているFMS(Fleet Management System、遠隔運行管理システム)についてのご紹介がメイントピックで、そのFMSを裏側から支えるテクノロジーという位置づけで弊社のiSCPについてもご紹介させていただきました。本記事ではその登壇のなかから、iSCPに関する部分のみを抜粋してご紹介いたします。 本記事では、以下の内容をご紹介します。 弊社ユースケースにおいてMQTTに不足していたポイント 弊社の独自プロトコルiSCP開発の経緯 弊社の独自プロトコルiSCPの特長 以下のような方には、なにかヒントになるかもしれません。 メッセージ配送ミドルウェアをどう選定したらよいのかわからない 大量・高頻度なデータの伝送がうまくいかなくて困っている MQTTが苦手とするユースケースについて知りたい はじめに そもそもintdashとは iSCPが必要とされる背景 intdash / iSCPの適用先 なぜMQTTを使わなかったのか 高頻度メッセージに対して低遅延性を実現できなかった 伝送効率化のために、結局 X over MQTT が必要になった データの確実な永続化に対応できなかった iSCPの特長 さいごに 2024/01/18 追記 MQTT5に関する連載始めました。ご興味お持ちいただけましたら、こちらも併せて覧ください。 tech.aptpod.co.jp そもそもintdashとは iSCPをご紹介する前に、まずはiSCP(intdash Stream Control Protocol)が頭に冠しているintdashがそもそも何者かについてご説明しなくてはなりません。 intdashは、弊社が開発している産業用IoTプラットフォームです (プラットフォームの名称であり、プラットフォームを構築するためのミドルウェア製品の名称でもあります)。 自動車や自律ロボットなどの高機能マシンを主にターゲットとして 、それらが吐き出す大量かつ高頻度なIoTデータを、インターネットやLTE網などを利用してクラウドに集めたり、遠隔地に中継したりすることができます。intdashを用いることで、様々なIoTデバイスや高機能マシンをコネクテッド化し、相互に通信させることが可能になります。 産業用IoTプラットフォームintdash intdashが持つ主な特徴は以下の3つです。 【データの伝送】IoTデバイス間をリアルタイム伝送でつなぐ 【データの保存】伝送されたデータはクラウドに蓄積する 【データの活用】蓄積されたデータにアクセスするAPIを提供する 1つめのintdashのリアルタイム伝送機能の実現のために、 intdashのサーバーとクライアントの間で使用されるプロトコルが、本記事のメイントピックであるiSCP(intdash Stream Control Protocol) になります。 iSCPが必要とされる背景 前述のとおり intdash / iSCPは自動車や自律ロボットなどの “高機能マシン” のコネクテッド化を主にターゲットとしています 。このようなマシンでは、高機能であるが故に内部のバス上で大量のデータが飛び交っていますが、 大量のデータに対してはデバイス側で集約・抽出処理を行い、サマリデータのみをクラウドに送信するアプローチを取ることが一般的です 。 これは、大量のローデータ(生データ)をそのまま送信する方法では、消費帯域が多く回線費用がかさんだり、そもそもLTE回線では帯域が足りなかったり、デバイスの性能が送信処理に耐えきれなかったりと、様々な問題が発生するためです。 一方で、弊社が長らく支援させていただいている自動車の研究開発分野など、 ニッチではあるものの一部のケースにおいて、このような事前処理のアプローチが取りづらい領域があることも分かっています 。intdashは、試作車両のテストや各種車両からのデータ取りなどでご利用いただくことが多くありますが、 これらのお客様にとっては、ローデータこそが取得したいデータであって、集約されてしまったサマリデータでは意味が無いからです 。 それでもやっぱりローデータがほしい ものづくり大国日本における ”ものをつくる側” の皆様のデジタルトランスフォーメーションをお手伝いするため、ものづくりにおいて不可欠な "計測器"をそのままクラウド上に移動させてしまうもの だと捉えていただくのが最もイメージに近いでしょうか。このようなユースケースにおいて、大量・高頻度なローデータの収集や伝送を実現するため、以下のような目的を持って開発されたプロトコルがiSCPになります。 伝送の低遅延化 : すばやいトライアンドエラーを実現するため、リアルタイムに状態が把握できることは大きなメリットとなります 伝送効率の向上 : 大量のデータからなるべく冗長性を排することで、モバイル回線の細い帯域を有効活用します 保存データの高信頼化 : データ欠損なく保存しきることをプロトコルレベルで保証することで、安心して収集データを活用できます 多様なデータへの対応 : 多様なデータを統一的に扱える仕組みとすることで、様々な試行錯誤に柔軟に対応できます 弊社の主力商品であるWebベースの可視化ダッシュボード 「Visual M2M Data Visualizer」 も、iSCPを使用して実現しているプロダクトのひとつです。 自動車などのマシン側から打ち上げられた大量データをWebアプリケーションで受け取り、ブラウザ上のダッシュボードで可視化するツールですが、 マシンからブラウザまでデータを届ける際のプロトコルとしてiSCPを使用しており、打ち上げられるデータが大量になってもブラウザでしっかり可視化することができます。 www.youtube.com intdash / iSCPの適用先 ちなみに、intdashの適用領域は前述した研究開発領域のみにとどまりません。たとえば最近では、デリバリーロボットをはじめとするAGV/UGVの監視などにおいて、 「普段はサマリデータだけで良いけれども、事故などの問題事象が発生した場合にはすべてのローデータをかき集めてすばやく状況把握や原因解析を行いたい」 といった要望をいただくケースが出てきています。 このように、IoTのコモディティ化に伴って、ニッチな研究開発領域だけでなく一般のIoTサービスにおいても 「いざというときのために」すべてのローデータをリアルタイム伝送できるケイパビリティを備えておきたい、という志向が生まれつつある ように感じています。 また、AGV/UGVなどのユースケースでは、ロボットが自律的に対処できない場面に直面した場合のために遠隔操縦機能を備えておくと安心ですが、 遠隔操縦などを行う場合にも高頻度データの低遅延伝送は効果を発揮します 。現状、遠隔操縦はまだそこまで広く社会実装されている状況ではありませんが、今後自律ロボットの普及に伴って、ロボット管理プラットフォームやそれに付随する遠隔操縦機能の需要も高まってくるのではないかと考えており、intdashはそのような領域にも適用可能です。 その他、intdashをバックエンドに使用したソリューションとして、最近新しいプロダクトをいくつか発表しておりますので、よろしければこちらもご覧ください。 自動車業界向け ECU遠隔適合ソリューション「Automotive Pro Remote CAL」 tech.aptpod.co.jp モビリティ・ロボットの管制制御ソリューション「intdash Control Center」 tech.aptpod.co.jp もちろんintdash自体は、データを伝送・蓄積・活用するための汎用的なプラットフォームになりますので、 これらの活用例に限らず、様々なサービスやソリューションのバックエンドとしてご活用いただけます 。 なぜMQTTを使わなかったのか ここからやっと本題に入ります。ここまで読み進めてくださった皆様がおそらくお持ちであろう 「IoTのリアルタイム伝送ならばMQTTがあるじゃないか、なぜそれを使わなかったんだ?」 という疑問にお答えします。 実は以前、弊社でもMQTTを使用してリアルタイム伝送機能を実現しようとしていたことがありました。しかしながら、MQTTでは、研究開発領域で求められる要件(リアルタイム性と確実なデータ永続化の両立)を実現することができず、泣く泣く使用を諦めたという過去があります。では、MQTTの何がいけなかったのか。 高頻度メッセージに対して低遅延性を実現できなかった MQTTは一般的に、エンドツーエンドで低遅延にデータを転送できるプロトコルとして知られています。これは、PubSub型のメッセージングパターンの採用と、軽量でシンプルなプロトコル仕様により実現されています。MQTTは確かに、 「あるクライアントから送出されたデータが別のクライアントに到達するまでの時間が短い」 という意味で、低遅延伝送を実現可能なプロトコルです。 しかしながら、このプロトコルを "高機能マシン" が吐き出す大量データの伝送に適用するとどうなるでしょうか。一般的に自動車が吐き出す車両データ(CANデータ)は、秒間数千フレーム〜1万フレームにもなります。例えば、この大量フレームをMQTTのメッセージにそれぞれ詰め込んで送信したとすると、 少なくとも開発当時のMQTTブローカーでは、すべてのメッセージを送りきれる程のスループットが出ませんでした 。 メッセージを送りきれないということは、各メッセージはその分滞留することになり、結果としてメッセージ配送に要する時間は増大します。要するに、メッセージ一つ一つの転送自体は低遅延に実現できるものの、大量のメッセージを送りつけるようなケースではメッセージの滞留によりリアルタイム性が損なわれてしまう、ということになります。さらに悲しいことに、 スループットの上限値は、QoS(メッセージの転送品質)の設定を上げるとさらに低下します 。 世の中には、MQTTブローカーのスループットを調査したベンチマーク結果も多くありますが、その多くは、 複数のクライアントから同時にデータ送信を試行することで、クライアント全体として数万メッセージのスループットが出ることを確認するもの です。クライアント数が増えるケースについては、サーバーをクラスタリングして水平スケールにより対応することもできますが、我々が対峙している1台単体で数千〜数万のメッセージを生成してしまうようなケースでは、単にサーバー台数を増やせば解決というわけにはいきません。 このようなケースに耐えうるMQTTブローカーは、少なくとも企画当初は世の中に存在せず、intdash / iSCP開発の大きなきっかけとなりました。 ※ MQTTの名誉のために若干のエクスキューズを入れておくと、 これはMQTTの性能が悪いと言っているわけではありません 。 MQTTは、1クライアントから受け取れるメッセージ数については弊社の要件を満たしませんでしたが、その代わりに水平スケールさせやすい仕様になっていると思っています。 一方で弊社のiSCPでは、1クライアントから受け取る大量メッセージを捌き切るためにステートフルなデータ保持の仕組みを敢えて導入したり、とにかく大量のデータを捌き切ることに仕様を全振りしています。 これは、あくまで対象とするユースケースの違い・プロダクトの思想の違いであって、どちらが良い悪いというものではありません 。 ユースケースによっては、よりMQTTが適している場合もあれば、iSCPが適している場合もあり、適材適所でプロダクトを選択していけばよいだけのことです。 それぞれ向いているユースケースが違う 伝送効率化のために、結局 X over MQTT が必要になった 前のセクションを読まれた皆様の中には、 「1データずつ1メッセージで送信するからメッセージ数が膨大になるのであって、複数メッセージをまとめて送ればよいのではないか」 と気づいた方もいらっしゃると思います。そのとおりです。あくまでメッセージ数が多すぎることが原因なので、複数データをまとめて大きめなメッセージにしてからバルク送信すれば、スループット不足の問題はある程度回避することができます。一見、この方法で問題は解決できるように思えますが、これはまた別の問題を引き起こします。 バルク送信を採用するということは、MQTTのペイロードへのデータの格納方法として所定のフォーマットを定義するということです。これは、 MQTTの上層にさらに別のプロトコルを定義することに相当します(X over MQTT) 。このアプローチを取った場合、 各クライアントは MQTT のプロトコルに準拠しつつ、MQTT上に想定されているフォーマットに合わせた形式でMQTTのペイロードを構築して送信しなければなりません 。すなわち、そのプロトコルは下層にMQTTを採用してはいるものの、MQTTで定義されている仕様に従っただけのクライアントからは通信ができないことになります。 これはたとえば、HTTPは主にTCP上のプロトコル(= HTTP over TCP)ですが、HTTPサーバーとただのTCPクライアントで通信するには、クライアント側にさらにHTTPを解釈するための自前実装が必要になることと同じだと考えていただければ、分かりやすいでしょうか。 MQTTを下層に使用したとして、結局その上層に独自のプロトコルを定義するのであれば、下層はわざわざMQTTに縛られる必要はありません 。幸い、MQTTのプロトコル仕様は極めてシンプルで、MQTTブローカーにより提供される機能性の実装はそこまで複雑なものではないため、 MQTTに依存することによって課せられる制約と、独自にプロトコルを定義するコスト とを天秤にかけた結果、弊社では独自のプロトコルを開発することを選択しました。 どうせ作るするならすべて自前で作ってしまえ データの確実な永続化に対応できなかった 主にデータ収集用途で使用されることが多かったintdashでは、集めたデータの信頼性についても高い要件を課せられていました。 サーバーに送信されたデータは、取りこぼすこと無く確実にデータストアに保存しなければなりません 。しかしながら、この機能性を既存のMQTTブローカーを用いて実現しようとすると、アーキテクチャが複雑化してしまうという問題がありました。 もちろん、MQTTにもQoS(メッセージの転送品質)という考え方があり、 "伝送経路での欠損については" 検出することができます。一般的に言われていることですが、この "伝送経路での欠損については" の部分が注意を要するところで、 MQTTのQoS設定を上げたとしても、エンドツーエンドでの欠損については検出することができません 。 どういうことかというと、例えばパブリッシャーとサブスクライバーが存在した場合、検出ができるのはあくまで パブリッシャー〜ブローカー間 と ブローカー〜サブスクライバー間 それぞれの経路についてのみであって、例えば極端なケースでは、パブリッシャーからブローカーへ転送されたあと何らかのエラーによってデータが消失してしまうと、それをパブリッシャーは検出することができない、ということになります。 既存のMQTTブローカーを用いてリアルタイム機能およびデータの確実な永続化機能を実現しようとすると、データを永続化するクライアントをサブスクライバーとしてブローカーにぶら下げ、永続化サブスクライバーがデータストアへデータを保存することになりますが、このような形式では 送信クライアントからデータストアまでのエンドツーエンド経路におけるデータ欠損の可能性を排除することができず、結局MQTT上で独自のプロトコルを定義しなければならなくなります (前のセクションでも登場した X over MQTT という形になります)。 片道伝送経路での到達確認しかできない 前のセクションでも言及したとおり、MQTTのプロトコル仕様自体は極めてシンプルで、同様のものをイチから考案することもできなくはありません。 MQTT上に独自プロトコルをスタッキングするくらいなら、はじめから独自のプロトコルを作ってしまったほうが柔軟でシンプルなものができあがるだろう ということで、さらに独自プロトコルの開発に踏み切る機運が高まりました。 もちろん世の中には、「プロトコル自体はMQTTを採用し、MQTTの標準仕様には無い機能性を追加した独自ブローカーを作る」というアプローチを取っている商用MQTTブローカーも存在します(このようなブローカーは、intdashの競合ということになります)。このようなアプローチを取るメリットは、一般のMQTTのライブラリやツール群を流用できることにあります。しかし、それと引き換えに、 MQTT標準仕様の範囲から逸脱しない範囲でしか機能を拡張できない、MQTTの仕様改訂への追従など自社でコントロールできない仕様変更リスクを抱える、などのデメリットもプロダクトに内包させる ことになります。 弊社としては、MQTT標準仕様の範囲だけでは実現できない機能性を追加したかったこと、テックベンチャーとしてMQTTに競合するような新しいプロトコルの確立に挑戦してみたかったことなども含め、メリット・デメリットだけでなく開発メンバーの思いやビジネス的な思惑等、様々なことを考慮して総合的に判断した結果、iSCPという独自プロトコルを開発することを選びました。 iSCPの特長 ここまで説明したMQTTを採用するにあたっての課題に対して、X over MQTT から派生して、MQTT部分も含めてすべてオリジナルなプロトコルスタックにより定義したものがiSCPです。 さらに、MQTTのようなPubSub部分も含めて独自で定義したため、MQTTにはない機能性もいくつか追加することができました。 iSCPの特長には様々なものがありますが、特徴的なものだけを拾い上げると、まずは大量・高頻度なデータを効率よく伝送できるように以下の特長を持っています。 これらの特長により、MQTTでは難しかった大量・高頻度なデータの伝送処理を実現しています。 複数データをまとめてバルク送信(もちろんバルクサイズは調整可能) メタ情報をあえてステートフルに保持することで、通信オーバーヘッドを削減 WebSocketを参考にしたメッセージ圧縮方式の採用 また、主に研究開発にて要求されるリアルタイム性と確実な永続化の両立のため、以下の特長も備えています。 ブローカーはデータを受信したら最優先で転送(永続化処理はあと回し) クライアントへのAckは永続化処理が完了してから返却 Ackにより永続化確認ができないデータは別途あとから永続化 クライアントへのAck返却タイミングが永続化処理完了後となっている点がiSCPの特徴的な部分です 。多くのプロトコルではAckは通信経路での到達確認や順序保証に使われるため、ある程度のAckが返却されない場合にはAck待ちにより送信が停止してしまいますが、iSCPにおいてはサーバーへデータが永続化されたかどうかの確認に用いられるものであるため、Ackの返却は必ずしも待つ必要がありません。 大量にデータを送りつけ、欠損があった場合には検出だけしておき、帯域に余裕があるときに改めて欠損部分だけを永続化処理する、というのが iSCP の基本の考え方になります 。 intdash / iSCPでの処理の流れ このような仕様により、 伝送時にはリアルタイム性を最優先に転送を行いつつ、後からではあるものの取りこぼすことなくデータを回収できる ようになっています。 このような機能性は、弊社でも実績の多い研究開発におけるデータ収集のユースケース(データを可視化しながらトライアンドエラーを行い、最終的にはすべてのデータを収集し切りたい)と極めて相性がよいものです 。もちろんそれだけでなく、たとえば遠隔管制・フリート監視のようなユースケースでは監視時にはリアルタイム性が、事故発生時の解析等でにはデータの信頼性が重要なファクターとなるなど、研究開発以外のユースケースにおいても効果を発揮します。 また、最近では遠隔管制に関連して、ロボットに対する遠隔操縦に対する要望もいただくようになってきています。 このようなケースでは、データの詰まりによってリアルタイム性の失われやすいストリームベースの通信方式よりも、データグラムベースの通信方式が好まれる傾向があります。 このような要求にも応えられるようiSCPは現在も日々進化を続けており、iSCPのメジャーバージョンアップに向けて現在準備を進行しております。 メジャーバージョンアップ前の現行バージョンでは、下層に使用するトランスポートプロトコルとしてWebSocketしか選択できませんでしたが、 メジャーバージョンアップ後のバージョンでは、 データグラムベースの通信方式に対するサポートが追加され、 WebSocketに加えて最新のトランスポートプロトコルであるQUICやWebTransportも使用可能となる予定です 。 さいごに いかがでしたでしょうか。 弊社がなぜMQTTを捨て独自プロトコルの開発に踏み切ったのか、また、その結果生まれたiSCPがどのようなプロトコルなのか 、この記事でお伝えできていれば幸いです。また、前述のMET2022にてご一緒させていただいたマクニカ様のFMS(Fleet Management System)のように、intdashやiSCPが持つ特長に少しでも興味や魅力を感じていただけましたら、ぜひとも皆様ご担当のシステムへの導入をご検討ください。 iSCP のクライアントライブラリ はオープンソース化していますので、どなたでも自由にご利用いただけます。また、 プロトコル仕様書 も公開可能なものを用意しておりますので、プロトコル仕様をよく精査して導入をご検討いただけます。 サーバーソフトウェア や弊社が運用する マネージドサービス は有償でのご提供となりますが、 フリートライアルのプラン もご用意しております。その他些細なことでも構いませんので、プロダクトに関するお問い合わせについては、 弊社営業までご連絡ください 。(私自身も、弊社プロダクトの開発責任者として全力でサポートさせていただきます) 結びとなりますが、アプトポッドではintdashやそれを取り巻く周辺プロダクトの販売だけでなく、intdashを活用したシステムインテグレーションや受託開発も行っております。当社が直接お手伝いをするだけでなく、当社が認定した信頼と実績のあるパートナー企業様にて、ご対応させていただくことも可能です。本記事でご紹介できなかった弊社のプロダクトやビジネス全般につきましては、弊社のコーポレートサイトをご覧ください。 「IoTシステムを構築したいがどんなアーキテクチャがよいのかわからない」「MQTTで構築した既存のIoTシステムがあるが限界を感じている」など、IoTシステム構築に関する一般的なご相談につきましても、お問い合わせいただければお力添えいたします。 www.aptpod.co.jp ※ 本記事をお読みいただき、アプトポッドのプロダクトやエンジニアリングに興味を持ってくださったエンジニアの方々からの連絡もお待ちしております。 まずはカジュアルな情報交換からでも構いません。会話をさせていただくなかで、募集中の職種をご紹介させていただきます。( 採用ページはこちら ) www.wantedly.com 最後までお読みいただき、ありがとうございました。 皆様よいクリスマスと年末をお過ごしください! 🎄🎍
アバター
aptpod Advent Calendar 2022 の20日目を担当します、intdash グループ フロントエンドエンジニアの佐藤です。 早速ですが、弊社では認可制御にOAuth 2.0 を採用しています。 tech.aptpod.co.jp ブラウザのアプリケーションでこの認可制御をする際、Express 等を使ったバックエンドがある場合が多いかと思います。 弊社でもNext.js を用いて、認証を管理するバックエンドサービス (BFF) のある構成をとっています。 このバックエンドがある場合のパターンは、Node.js のクライアント・ライブラリやExmaple も多く、それに従えばおおよその実装はできるのではないでしょうか。( oauth2-proxy が有名でしょうか。) バックエンドがある場合の方がセキュリティレベルは高く、一般的にこちらが採用されることが多いように思えます。 一方、バックエンドが無いアプリケーション、つまりブラウザ側 のみ で認証管理する方法は調べてもあまり有用な情報が出てこないことが多いです。 業務の中でブラウザ側のみで認証管理をする場合の実装が必要になり、実装方法について色々と調べましたので、その内容をご紹介します。 前提条件 実装方法 実装する処理の流れ 環境構築 code_verifier とstate を保存する 認可リクエスト先のURL を作成する 認証コードをアクセストークンへ交換する アクセストークンを保存する アクセストークンを利用してリソースを取得する 実装してみて 前提条件 Implicit Flow はセキュリティ上の懸念が伴うために使用しない PKCE に対応した Authorization Code Flow で認可リクエストを行う 実装方法 完成したコードの内容は以下のようになりました。 import { v4 as uuidv4 } from "uuid" ; import pkceChallenge , { generateChallenge } from "pkce-challenge" ; import Cookies from "js-cookie" ; import axios from "axios" ; import { AuthMeApi , MeasDataPointsApi , AuthOAuth2Api } from "../../intdash" ; // クライアント ID const CLIENT_ID = "XXXX-XXXX-XXXX-XXXX" ; // 認可先のホスト const AUTHORIZATION_HOST = "https://example.intdash.jp" ; // リダイレクトURI const REDIRECT_URI = "https://localhost:8443" ; // PKCE の設定 const { code_verifier } = pkceChallenge (); // state の作成 const state = uuidv4 (); (async () => { // アクセス時のURL の検証 const code = new URL ( window .location.href ) .searchParams. get( "code" ) ?? "" ; try { const authOAuth2Api = new AuthOAuth2Api ( { isJsonMime: () => true , basePath: ` ${ AUTHORIZATION_HOST } /api` , } ); const { data: { access_token , expires_in } , } = await authOAuth2Api.issueToken ( { grantType: "authorization_code" , code , clientId: CLIENT_ID , redirectUri: REDIRECT_URI , codeVerifier: Cookies. get( "code_verifier" ) ?? "" , } ); // アクセストークンを取得できた場合、PKCE とstate の値を削除する Cookies.remove ( "code_verifier" ); Cookies.remove ( "state" ); if (typeof access_token !== "undefined" ) { Cookies. set( "_bearer_token" , access_token , { ...options , expires: expires_in , } ); } const authMeApi = new AuthMeApi ( { isJsonMime: () => true , basePath: ` ${ AUTHORIZATION_HOST } /api` , } ); const { data: { name } , } = await authMeApi.getMe ( { withCredentials: true , } ); document .querySelector < HTMLDivElement > ( "#app" ) ! .innerHTML = `<p>Hello ${ name } </p>` ; } catch ( error ) { Cookies. set( "code_verifier" , code_verifier , options ); Cookies. set( "state" , state , options ); const requestURL = new URL ( ` ${ AUTHORIZATION_HOST } /api/auth/oauth2/authorization` ); requestURL.searchParams. set( "client_id" , CLIENT_ID ); requestURL.searchParams. set( "response_type" , "code" ); requestURL.searchParams. set( "redirect_uri" , REDIRECT_URI ); requestURL.searchParams. set( "state" , Cookies. get( "state" ) ?? "" ); requestURL.searchParams. set( "code_challenge" , generateChallenge ( Cookies. get( "code_verifier" ) ?? "" ) ); requestURL.searchParams. set( "code_challenge_method" , "S256" ); document .querySelector < HTMLDivElement > ( "#app" ) ! .innerHTML = `<a href= ${ requestURL.href } >Connect Your Account</a>` ; } } )(); 各エンドポイントは OpenAPI Generator でドキュメントから生成したクライアントを通して、リソースを取得しています 実装する処理の流れ 以下のようなフローで認可を行い、エンドポイントから自分の名前を取得するSPA を実装していきます。 なお、薄灰色の箇所は認可サーバーの役割になるので本記事では触れません。 https://localhost:8443 にブラウザからアクセス 「Connect Your Account」のリンクをクリック https://example.intdash.jp へ認可リクエストを行う https://example.intdash.jp 上でユーザー名とパスワードを入れて認証 https://localhost:8443 へcode を発行 (URL のクエリパラメーターにセット) しリダイレクト https://localhost:8443 上でトークン交換をリクエストする 問題なくトークンが発行できたらCookie に_bearer_token として値をセット Axios で自分の名前を取得するエンドポイントからデータを取得 UI フロー図 環境構築 さくっと作りたかったので Vite を使ってみました。 HTTPS でlocalhost を起動したいのと、API のエンドポイントのホスト ( https://example.intdash.jp ) に対してProxy をしたいので vite.config.js を編集します。 import { defineConfig } from "vite" ; import fs from "fs" ; export default defineConfig( { server: { port: 8443, https: { key: fs.readFileSync( "./.key.pem" ), cert: fs.readFileSync( "./.cert.pem" ), } , proxy: { "/api" : { target: "https://example.intdash.jp" , changeOrigin: true , configure: (proxy, options) => {} , } , } , } , } ); 以下のコマンドを入力すると、 https://localhost:8443 でローカルサーバーが立ち上がります。 yarn dev これで、環境準備が整いました。 code_verifier とstate を保存する 認可リクエストをする前に code_verifier と state を適切なブラウザ API を使用して任意の場所に保存します。 以下の例では js-cookie を利用して Cookie に保存しています。 import { v4 as uuidv4 } from "uuid" ; import pkceChallenge , { generateChallenge } from "pkce-challenge" ; import Cookies from "js-cookie" ; // PKCE の設定 const { code_verifier } = pkceChallenge (); // state の作成 const state = uuidv4 (); Cookies. set( "code_verifier" , code_verifier , options ); Cookies. set( "state" , state , options ); 認可リクエスト先のURL を作成する 次に、認可リクエスト先の URL に以下をクエリパラメータとして追加します。 生成したURL をhref 属性に追加したa タグ を実装します。 ユーザーはこのa タグ をクリックすることで認可フローを開始します。 const requestURL = new URL ( ` ${ AUTHORIZATION_HOST } /api/auth/oauth2/authorization` ); requestURL.searchParams. set( "client_id" , CLIENT_ID ); requestURL.searchParams. set( "response_type" , "code" ); requestURL.searchParams. set( "redirect_uri" , REDIRECT_URI ); requestURL.searchParams. set( "state" , Cookies. get( "state" ) ?? "" ); requestURL.searchParams. set( "code_challenge" , generateChallenge ( Cookies. get( "code_verifier" ) ?? "" ) ); requestURL.searchParams. set( "code_challenge_method" , "S256" ); document .querySelector < HTMLDivElement > ( "#app" ) ! .innerHTML = `<a href= ${ requestURL.href } >Connect Your Account</a>` ; 認証コードをアクセストークンへ交換する 認可先で認証が承認されたら認証コードとともに指定されたリダイレクト URL にリダイレクトされます。 https://localhost:8443/?code=UeE7Adf6QxGDiKuKOngG0Gc9Nee3XhnxMnKYsNTqQ60.OJouZMWIrYDm6EYIpt7xbBMSYC6u7UouTCo30Yk-Uyk&remember_me=true&scope=add_any_edge_to_project%20admin%20anonymous%20authz%20config%3Ar%20config%3Arw%20edge%3Ar%20edge%3Arw%20group%3Ac%20group%3Al%20group%3Arw%20me%3Ar%20me%3Arw%20meas%3Ar%20meas%3Arw%20media%3Ar%20media%3Arw%20offline%20passwordpolicy%3Arw%20project%3Al%20project%3Arw%20projectedge%3Arw%20role%3Ar%20role%3Arw%20scope%3Arw%20screen%3Ar%20screen%3Arw%20sig%3Ar%20sig%3Arw%20stats%3Ar%20stream%3Ar%20stream%3Arw%20system%3Ar%20temporary%20user%3Ar%20user%3Arw%20v1_admin&state=0ebdee45-7178-4d86-8978-560bf49fa6e4 アクセストークンの認証コードを交換するために、トークンエンドポイントに対して POST リクエストを行います。 リクエストには次のパラメータが含まれます。 grant_type 値は authorization_code で固定されています code URL のクエリパラメータに含まれている code を使用します client_id redirect_uri 認可フローを開始したときと同じ値を使用します code_verifier 任意の場所に保存した code_verifier を使用します import { AuthOAuth2Api } from "./intdash" ; const authOAuth2Api = new AuthOAuth2Api ( { basePath: `https://example.intdash.jp/api` , } ); const { data: { access_token , expires_in } , } = await authOAuth2Api.issueToken ( { grantType: "authorization_code" , code , clientId: CLIENT_ID , redirectUri: "https://localhost:8443" , codeVerifier: Cookies. get( "code_verifier" ) ?? "" , } ); アクセストークンを取得した場合のサンプルデータです。 { " access_token ": " eyJhbGciOiJSUzI1NiIsImtpZCI6ImIyYjNkNTIwNzY0MDQ3MTAwMmY0ZWY4MjhjZjJlN2YyZmYwNDhkMzc0YzUwNGYyNTJiYmQ0ZTgwZWE4YzJhZGUiLCJ0eXAiOiJKV1QifQ.eyJzY3AiOlsiYWRkX2FueV9lZGdlX3RvX3Byb2plY3QiLCJhZG1pbiIsImFub255bW91cyIsImF1dGh6IiwiY29uZmlnOnIiLCJjb25maWc6cnciLCJlZGdlOnIiLCJlZGdlOnJ3IiwiZ3JvdXA6YyIsImdyb3VwOmwiLCJncm91cDpydyIsIm1lOnIiLCJtZTpydyIsIm1lYXM6ciIsIm1lYXM6cnciLCJtZWRpYTpyIiwibWVkaWE6cnciLCJvZmZsaW5lIiwicGFzc3dvcmRwb2xpY3k6cnciLCJwcm9qZWN0OmwiLCJwcm9qZWN0OnJ3IiwicHJvamVjdGVkZ2U6cnciLCJyb2xlOnIiLCJyb2xlOnJ3Iiwic2NvcGU6cnciLCJzY3JlZW46ciIsInNjcmVlbjpydyIsInNpZzpyIiwic2lnOnJ3Iiwic3RhdHM6ciIsInN0cmVhbTpyIiwic3RyZWFtOnJ3Iiwic3lzdGVtOnIiLCJ0ZW1wb3JhcnkiLCJ1c2VyOnIiLCJ1c2VyOnJ3IiwidjFfYWRtaW4iXSwidGVuIjowLCJleHAiOjE2NjY1OTAwOTAsImp0aSI6ImE3MjQ4ZTBjLTZjYzUtNDkyNS1hZTEyLTU0Mjk3ZDYyNjNiYiIsImlhdCI6MTY2NjU4NjQ5MCwiaXNzIjoiaHR0cHM6Ly9kZXYuaW50ZGFzaC5qcCIsInN1YiI6IjIwMGU0NTBlLTE4YzMtNGI1MS1hMzk2LWM4NmM5NjYxNjYxMiJ9.F6Obt776U0EupdVqKnCSN0fVX1xKzDXZNTOVVpTinWvwF60r4rooKA_X60N7Bu4y3p1V6g95DJFE25BFAsOZBNM0Pjv8yEFEevLP34kgCoydT80l5ODdgYK0M0k5O03-Cdnjd4_yKk2stoSmF2TMNEjWm47ho6XDVDapi41RddfYu7YUn5_NwQVKBUDHL1i5U1a5-wvcOD_42A9rw2_kxoExuYq3UWOg692ZcfaDdaTDNU_OxagjWSZ8_Lx44kQKdNLZu9tLJZI0DUtYSD43eTy1GusVnxVmKASNigYByPuYaXZU6rkEZV9NlHeTjchh73lvpUhOozjpTXfaaoLpcQ ", " expires_in ": 3599 , " refresh_token ": " EIe7ZiGH_USAAs-21En0NzbnxN3WTFPgmMX9UMDSCtE.jTW1O7yEypG_qkmPY1OT3l1mcsSntdZ9c5YwmFZd9RY ", " refresh_token_expires_in ": 2591999 , " scope ": " add_any_edge_to_project admin anonymous authz config:r config:rw edge:r edge:rw group:c group:l group:rw me:r me:rw meas:r meas:rw media:r media:rw offline passwordpolicy:rw project:l project:rw projectedge:rw role:r role:rw scope:rw screen:r screen:rw sig:r sig:rw stats:r stream:r stream:rw system:r temporary user:r user:rw v1_admin ", " token_type ": " bearer " } アクセストークンを保存する 適切なブラウザ API を使用して、アクセストークン(と、ある場合はリフレッシュトークン)を可能な限り安全に保存します。 以下の例では Cookie に保存しています。 Cookies. set( "_bearer_token" , access_token , { ...options , expires: expires_in , } ); アクセストークンを利用してリソースを取得する import { AuthMeApi } from "./intdash" ; const authMeApi = new AuthMeApi ( { basePath: `https://example.intdash.jp/api` , } ); const { data: { name } , } = await authMeApi.getMe ( { withCredentials: true , } ); document .querySelector < HTMLDivElement > ( "#app" ) ! .innerHTML = `<p>Hello ${ name } </p>` ; OAuth 2.0 で認証したのち、発行されたアクセストークンを使用してリソースが取得できました。 実装してみて アクセス時のURL の検証や、Cookie に格納した値の適切なタイミングでの削除などバックエンドがあるときとは異なる点が多くありました。 リクエストURL の生成やトークン交換はNode.js 上で動くクライアントライブラリ (PKCE に対応している client-oauth2 )があるので、そちらを使ったほうがコードがスッキリします。 例えば初回アクセス時やアクセストークンが交換できなかった際、認証先にリダイレクトをしたい場合はバックエンドだと以下のようなコードになります。 // 認証のためのインスタンスの作成 import ClientOAuth2 from "client-oauth2" ; const intdashAuth = new ClientOAuth2 ( { clientId: CLIENT_ID , accessTokenUri: ` ${ AUTHORIZATION_HOST } /api/auth/oauth2/token` , authorizationUri: ` ${ AUTHORIZATION_HOST } /api/auth/oauth2/authorization` , redirectUri: REDIRECT_URI , state , } ); const uri = intdashAuth.code.getUri ( { state , query: { code_challenge , code_challenge_method: "S256" , } , } ); res.redirect ( uri ); 結局、メリットはとくになかったですね。。。 バックエンドがどうしても用意できないときに、最終手段として使うくらいに考えたほうが良さそうです。
アバター
aptpod Advent Calendar 2022 の19日目を担当します、ソリューションアーキテクトの渡辺です。 ところで皆さん。 海外旅行に行くために航空機を利用したことがありますか。 その航空機の中でインターネットが当たり前のように利用できます。 それは何故でしょう? 海外旅行に行くために豪華客船を利用したことがありますか。 その豪華客船の中でもインターネットが当たり前のように利用できます。 それは何故でしょう? これらには「宇宙通信」という技術が用いられています。 この宇宙通信を intdash で試す機会がありましたので、宇宙通信の概要説明と共にその様子をレポートします。 宇宙通信とは 2種類の衛星通信 静止衛星を利用する 低軌道衛星を利用する intdash による宇宙通信 宇宙通信とは 宇宙空間を飛行する機体は正式には「宇宙機」と呼ばれます。 人工衛星、探査機、宇宙ステーションこれらすべて宇宙機です。 この宇宙機が行う電波通信のことを宇宙通信と呼び、特に人工衛星に搭載した中継器を用いて地上の2地点間の通信を行うことを「衛星通信」と呼びます。 2種類の衛星通信 衛星通信では人工衛星を通信の中継器として用いますが、利用する衛星によって大きく2種類に分類できます。 静止衛星を利用する 身近なものとしては、BS放送があります。 地上から静止衛星に対してTV映像を送信し、それを受信した静止衛星はそのTV映像を地上の広い範囲に向けて送信します。 静止衛星は高度36,000Kmにあり、地表の広い範囲をカバーします。 また、地上から見ると上空の固定した位置に静止しているため、常に通信を行えます。 【静止衛星のカバー範囲】 静止衛星は1機で地上の30%~40%をカバーできることから、静止衛星を4機使うと理論的には全世界をカバーする通信網を構築することが出来ます。 この方式でTDRS (Tracking and Data Relay Satellite)がNASAにより運用されており、8機の静止衛星が稼働しています。 【静止衛星による全世界カバー】 静止衛星通信のメリット 静止衛星には大出力の中継装置を搭載できるためブロードバンド通信が可能 広範囲に同報配信が出来るため放送用途に向いている 静止衛星通信のデメリット 衛星を赤道上空にしか配置できないため、北極・南極では利用出来ない 地上からの送信に大出力が必要となるため地上の送信装置を小型化できない 低軌道衛星を利用する 近年、本格的に利用出来る様になってきました。 主に大型の航空機や、外航船舶で利用されています。 衛星の高度が静止衛星の36,000Kmに対して800Km前後とかなり低く地上に近いところを飛んでいるため、カバーできる通信範囲が狭いです。 また、地上に対して秒速7Km(音速の20倍)以上という極超音速で移動しているため、1機の衛星は10分足らずで上空を通り過ぎてしまいます。 【低軌道衛星のカバー範囲】 このような低軌道衛星と1対1ではまともな通信は行えないので、多数の衛星を打ち上げて、上空を衛星で一杯にしてしまおう、というのが低軌道衛星を利用する場合の考え方です。 移動中にスマートフォンで通話をしているような場合、一つの基地局のカバー範囲から次の基地局のカバー範囲に人が移動しても通話を続けることが出来ます。 これをローミングと言いますが、低軌道衛星を利用する場合は基地局の方が超高速で移動していて次々とローミングを行っている状態、という訳です。 スペースX社の「スターリンク」サービスは何と2,000機を超える小型衛星を打ち上げて運用しています。 【低軌道衛星による全世界カバー】 低軌道衛星通信のメリット 地上の送受信装置を小型化できるため携帯電話としての利用も出来る 極軌道衛星を用いれば北極・南極も含めて地球上全てのエリアで利用できる 低軌道衛星通信のデメリット 低軌道衛星には大出力の中継装置を搭載出来ないため通信帯域が限られてしまう 多数の衛星が必要で低軌道衛星は運用寿命も短いためコストが高い intdash による宇宙通信 さて、話は変わって intdash による宇宙通信を行ってきた様子のレポートです。 冒頭で航空機で宇宙通信が利用されていることを書きましたが、今回の機会も将来、航空機で intdash を利用して頂くことを想定したものです。 そのためなんと当社製品 「EDGEPLANT T1」 を航空機に搭載して空に飛ばし、上空で宇宙通信(衛星通信)を行ってきました。 利用させて頂いたのは「イリジウム」という低軌道衛星を用いた衛星通信サービスです。 www.n-aviation.com イリジウムは66機の低軌道衛星を運用しています。 このイリジウムが計画された当初は77個の衛星を用いる事になっていたため、原子番号77の元素であるイリジウムがサービスの名称になっています。 このイリジウムという名前にピンときた方はかなりの宇宙マニアですね。 1991年に計画された後 衛星に反射する強い太陽光がUFO騒ぎを起こしたり 人類史上初の人工衛星同士の衝突事故を起こしたり で世を騒がしたあのイリジウムです。 一度は経営破綻して計画がとん挫しましたが、いつの間にか復活して当初計画していたサービスを見事に実現させていたのです。 この度、ナビコムアビエーション様のご協力で、同社が保有する小型飛行機にイリジウム地上局と 「EDGEPLANT T1」 を搭載して飛行試験を行って頂きました。 www.n-aviation.com 今回の飛行試験ではこの小型飛行機が飛びました。 ナビコムアビエーション様が所有している機体です。 二人乗りのシートの後ろに諸々の機材を搭載しました。 もちろん 「EDGEPLANT T1」 もここに搭載します。 そして無事に離陸。 周辺を飛行して地上をカメラで撮影し、撮影データをイリジウム回線で地上に送信する、というのが今回の飛行試験の目的です。 当社営業担当社員のK氏が撮影(カメラ持ち)係として搭乗し、2回飛行したのですが、とっても楽しかったらしいです(笑) こんな感じで無事に宇宙通信を intdash で試すことが出来ました。 このような小型航空機(モーターグライダー)で宇宙通信ができる技術が既にあります。 近い未来「空飛ぶ車」などもっと小型な航空機に intdash が導入されたら、世界中の空を intdash が飛ぶ日も近い???
アバター
aptpod Advent Calendar 2022 の16日目の担当は、開発本部ソリューションプロフェショナルGrの影山です。普段は組み込みソフト周辺の開発やインテグレーションを担当しています。 今日は、aptpodで取り組んでいる、ROSをインターネットに接続する技術について、これまでテックブログやデベロッパーズガイドで公開してきた情報だけでは分かりにくかった、導入の大まかなイメージをご紹介したいと思います。 本記事で思ったよりもROSxインターネットが簡単に実現できそう!と思って頂ければと思っています。 想定読者:ROSをインターネット経由で利用したい方、ロボットの遠隔管理、制御に興味のある方 ROSをインターネットにつなぐ技術 TurtleBot3をインターネット経由で制御してみる ステップ1 構成の検討 ステップ2 intdashの環境を導入 ステップ3 Edgeの作成 ステップ4 設定ファイルの書き換え intdash Edge(コントローラ側) intdash Edge(TurtleBot3側) intdash Bridge(コントローラ側) intdash Bridge(TurtleBot3側) ROS launch(コントローラ側、TurtleBot3側共通) ステップ5 動作確認 終わりに 参考情報 ROSをインターネットにつなぐ技術 実際の導入の紹介の前に、前提となる弊社のプロダクトについて簡単にご紹介します。 aptpodではリアルタイム時系列データの可視化、蓄積を実現するintdashをこれまで開発して、様々なお客様に提供してきました。intdashにROSを接続することで、二つのROS空間があたかも同じローカルネットワーク上に存在するように扱えるようにすることを目的として、intdashへの接続のためのintdash Bridgeとノードを開発しました。 intdashを利用したROSのインターネット接続 詳細は以下のエントリを見て頂くのが分かりやすいかと思います。 tech.aptpod.co.jp tech.aptpod.co.jp TurtleBot3をインターネット経由で制御してみる 本記事の細かい部分はそれぞれの弊社の デベロッパーズガイドやマニュアル を参照して頂くとして、作業全体の大きな流れをつかんでいただくことを第一の目標として説明していきたいと思います。 良くチュートリアルやデモで用いられる TurtleBot3 とTurtleBot3が対応しているROS1を例にとって説明していますが、弊社の製品は ROS2にも対応 しております。 ステップ1 構成の検討 TurtleBot3では、Raspberry Piを制御用のコンピュータとして利用しています。TurtleBot3のマニュアルに従ってセットアップすると、開発元で提供されているTurtleBot3制御関連のROSノードがインストールされて、ゲームコントローラなどを接続して走行を制御できるようになります。 コントローラの入力は標準のパッケージのjoyをインストールできていれば、joy_nodeからコントローラの操作像情報を含んだjoyトピックがpublishされ、それをTurtleBot3のノードが受信して動作します。 元となる構成 遠隔制御を実現しようとする場合、上記のような構成を以下のように2つに分解して、遠隔制御を実現するのが一番シンプルかと思います。 intdash bridge nodeとintdash Edgeをセットで対象のデバイスにインストールすることで、ROSをintdash Serverに接続できるようになります。 intdash bridgeではROSのトピックをintdashの通信仕様に合わせて変換して、intdash Edgeを経由して、intdash Serverと送受信できるような機能を提供しています。 intdash bridgeを用いることで、joy_nodeとTurtleBot3関連ノード観点では、2つのROSの空間が透過的に繋がっているように見えるようになります。 目標とする構成 以降のステップではこの構成を実現するために必要なステップを説明していきます。 ステップ2 intdashの環境を導入 intdash Edge *1 とintdash Bridgeはそれぞれパッケージが公開されているのでLinux環境 *2 であれば簡単にインストールできます。 intdash Edge(intdash Edge Agent)のインストール( 詳細 ) sudo apt-get install intdash-edge intdash Bridgeのインストール( 詳細 ) sudo apt-get install ros-noetic-intdash-bridge  (ROS1:Noeticの場合) ステップ3 Edgeの作成 intdashではEdgeの管理や、アップロードされたデータの管理、可視化のために、 各種Webアプリケーション も提供しています。 Edge Admin Console画面のGUI操作で、intdashサーバ上で仮想的なEdgeを簡単に生成できます。 Edgeをサーバ上で作成したときの画面 Edgeの生成時には、各々のEdgeを識別するためのUUIDと、サーバ接続時に利用するシークレットIDのペアが発行されるので、それらのIDを手元に控えます ステップ4 設定ファイルの書き換え 作成したEdge情報を踏まえて、関連する設定ファイルを書き換えていきます。 設定ファイルの全体ではなく、ポイントとなる部分を抜粋して例を記載しています。 設定対象ファイルのパスは代表的なものを示していますが、運用環境に応じて自由に変更可能です。 intdash Edge(コントローラ側) 編集対象: /etc/opt/intdash/manager.conf 空欄の部分に接続先のintdashサーバのアドレス、EdgeのUUIDとシークレットIDを記入します。 以下のようなloggersにintdash Bridgeで使用するFIFOの設定を追記します。 "connections": [ { "fifo_tx": "/var/run/intdash/logger_001.tx", 注:intdash Edgeとintdash Bridgeの間の通信で使うFIFOを指定しています "fifo_rx": "/var/run/intdash/logger_001.rx", "channel": 1 } ], "details": { "plugin":"fifo", "plugin_dir": "$LIBDIR/plugins" } clientsのtype:realtimeに "dst_id": ["<TurtleBot3のEdge UUID>"] を記載する。 intdash Edge(TurtleBot3側) 編集対象: /etc/opt/intdash/manager.conf 空欄の部分に接続先のintdashサーバのアドレス、EdgeのUUIDとシークレットIDを記入します。 loggersにintdash Bridgeで使用するFIFOの設定を追記します(コントローラと同じく)。 clientsのtype:controlを追加して、以下のようなコントローラEdgeからサーバにアップロードされたデータを受信する設定を行います。 "ctlr_id": "<コントローラのEdge UUID>", "ctlr_flt_ids": [ "/joy"    注:joyトピックを受け取るという意味 ], "ctlr_ch": 1, "ctlr_dtype": 14 注:バイナリデータを受け取るという意味の設定 intdash Bridge(コントローラ側) 編集対象: /etc/opt/intdash/params.yaml サーバへ送信して他のEdgeと共有したいトピック名をここで指定します。 incoming: enabled: false # サーバからのデータは受信しない queue_size: 100 suffix: "" outgoing: enabled: true # サーバへデータを送信する max_array_size: 500 topics: - topic_name: "/joy" # アップロードしたいトピック名 send_mode: "raw" queue_size: 500 intdash Bridge(TurtleBot3側) 編集対象: /etc/opt/intdash/params.yaml サーバからの受信を有効にします。 incoming: enabled: true # サーバから来るデータをROSに送り出す queue_size: 100 suffix: "" outgoing: enabled: false # サーバにデータは送らない ROS launch(コントローラ側、TurtleBot3側共通) 既存のノードの起動設定に加えて、intdash Bridge のノードを起動する設定をlaunchファイルに追記します。 launchファイルの編集例 <arg name="paramsfile" default="/etc/opt/intdash/params.yaml" /> 注:前ステップで編集した設定ファイルをここで指定します <node pkg="intdash_bridge" name="intdash_bridge" type="intdash_bridge_node" output="screen" clear_params="true"> <param name="fifo_tx_raw" value="/var/run/intdash/logger_001.tx" /> 注:intdash Edgeの設定と合わせて、intdash Edgeとintdash Bridgeの間の通信で使うFIFOを指定しています <param name="fifo_rx_raw" value="/var/run/intdash/logger_001.rx" /> <rosparam command="load" file="$(arg paramsfile)" /> </node> ステップ5 動作確認 次のようなステップで起動させることで、動作を確認できます。 intdash Edgeの起動 パッケージと共にインストールされている /etc/systemd/system/intdash-edge.service をsystemctlで起動させます *3 。 ROS launchの実行 インターネットに接続した環境で、roslaunchコマンドを使い前のステップで設定した環境を起動させます。設定に問題なければ以下の動画のようにコントローラでの遠隔操作ができようになっているはずです。 youtu.be 終わりに 今日はaptpodのROSに関する取り組みをご紹介しました。いかがだったでしょうか? ネットワーク越えの設定は難しいように思われますが、intdashと組み合わせてステップを踏んで設定していくとで、意外と簡単にROSのネットワーク接続ができることが伝わっていると幸いです。 現在、aptpodでは、今日紹介したROSやその他の環境も想定してリアルタイムでインタラクティブな管制制御システムの迅速な構築を可能にするintdash CONTROL CENTERというソリューションフレームワークを開発しています。 昨日の記事 に詳細が書かれていますので、気になった方はそちらも合わせてご覧ください。 参考情報 aptpod,Inc CONTROL CENTER aptpod,Inc. Docs *1 : intdash Edgeの基本機能はintdash Edge Agentとして提供されています。今回は実績のあるバージョンを紹介していますが、最近新しいintdash Edge Agent2がリリースされたので、今後はそちらを利用していくようになる予定です *2 : AMD64アーキテクチャー上のLinux、Raspberry Pi 上のRaspbianなどをサポートしています *3 : manager.confの配置や、その他のパス設定を変えたい場合はserviceファイルを編集してください。
アバター
aptpod Advent Calendar 2022 の15日目を担当します、ソリューションアーキテクトの岩坪です。 今回の記事では当社が2022年12月にベータリリースしました、モビリティ・ロボットのフリート管理や遠隔監視、遠隔制御を実現するための 管制制御システム向けのソリューションフレームワークである「 intdash CONTROL CENTER 」 を紹介させて頂きます。intdash CONTROL CENTERを利用すると 低コスト・短期で、データ利活用が可能な、拡張性のあるシステム を構築することができます。 記事の後半にはintdash CONTROL CENTERを利用した管制制御システムを想定したユースケースのデモ動画も載せていますので、「何はともあれまずはどういうことができるの」という方は先に デモ動画 を見てみて下さい。 はじめに intdash CONTROL CENTER とは何? intdashを利用したデータ伝送プラットフォームの特長 intdash CONTROL CENTERで実現できること intdash CONTROL CENTERを使ったデモ紹介 おわりに はじめに aptpodのソリューションアーキテクトという役割は、お客様のデータ収集やデータ利活用における課題解決や、お客様業務のDX(デジタルトランスフォーメーション)実現に向けて、当社コアプロダクトである IoTデータ伝送プラットフォーム intdash をベースにソリューション提案を行い、お客様と共にプロジェクトを推進、発展させていくことをミッションとしています。 ソリューションアーキテクトってどんな仕事? - aptpod Tech Blog ここ数年は、様々なモビリティ・ロボット向けにintdashを活用頂き、 建設機械・重機・農機、配送ロボットや警備ロボットといったサービスロボット、工場や物流倉庫内のAGV(Automatic Guided Vehicle)・AMR(Autonomous Mobile Robot)等において、 遠隔監視、遠隔制御、フリート管理 を実現したいお客様も増えてきています。 そういった背景もあり、aptpodは様々なモビリティ・ロボットにおける遠隔監視・遠隔管理/フリート管理・遠隔制御向けのプロダクト企画、開発を進めており、 この度、2022年12月に管制制御システム向けのソリューションフレームワーク「intdash CONTROL CENTER」をベータリリースすることができました。 intdash CONTROL CENTER とは何? 今回紹介するintdash CONTROL CENTERは、 モビリティやロボット向けのリアルタイムかつインタラクティブな管制制御システムを迅速に構築 できるようにするための、ソリューションフレームワークです。 本ソリューションを活用頂くことで、ロボットや自動車、建機・重機といった複数のモビリティを対象に、遠隔からモビリティ群を監視・管理することができ、必要に応じて人の手による遠隔指示・操作の介入を行うことができるようになります。 こういった管制制御システムを構築し、運用していく為には、そこに至るまでに 要件定義や機能開発、検証(PoC)のために多大な開発コスト、期間が必要 になるため、システムを導入したいと考えていても、なかなか立ち上げに進められない方々が多いのが現実です。導入検討の初期段階からいきなり本番運用を見据えた全ての要件定義や運用方法を定めるということも現実的ではないため、小さなPoCのフェーズからはじめて徐々に要件を定めつつ、開発、検証のサイクルを回していく必要もあります。 intdash CONTROL CENTERはまさにこういった「管制制御システムを作っていきたいが、何からどう手を付けてよいのか、いきなり膨大な予算を取るのは難しい…。」と考えられている方にも適したソリューションです。本ソリューションの、 データ収集・データ保存・データ管理・データ可視化、といった基本機能をまずは活用頂くことで短期・低コストで初期フェーズのシステム構築を実現 します。検証を繰り返す中で、必要となった機能はあとから拡張開発することも可能なので、段階的に運用に向けたシステム構築を進めることができます。 intdash CONTROL CENTERの適用シナリオとしては、下記のようなものがあげられます。 工場や物流倉庫におけるAGVの運用監視・遠隔制御介入 建設現場における建設機械の運用監視・遠隔指示 スマートシティにおける自動運転モビリティの運用監視・遠隔指示 intdash CONTROL CENTERの適用シナリオ intdash CONTROL CENTERを利用頂くことで、個別開発の要素を減らし、ベースとなる機能の検証も減らすことができるので、 お客様の実現したいことに対して、お客様自身が注力すべき領域のみに集中 してシステム構築を進めることができるようになります。 intdashを利用したデータ伝送プラットフォームの特長 intdash CONTROL CENTERの説明の前に、まずは本ソリューションのベースとなる、当社のコアプロダクト intdash に関して概要を説明します。 intdashに関する詳細は、下記を参照下さい。 aptpod,Inc About intdash intdashでは自動車やロボット・産業機械や制御・可視化アプリケーションなど、短期間に大量のデータを発生させるデバイスをモバイル網やインターネット網を経由して相互にライブ接続することができます。intdashを流れるストリーミングデータはそのまま時系列データストアに保存され、Visual M2Mでの可視化やAnalytics Servicesでの計算処理や機械学習に利用することができます。 各種デバイスからのリアルタイムなデータ伝送と、時系列データとして様々なデータをサーバへ保存し、可視化をするといったデータ伝送プラットフォームの実現のために、当社からは以下のミドルウェアおよびアプリケーションを提供します。 サーバサイドミドルウェア: intdash Server エッジサイドミドルウェア: intdash Edge 時系列データの可視化アプリケーション: Visual M2M Data Visualizer 管理ユーティリティ: Edge Admin Console、Edge Finder、Meas Hub intdashを利用頂くことで、下記の特長を持つIoTデータ伝送プラットフォームを構築することができます。 短期間に大量のデータが発生するような 高頻度のデータ を扱うことができる 高いリアルタイム性 でデータ伝送ができる 伝送時にパケロスした データの完全回収 ができる 多種多様なデータに対して 時刻を同期してデータ管理 が行える サーバに保存された データを後から利活用 できる 上記の通り、intdashはクラウドなどのサーバに構築したintdash Serverにモビリティのデータをリアルタイムに保存し、データを管理・活用することができるものです。モビリティの機体やデータを管理するための、管制制御システムのようなモビリティ管理プラットフォームをサーバをハブとしたデータ伝送システムとして構築するのが望ましい理由としては、いくつかあげられます。 管理対象のモビリティに問題が発生した際に、問題発生時のモビリティのデータをエビデンスとしてあとから確認したい( 過去データの再生 ) 管理対象のモビリティのデータは様々な拠点から、複数の利用者が確認したい( 複数拠点からのアクセス ) 収集したモビリティのデータをただ貯めておく、可視化するだけでなく、データを利活用してDXを推進したい( データの利活用 ) こういったニーズがある場合は、 限定された拠点や環境においてのみ利用可能なデータとして管理するのではなく、intdashのようにクラウドなどのサーバをハブとしたシステムとして、モビリティのデータを伝送し、保存、管理 する必要が出てきます。intdashを利用頂くことで、これらのニーズに応える管制制御システムの構築が可能となり、これが本記事で紹介するintdash CONTROL CENTERで構築したシステムの特長にもなります。 intdash CONTROL CENTERで実現できること 改めて説明すると、intdash CONTROL CENTERはモビリティやロボットのリアルタイムかつインタラクティブな管制制御システムを迅速に構築できるようにするための、ソリューションフレームワークです。 intdash CONTROL CENTERは下記のコンポーネントで構成されます。 モビリティの機体データの送受信処理を行うエッジ側のソフトウェア データストリーミング中継処理やデータ保存を行うサーバ側のソフトウェア リアルタイムな群管理や個別機体の状態モニタを行えるWEBアプリケーション intdash CONTROL CENTERを構成するコンポーネント それぞれのソフトウェアコンポーネントを活用することで実現できるintdash CONTROL CENTERの機能と特長について説明します。 (1)リアルタイムなフリートマップマッピング 複数モビリティの位置情報や、モビリティに搭載されたカメラの映像などのデータをマップマッピングして可視化できる、WEBベースの統合監視環境をリファレンスアプリケーションとして提供します。 本アプリケーションを利用することで、離れたところから現場で稼働する複数のモビリティの稼働位置、稼働状況を確認することができます。 本アプリケーションは、以下のような開発に活用頂くことができます。 屋内シナリオにおける対象となるエリアのマップなどを画像データとして背景に表示したUI開発 屋外シナリオにおけるOpenStreetMapやGoogle Mapsなどを利用したUI開発 モビリティ個別やモビリティ群全体に対するコマンド送信による遠隔指示機能の実装 (2)モビリティの様々なリアルタイムデータを確認可能なダッシュボード モビリティの詳細データをリアルタイムにダッシュボードに表示して確認することができます。 制御データや映像データなど様々なデータをリアルタイムに表示することが可能であり、ノンプログラミングでユーザによる自由なダッシュボードの構成変更が可能です。 モビリティ毎の状態(ステータス)、速度、稼働率などの稼働状況や、バッテリー稼働のモビリティのSoC(State Of Charge)やSoH(State of Health)など、モビリティ管理に必要な詳細なデータを遠隔から監視できるようになります。 ダッシュボード上のVisual Partsを変更することで、対象となるデータの値を表示するだけでなく、時間変化に伴う稼働率状況の変化などをグラフ表示することもできます。 (3)モビリティを遠隔操縦するためのコントローラ接続と操作データ伝送 ゲームコントローラなどの様々な操作デバイスを接続するためのエッジデバイス用のコンポーネントを提供します。本コンポーネントを利用頂くことで、エッジデバイスに接続されたコントローラの操作情報を操作対象であるモビリティへ遠隔からリアルタイムにデータ伝送し、リアルタイムな遠隔操作・操縦を実現します。 倉庫や工場内などのモビリティはAMRのような自律走行やAGVのような磁気テープ上を無人走行するケースが多いですが、予期しない障害物が置かれてしまうなどして動作不能となるケースがあります。その場合に、モビリティの異常状態(動作不能)を検知して、一時的に遠隔からの人の手による操縦を介して復帰可能な位置まで移動させるような場合に、遠隔操縦が活用できます。 (4)ロボット/モビリティ、センサーからカメラまで様々なデバイスの接続 ロボットや自動車などのモビリティ、またモビリティ上に搭載されるセンサーなどの様々なデバイスを接続して、モビリティのデータ収集するための、エッジデバイス用のコンポーネントを提供します。本コンポーネントは、エッジデバイス側のソフトウェアコンポーネントである「Device Connector」として提供します。 Device Connectorはターゲットとなるデータデバイス(モビリティ自体、センサー、カメラなど)からデータを取得して、intdash Serverにデータ送信を行う「intdash Edge Agent」にデータを受け渡す機能を持ちます。 Device Connectorを利用することで、下記のような様々な形式のデータをフュージョンストリーミングでintdash Serverへ送信することが可能です。 ロボットにおけるROS1/ROS2のメッセージ モビリティにおけるCAN(Control Area Network) 汎用センサー、ビデオなどのセンサーデバイス (5)データの収集・保存と利活用 モビリティから収集されたすべてのデータはサーバに永続化されるため、運用時のデータは過去データを再生することで当時の状況を詳細まで確認することが可能です。 これにより、異常発生時には、関係者によるデータレビューもすぐに行うことができます。これは国内外など関係者が様々な拠点にいる場合でも同様で、同じデータに各拠点からアクセスしてデータ内容を確認することができます。 また、サーバに保存されたデータを活用することで、詳細なデータ解析フローを実現することもできます。運用時に複数のモビリティのデータを都度、人の手により確認して、解析することは現実的ではないので自動化された解析フローを構築することで、効率的な管制制御システムの運用を行うことができます。 (6)豊富なSDK・APIを利用した拡張開発 intdash CONTROL CENTERでは、用意されたSDK、APIを利用することでリアルタイムデータ処理アプリケーションの開発が可能です。お客様ごとの、利用されるモビリティや、運用シーンに合わせて下記のような拡張開発を行うことができます。 アラート機能 詳細データを活用した異常検知 リアルタイム分析による異常検知 AIを利用したリアルタイム映像分析 モビリティ個別の稼働率計算 SDKなど拡張開発に必要となる情報は下記リンクにも置いてありますので、ご興味ある方は参照下さい。 aptpod,Inc Development aptpod,Inc. Docs intdash CONTROL CENTERは上記の機能を実現するソフトウェアコンポーネントを提供します。これをベースにユースケースに応じた、拡張性を持ったシステム開発が可能になります。 前述の通り、ゼロから開発を進めると費用、期間ともに大きく掛かってしまう、モビリティ/ロボット向けの管制制御システム、遠隔操縦システムですが、本ソリューションを導入し、全ての機能または一部の機能を活用頂くことで、 低コスト、短期での本番運用に向けたシステム構築 ができるようになります。 上記にあげた機能のいずれかの実現を目ざしている、または、上記のような機能実現に課題があるといったお客様は是非、当社へご連絡頂き、intdash CONTROL CENTERの活用について一緒に検討させて下さい。 intdash CONTROL CENTERを使ったデモ紹介 これまで説明してきたintdash CONTROL CENTERを利用した、2つのユースケースにおけるデモを紹介します。1つ目は 自律走行ロボット群のフリート管理 、2つ目は 移動ロボットの遠隔操縦・コマンド指示 のユースケースです。 (1)自動走行ロボット群のフリート管理 ROS(Robot Operation System)のシミュレータである Gazebo 上で、屋内工場内に6台の自動走行ロボットを稼働させています。ロボット内はROS1で構築しています。 それぞれのロボットにはintdash Serverとデータ送受信を行うための、intdash EdgeとDevice Connectorを搭載しており、各機体の位置情報、カメラ映像などをリアルタイムにintdash Serverに送信しています。 intdash Serverに送信された位置情報をもとに、intdash CONTROL CENTERのリファレンスアプリケーションであるフリートマップアプリケーションを使用して、 各機体の位置や状態、カメラ映像をリアルタイムに可視化 することができます。 各ロボットの詳細なデータを確認したい場合には、フリートマップアプリケーションからVisual M2M Data Visualizerに遷移して、 機体データの詳細をダッシュボード上で確認 することができます。 今回のデモではVisual M2M Data Visualizerで、各ロボットのSoC, SoHや稼働率をダッシュボード上に値表示、グラフ表示を行っています。 本デモのように遠隔監視室から、稼働しているロボットのマップ上の位置や、SoC/SoH、稼働率といった稼働状況を監視することで、 管理対象のロボットが安全かつ効率的な作業が実施できているかを確認 することができます。 システム構成 youtu.be 【動画説明】 3:30頃まではフリートマップアプリケーション上に複数のロボットの位置情報を表示しています。画面下部には選択しているロボットの名称や状態、カメラ映像を表示しています。 3:30頃からVisual M2M Data Visualizerで6台のロボットそれぞれの詳細データをダッシュボード上に表示しています。速度、角速度、SoC/SoH、稼働率などを値で表示しています。 4:30頃からは同じくVisual M2M Data Vizualizerで6台のロボットのSoCや稼働率の推移をダッシュボード上でグラフ表示しています。 本動画では同じディスプレイでそれぞれのアプリケーションを順番に表示していますが、実際の遠隔監視室では複数のディスプレイを配置して、それぞれのアプリケーションを並べて同時に確認することもできます。 (2)移動ロボットの遠隔操縦・コマンド指示 オープンソースの移動ロボットプラットフォームである「 Turtlebot3 」(実機のロボット)とGazebo上のロボット(シミュレータ上のロボット)を使用した遠隔操縦のデモです。 制御対象のロボット(Turtlebot3)はROS1で構築しており、ロボットに搭載したRaspberry Piにintdash Severとデータ送受信するためのintdash EdgeとDevice Connectorを搭載しています。 同じく、Gazebo上のロボットにもintdash EdgeとDevice Connectorを搭載しています。 遠隔操縦用のコントローラとしては「 DualSense 」を使用しています。操作情報をintdash Serverに送信するために、Raspberry Piを用意し、intdash EdgeとDevice Connectorを搭載しています。DualSenseとRaspberry PiはBluetoothで接続して、コントローラのボタン、ジョイスティックの情報をリアルタイムにRaspberry Pi上のintdash Edgeを介して、intdash Serverに送信します。 intdash Serverに送信された操作情報は、ロボット上のRaspberry Piが受信して、操作情報に従い、ロボットの車輪やアームを動作させます。 本デモの構成では、ロボットに搭載されたカメラ、センサ情報をリアルタイムにVisual M2M Data Visualizerで監視を行いながら、 必要な場合には、人の手を介して遠隔操縦を行うことが可能 となります。 また、Visual M2M Data Visualizer上のボタンを操作することで、ロボットに対するコマンド送信を行うこともできるので、 遠隔監視室からロボットへ指示を行うことが可能 です。 システム構成 www.youtube.com 【動画説明】 0:30頃までは、画面右下に表示されているカメラ映像のDualSenseを操作して、Gazebo上のロボットを遠隔操縦しています。Gazebo上のロボットの動きは画面左下のGazebo上のカメラ映像と、LiDAR情報から確認できます。 0:40頃に掛けて、遠隔操縦の制御対象をGazebo上のロボットから、Turtlebot3に切り替えています。 1:15頃までは、DualSenseを操作して、Turtlebot3を遠隔操縦しています。Turtlebot3の動きは、画面右下のカメラ映像と、画面左上のTurtlebot3に搭載したカメラの映像、LiDAR情報から確認できます。 1:25頃からは、Visual M2M Data Visualizer上の、画面右上の青いボタンを押すことで、Turtlebot3に「アーム位置をリセットする」コマンドを送信しています。青いボタンを押すと、画面右下のTurtlebot3のアーム位置が初期位置に移動する様子が確認できます。 おわりに 今回は当社が提供する、 モビリティやロボットのリアルタイムかつインタラクティブな管制制御システムを迅速に構築するためのソリューションフレームワークである「intdash CONTROL CENTER」 を紹介させて頂きました。 intdash CONTROL CENTERを導入して管制制御システムを構築することで、下記の特長を持つシステムが実現できます。 低コスト、短期でシステムを構築 拡張性のあるシステムを実現 クラウドに保存されたデータを利活用可能 ロボット管制・管理、遠隔操縦、フリート管理などに課題をお持ちの方は、是非当社にご連絡下さい。 intdash CONTROL CENTERを活用頂くことで、課題解決を行い、本番運用に向けた管制制御システムを迅速に実現できるようお手伝いできればと思います。 また、当社ではロボティクス分野向けのソリューションの他にも、自動車分野向けのパッケージプロダクトも開発を進めています。 aptpod,Inc REMOTE CAL 【intdash AUTOMOTIVE PRO REMOTE CAL】ECU遠隔適合システムのご紹介 - aptpod Tech Blog intdash CONTROL CENTER、intdash AUTOMOTIVE PRO REMOTE CALともにパイロットユーザーを募集中です! aptpodは今後も、各産業のDXを進めるためのプロダクトを企画、開発を進めていきます。intdash及び、当社プロダクトで解決できる課題があれば、是非、お気軽に下記リンクからご連絡下さい。 aptpod,Inc. Contact
アバター
aptpod Advent Calendar 2022の14日目、担当はコーポレート・マーケティング室、デザインチームの「チェン ・ルイ」です。普段は社内製品のアプリケーションのUIデザイン業務を行なっています。 今年8月から弊社デザイン業務が少しずつSketchからFigmaに移行しています。 弊社のデザイナー高森の8月の記事 では俯瞰的にデザインツール変更や導入するときに確認したポイントを紹介しました。 今回は実際にFigmaを使ってデザインファイルを制作、管理するときに実用的なTipsをいくつか紹介します。 グリッドの整理機能 Selection Colorsで色変数の一括適用 Sectionの活用 PageやSectionを利用してコンポーネントをグルーピングする 最後に グリッドの整理機能 複数のオブジェクトを選択して配列したあと、隅にあるグリッドアイコンをクリックすると、配置を整理できます。 オブジェクトはドラッグして再配置したり、直接画面で間隔を調整したり、プロパティパネルで数値を調整することも可能です。 Sketchではグリットを作る場合、1行、1列ずつ整列する必要があります。Figmaのグリッド整理機能があると時短になります。 グリッドレイアウトを制作するときに試してみましょう。 Selection Colorsで色変数の一括適用 デザインコンポーネントを整理するとき、色を一括で色変数に適用したい場合、 Selection Colors の設定を利用すると便利です。 Selection Colors はFills、Strokes、Solid colorsなどを跨いで一括で色を表示しています。 特に複数のレイヤーを含むコンポーネントは、レイヤーを1つ1つ選択しなくても大丈夫なので、かなり時間が節約できます 。 以下の例はボタンのテキストに色変数を適用する例になります。 【 テキストレイヤーを選択して適用する場合 】 コンポーネントのテキストレイヤーを1つ1つ選択するとかなり手間がかかります。 【 Selection Colorsを利用する場合 】 ボタンを一括で選択して、まとめて変換できます。 コンポーネントに色変数の一括適用したいときに、 Selection Colors を使ってみてください。 Sectionの活用 Sectionは最近追加された機能であり、Sketchには無い、上位のレイヤータイプです。複数のFrame(Sketch のart board相当)をまとめて管理することが可能です。 コンポーネントやデザインガイドを整理するとき、グルーピングして管理したい場合もあります。コンテンツの増減によって、全体の背景の大きさを調整する場合もあります。この場合、Sectionをおすすめします。 【 Frame 】 【 Section 】 上記動画の通り、Frameを使用する場合Contraintsの設定はデフォルトで Scale になり、そのまま広げるとUI要素のサイズも変わってしまうため、まずはLeft、Topに設定する必要があります。 一方、Sectionを利用するとContraintsの設定が関係なく自由に広げてもUI要素のサイズが変わりません。細かいところですがかなり作業時間を節約できます。 現状、SectionとFrameの使い分けは主にこのようになります。 Section→ コンポーネントのグルーピング Frame → UI画面のベース UIコンポーネントを整理するときに、Sectionを活用してみてください。 PageやSectionを利用してコンポーネントをグルーピングする Sketchと同じく、コンポーネントの「/」命名規則が適用されます。 過去SketchでComponentの名前をつける際、「/」で分割を多用するとコンポーネント名が長くなりすぎます。グループ名の漏れやタイポが原因でグルーピングできず、後程編集し直すこともたまに発生しました。 Figmaでは、PageやSection、Frameを使用してカテゴリを作成することができます。コンポーネントをフレームに追加すると「/」と同じように整理されます。コンポーネントを新しいフレームにドラッグするだけで、すぐにコンポーネントを再編成できます。 PageとSectionの活用によって、あらかじめSectionやページに配置と最初からグルーピングでき、コンポーネントの名前が短くなり、二度整理する手間をなくすことができます。 現状iconの画面や目次の階層はこのような関係になります。 階層の順番はこのようになります: ページ > Section > Frame > Component名 UIコンポーネントを整理するときに、是非活用してみてください。 最後に Figmaを活用するTipsは他にもたくさんありますが、今後アップデートがあればまた紹介していきたいと思います。
アバター
aptpod Advent Calendar 2022 の13日目を担当します、ECUソリューショングループの村松です。 自動車産業は、100年に一度の大変革の時代といわれており、CASE Connected(コネクティッド)、Autonomous/Automated(自動化)、Shared(シェアリング)、Electric(電動化)、クルマを介した様々なサービス化が進んでおります。 排ガス規制をクリアする為に導入されたECU(Engine Control Unit)は、いつのまにかECU( Electronic Control Unit)となり、電気が流れる車載機能のほぼ全てにECUが存在すると言われております。 昨今、安全性や快適性が追求され複数のECUにまたがるロジックの開発、グローバル開発車両に伴う各国での検証は、実走行試験の複雑化や長期化が課題となっております。 aptpodでは、低遅延、ハイスループットのIoTソリューションintdashの利点と汎用計測適合プロトコルXCP(eXtended Calibration Protocol)による遠隔適合ソリューションintdash AUTOMOTIVE PRO REMOTE CAL(CALibration)で、皆様の課題解決へお力になりたいと考えております。 今回は、β版のリリースを予定しております intdash AUTOMOTIVE PRO REMOTE CAL をご紹介したいと思います。 2021年にご紹介しました CCP(CAN Calibration Protocol) DAQ(Data AcQuisition)サービスについてのtech Blog もご参照ください。 tech.aptpod.co.jp REMOTE CAL システム構成 REMOTE CALの機能 遠隔適合 ユースケース 適合試験者 現地作業者 最後に REMOTE CAL システム構成 REMOTE CALは高速で確実な遠隔データパイプライン環境を実現するサーバーシステム、及び車両計測適合用に制定されたマークアップラングエッジA2L(ASAM MCD-2 MC Language)に対応したWebアプリケーションで構成されます。それにより、計測機器メーカー各社のツールと連携し遠隔よりリアルタイムでの計測適合環境を構築します。 REMOTE CAL UI ECU内部情報が記載されたA2Lの登録、リモート先のEdgeの設定、データ可視化 ECU内部パラメータ(定数・変数値)の表示と変更 REMOTE CAL Server EdgeからのECU内部情報を変換、時系列に整列と格納 REMOTE CAL UIからのECUパラメータ変更をEdgeへ伝達 REMOTE CAL Edge 各社ECU計測器・インターフェースと連携し、ECU内部情報をserverへ転送 UIで設定されたECUパラメータを測定器I/F経由にてECUへ書き込み REMOTE CALの機能 ECU内部構造を記載したA2Lファイルの統合的に管理 XCP接続可能なECUに対しRAM値の計測及び、修正や変更など適合が可能 リアルタイムでのECUの計測・適合と合わせ、映像、位置情報、CANなど様々な情報をノンプログラムのダッシュボード上に配置し可視化 遠隔適合 ユースケース 適合試験者 試験車両をリアルタイムでECU内部実測値、画像、位置情報、CANなどを同時にモニタ可能 遠隔にある複数台の試験車両の情報を同時にダッシュボード上に表示 トラブル時の状況をモニタでき、遠隔地にある試験者へ迅速なサポートが可能 現地作業者 ダッシュボードにより、車両の状況の確認可能 適合作業に必要な車両の操作、確認可能 トラブル時の現地対応はもとより、開発拠点からのリモートサポート可能 最後に intdash AUTOMOTIVE PRO REMOTE CALは、製品版リリースへ向けて順次機能を拡充していく予定です。β版入手方法、製品のご質問や追加機能のご希望などございましたら、お気軽に こちらのリンク までご連絡ください。 www.aptpod.co.jp
アバター
本日は aptpod Advent Calendar 2022 の12日目、担当は開発本部のやべです。普段は EDGEPLANT 関係の開発業務をやっています。 さて、皆さん、スプラトゥーン3やってますか?12月から新シーズンが始まってますます楽しくなってきましたね。 aptpod には circle_switch なる slack のチャンネルがあるのですが、最近はもっぱらスプラトゥーンの話題です。先日も 8人集めてプライベートマッチやってました。 当初は最近調査していた Multipath TCP に関するきっちりした技術記事を書こうと考えていましたが、業務以外での社内の雰囲気も伝わるかと思い、このネタにしてみました。 概要 環境構築編 入力側の準備 制御(ゲーム操作)側の準備 調整編 実戦編 おわりに 目次はこんな感じです。イカ、よろしく~ ※本記事ではところどころスプラトゥーン3のプレイ画像が挟まりますが、任天堂のガイドラインを考慮してモザイク処理を施しております。見づらいですがご容赦ください。 概要 今回の目標は、キーボード入力を サーバーを経由 して、Switchにコントローラーの情報として送り、 実際に操作する ところまでになります。 まずはおおまかな構成について説明しておきます。 データの流れ 今回は手元にあった機材を流用して、よくある制御のパターンに近い構成にしています。 入力側:開発試作機( こちら で紹介しています)にキーボードを接続 制御側:Raspberry Pi 4B を Bluetoothコントローラーとして動作するように設定し、Switch からHDMI映像を入力する 実際の機材の接続は、こんな感じでした。 入力側環境 制御側環境 当初制御側のエッジでは Raspberry Pi 4B のUSBポートを直接利用していたのですが、それだと Bluetooth 接続時にHDMI入力が切れる問題が発生したため、セルフパワー給電ができるUSBハブを介することで動作を安定させています。写真に写っているのは StarTech 社のハブですが、同社の製品は信頼性が高く、aptpod でもよく採用しています。 www.startech.com 環境構築編 データのやり取りには、aptpod の製品である intdash Edge を利用しています。利用方法などを知りたい方は、 こちら をご覧ください。 入力側の準備 入力側では、以下のデータを取得してサーバーに送ります。 キーボード入力 カメラ映像(キーボードを映すもの) カメラについてはデフォルトで intdash Edge がサポートしているため、取得設定を行うのみです。キーボード入力については、実装スピード重視で、Python のライブラリを利用しました。 github.com キーボードの入力は、それぞれコントローラーの何らかのボタンに割り当てます。入力内容を変換する処理をどこでやるかは全体のシステム設計にもよりますが、データサイズを均一にするため整形を行ってサーバーに送りたいので、今回は入力エッジ側で変換するようにします。 CONTROLS = { "l" : "BA" , "k" : "BB" , "i" : "BX" , "j" : "BY" , ... } このような形で、入力データを2文字のコントローラー用のコードに変換しました(例:BA = Button A)。このデータを、ループして push/release のタイミングで送っていきます。 while True : event = keyboard.read_event() if event.name == "esc" : print ( "escape was pressed" ) break if not event.name in CONTROLS: continue ctrl = CONTROLS[event.name] if event.event_type == keyboard.KEY_DOWN: on_push(ctrl) else : on_release(ctrl) on_push 、 on_release では、FIFO経由で、データ送信処理を管理しているモジュール(Edge Agent)に対してデータを送っています。 制御(ゲーム操作)側の準備 制御側では、以下のことを行います。 キーボード入力をサーバーから受け取って、コントローラーとして動作する HDMI映像をサーバーへ送信する HDMI入力は、安価なキャプチャデバイスを使ってUSB経由で入力します。設定自体は一般的なUSBカメラと同じもので動作します。コントローラーとしての動作については、こちらの Python のライブラリを利用しました。 github.com 入力側からは、コントローラーの入力に対応したコードが送られてくるため、制御側では実際の定義に置き換えるようにします。 BUTTONS = { "BA" : nxbt.Buttons.A, "BB" : nxbt.Buttons.B, "BX" : nxbt.Buttons.X, "BY" : nxbt.Buttons.Y, ... } これらのデータが届いたタイミングで、対応するボタン入力(もしくはスティック入力)が動作するようにします。 while True : recv = fifo.read( 18 ) if len (recv) != 18 : continue d = decode(recv) if d[ "status" ] == 0 : # release button continue ctrl = d[ "ctrl" ] if ctrl in BUTTONS: nx.press_buttons(controller_index, [BUTTONS[ctrl]]) ... 調整編 とりあえず作っては見たものの、入力に対して反応が悪くなイカ? 初期バージョン 操作情報と一緒にCPU負荷を送っているのでそれを見てみると、制御側の負荷がかなり高くなっています。 制御側の負荷状況 おそらく入力を処理しきれていないため、かなり遅延が発生しているようです。そこでライブラリのコードを参考に、使うAPIの変更やキーボード入力の間引き、押し込み時間の調整など、いくつかの対策を行ったところ、かなり改善しました。 負荷軽減バージョン 赤枠のCPU使用率を見てみると、負荷が40%程度軽減されています。 スペシャル(必殺技的なやつ)もしっかり打てるぞ! スペースキーを押して 発動! 精度はさておき、ここまででキーボード入力を受け取って操作を行うというタスクについては完了しました。 実戦編 というわけで、いざ実戦投入! といっても、見知らぬ方々にご迷惑をおかけするわけにはいかないので、冒頭で話した社内プライベートマッチで一戦だけ行いました。 おろおろしているところを撃ち抜かれる図 結果、瞬殺。 映像の遅延やボタン入力の反応はさほど悪くないものの、スティック側の入力反映が微妙で思ったように動きません。また、移動しながらの視点変更など、同時入力を必要とするケースを考慮していなかったのも、けっこう辛いポイント。実際に社内で制御を扱っているプロジェクトでは色々と考慮して設計されているわけで、遠隔制御は1日にしてならず、と痛感いたしました(みんなすごい!)。 おわりに イカがだったでしょうか?intdash を利用した遠隔制御の雰囲気が伝わっていれば幸いです。 実際に自分でやってみた感想としては、単なる疎通まではたいして時間はかからないものの、その後の操作感の向上や安定性などを詰めていく作業が大変でした。ボードゲームのようなものならこれでも十分ですが、今回扱ったスプラトゥーンのように複雑な操作が必要なゲームに実戦レベルで対応するためには、更なる改善検討が必要になります。操作データの送信方法の見直しや処理の非同期化、Python以外の言語への置き換えなど、やれることはまだまだあります。 こんな記事もあるように、世の中的には遠隔制御とゲームの親和性も注目されていたりするので、今回やった取り組みは案外エントリーとしてはいいお題なのかな?とも思いました。 automaton-media.com ほな カイサン!!!
アバター
はじめに aptpod Advent Calendar 2022 9日目の記事を担当する、開発本部の加藤と申します。 aptpodでは自社製のハードウェアも提供しております。現在、コンピュータ製品には EDGEPLANT T1 がありますが、異なるニーズやユースケースにも対応できるような、測定用のペリフェラルを内蔵したコンピュータの試作機開発を行っています。この試作機の特長等についてご紹介させていただきます。こちらの試作機にご興味をお持ちいただけましたら、当社までお問い合わせください。製品化に向けたロードマップや、試作機の試用等についてご案内させていただきます。 はじめに 開発の背景 インターフェイスが少なくUSB周辺機器とセットで利用する必要がある 物理的なサイズが大きい 仕様概略 仕様詳細 外観および入出力 SOM 通信機能・GNSS機能 USB CAN 加速度・角速度センサ アナログ入力 電源ON/OFFの仕方 ストレージ 防水機能 社内テスト 動作温度範囲 静電気放電試験 ファスト・トランジェント/バースト試験 放射エミッション試験 自由落下試験 未実施の試験 実際のデータ収集での使用例 横浜ロボットワールド2022 最後に 開発の背景 aptpodでは、 intdash という双方向データ伝送プラットフォームを使用したデータ収集および遠隔制御サービスをご提供しております。 冒頭申し上げました通り、自社製のコンピュータには EDGEPLANT T1 があり多くのケースでご提供しております。このコンピュータはエッジ側でGPUを活用したAI処理を行う意図をもって開発しましたが、自社サービス専用ということではなく汎用的にも使用できるように設計されています。実際に アマゾンで単体販売 もしております。自社のサービスの全てでこの EDGEPLANT T1 を使おうとする場合には、以下の課題があります。 インターフェイスが少なくUSB周辺機器とセットで利用する必要がある 汎用的に使用できるようにUSBのポートを多く持たせ、インターフェイスの種類は少なく設計している為、USB周辺機器とセット利用が必要となります。その結果USB機器の製造も別途必要となります。製造する製品の種類が増えてしまうのは、生産管理が難しい、価格も高くなるなどのデメリットがあります。 物理的なサイズが大きい 処理能力が高くその際の放熱なども考慮されている為、それを必要としないケースではコンピュータ単体のサイズが必要以上に大きくなっていることになります。また、USBポートやそこからの供給電力を多く用意し多様な組み合わせに対応可能な汎用性を持たせており、用途が限定されるCANインターフェースやアナログ/デジタルインターフェースは内蔵しておりません。多くの場合、 EDGEPLANT CAN-USB Interface と組み合わせて構成しているのですが、測定対象が一定数以下の場合には、物量が必要以上に大きくなってしまいます。 課題解決の方法として、下記の条件を満たすエッジコンピュータを準備することを考えました。 弊社のデータ収集サービスでよく使われる測定用の機能を内蔵している。 内蔵している機能は全て同時に使用できる。 小型・軽量 より詳細な条件は、以下の通りとなります。 LTE通信機能を有する。 弊社のデータ収集サービス(データ完全回収)で使用できるCANやデジタル入力、アナログ入力機能を内蔵している。 内蔵している測定機能を全て同時に使用できる性能を有する。 自動車のデータ収集に必要十分な品質を備える。 動作電圧  9V~36V、動作温度範囲 -20℃~65℃。 長期間継続して購入可能であることが期待できる。 上記条件を満たすコンピュータが市販されていないか探してみましたが、全ての条件に合致するものは見つかりませんでした。その為、自社で開発・試作を行いました。 仕様概略 仕様概略につきましては、横浜ロボットワールド2022の参考出展時に配布させていただいたリーフレットをご覧いただければと存じます。 仕様詳細 仕様の意図や工夫した点などご説明させていただきます。 外観および入出力 サイズは幅88mm×奥行き94mm×高さ32mm(取付板を含まない)、質量は250gとなっております。自動車のダッシュボードの収納スペースやオートバイのシート下収納スペースにも収まるようにコンパクトにまとめました。 自動車に搭載する場合のサイズ感 入出力端子の配置は以下のとおりとなっております。 正面 背面 SOM SOMは、Raspberry Pi CM4を採用しました。コストパフォーマンスが高いこと、Raspberry Piは世に多く出ているハードウェアであり既にそこで動作するソフトウェアも多く作られていると考えられること、Linuxが動作すること、動作温度範囲が広いこと等が選定の理由です。Raspberry Piは弊社でも活用事例は多いです。以下は、Raspberry Piを使用した過去の記事のリンクです。 "リアルタイム"デジタルツインデモを展示しました IoTボタンによる回数記録基盤をAWSとRaspberry Piで構築する Bluetooth Low EnergyのclientアプリをBlueZとpythonで作ってみた intdashを活用したシステム開発 5Gのネットワークを計測してみた 通信遅延発生時にTurtlebot3を安全に遠隔制御する技術 ラズパイでCAN通信をして、車両の診断データを送受信してみた 通信機能・GNSS機能 内蔵の通信機能はLTEを採用しました。aptpod のユースケースではLTE通信が欠かせない為、必須要件であるからです。通信モジュールは、SIERRA WIRELESS社のEM7431にしました。これまで弊社で使用していたEM7430と比較して安価であること、GNSS機能も内蔵しておりコストパフォーマンスが高くなることが理由です。有線LANやWi-Fiが必要な場合には、USBから拡張していただく想定です。 USB USBポートは2ポートとしました。想定したのは、 EDGEPLANT USB Camera と CAN-USB Interface で2ポート、あるいは EDGEPLANT USB Camera とマイクで2ポートという使い方です。 データ収集ではカメラは使用頻度の高いデバイスなのですが内蔵してしまうと取付位置の自由度が下がってしまう為、USBによる外付けとしました。 マイクのインターフェースは、3.5㎜ミニジャックのものとUSBのものがあるのですが、データ収集サービスではマイクの需要はそこまで高くない為、汎用的に使えるUSBを使用することを考えました。 USBのコネクタはネジ止めができません。振動・衝撃でコネクタが外れないようにする為の高保持力(15N)のコネクタを採用しました。 CAN 接続したCANバス上のデータを取得する為のインターフェースです。測定用のサービスに使用する場合、CANに流れるデータ全てを記録する必要があります。CANのデータは高頻度で発生する可能性があり取りこぼしを起こさないようにする為に、専用のマイコンで受け取る仕組みにしました。内部回路は弊社の製品のCAN USB-Interfaceと同じにしました。 加速度・角速度センサ 筐体中心部に加速度・角速度センサICを実装しています。移動体の測定に使用することを想定している本製品にはあるべき機能と考えました。フルスケールが加速度は±2/±4/±8/±16g、角速度は±125/±250/±500/±1000/±2000dps、分解能はそれぞれ16bitです。 アナログ入力 下記の様な入力を想定して汎用的なアナログ入力ポートを4ポート設けました。入力回路は、インピーダンスを高くして接続先の動作の影響が少なくなる様意識しました。 各種状態検知:測定対象が出すエラー信号やLED制御信号の検出を行うケース センサ入力:測定対象に内蔵されているセンサーの電圧を測定するケース 各所電圧・電流検知:電圧や電流の測定を行うケース 外部スイッチ:自動車等の測定で運転者が任意のタイミングでスイッチを押し、後で検索しやすくするケース 電源ON/OFFの仕方 自動車に接続する場合を想定して、バッテリーが接続された状態でイグニッションキー(ボタン)の電圧を検出して電源ONする仕組みにしています。専用の入力端子があり、そこに9V以上の電圧印加で電源ONということです。入力がオープンかGNDレベルになると終了処理してからOFFになります。イグニッションキー(ボタン)は監視用のマイコンで常にチェックしています。このマイコンはCANバス信号もチェックすることが可能で、その内容によって電源ON/OFFする仕組み(Wake on CAN)も準備しています。電源OFF時の待機電流は、バッテリー電圧12V・周囲温度25℃の条件で約5mAでした。 ストレージ Raspberry Piシリーズと同様、ストレージはmicroSDカードを採用しました。データの信頼性の高い産業用のSLCモード64GB品を使用しました。また、意図しないバッテリー断でデータ破損しないように電断保護機能有りのものを選びました。 防水機能 防水機能について検討したのですがどうしても小型化と相反する為、外付けの防水ケースを別に設計・試作しました。ケーブルを通す防水ゴムは、ケーブルを先に通してからケーブル端を加工するものが多いのですが、この方式ですとUSBケーブルやアンテナケーブルの接続が困難になる為、コネクタ付のケーブルに取付けできるタイプを採用しました。 防水ケース 社内テスト 試作機で行った社内試験について簡単にご紹介させていただきます。国際規格の試験も行っておりますが、試験を行った試験場は認証試験場ではないことにご注意ください。 動作温度範囲 -20℃および65℃で起動及び24時間の連続動作を確認しました。 静電気放電試験 試験方法はIEC61000-4-2で、接触放電±8KV、気中放電±8KVで、動作停止しない・故障しないことを確認しました。 ファスト・トランジェント/バースト試験 試験方法はIEC61000-4-4で、電源ラインにノイズを印加する試験を行いました。テストレベル1(500V)にて、自己回復不可能な機能障害が無いことを確認しました。接続するディスプレイやUSBデバイスによって結果が大きく異なり、苦労しました。 放射エミッション試験 試験方法は、FCC Part15 Subpart Bで3m法で行いました。これも接続するディスプレイやUSBデバイスによって結果が大きく異なり苦労しました。本試作機単体(接続デバイスを選べば)では、ClassBで合格できそうなことを確認しました。 自由落下試験 試作機単体で1mの高さからコンクリートに自由落下させる試験を行いました。故障・変更・動作異常などなく問題ないことを確認しました。 未実施の試験 製品化を行う場合には最終の仕様にて下記についても試験を行いたいと考えております。 振動・衝撃試験 過渡伝導エミッション/イミュニティ(ISO7637-2) 放射イミュニティ(IEC61000-4-3) 伝導イミュニティ(IEC61000-4-6) 実際のデータ収集での使用例 本試作機を使用したデータ収集の例をご説明させていただきます。 試作機にソフトウェア( intdash Edge )を実装し、実運用に近い自動車での動作を確認しました。 構成図 搭載物一式 下記のデータ全て取得できることを確認できました。 カメラ:1台、解像度はHD、15fps GNSS:1台、位置検出、1秒に1回更新 CAN:内蔵CAN1ch+ EDGEPLANT CAN-USB Interface を1台追加=合計3ch 角速度センサ:3軸、各分解能16bit、104sps 加速度センサ:3軸、各分解能16bit、104sps 測定データは Visual M2M Data Visualizer で確認しました。各種データを様々な方法で可視化可能なツールで、測定中にリアルタイムで確認することも測定後に確認することも可能です。実際の表示画面を添付します。 Visual M2M Data Visualizerでの確認 横浜ロボットワールド2022 横浜ロボットワールド2022の弊社ブースでこの試作機の展示をさせていただきました。私も説明員として立ち会わせていただきました。 展示品 充電式電池(単3×8本)で駆動してワイヤレスにして、回転台の上に載せました。 EDGEPLANT CAN-USB Interface を接続。アナログ入力には測距センサも接続しました。回転させるとカメラ画像、内蔵の角速度センサのデータ、測距センサのデータが、リアルタイムに滑らかに表示される気持ち良い仕上がりになりました。 Visual M2M Data Visualizer画面 動作をみて頂いたお客様にも「センサーの状態がリアルタイムで確認できるのは良い」「電池駆動できるのは面白い」などご意見いただき大変好評でした。ご来場いただきありがとうございました。 最後に 試作したコンピュータを使用した弊社のデータ収集サービスについてご理解いただけたかと思います。もし、 intdash や本試作機にご興味いただけましたら、是非ご連絡をお願いします。また、本記事では記載できませんでしたが試作機(ハードウェア)は遠隔操作または自律移動ロボットのECUとしても利用可能ではないかと考えております。もし、Raspberry Piベースの堅牢なコンピュータにご興味あれば是非お声がけをお願いします。仮に本試作機(ハードウェア)をご評価いただけるということであればすぐにご提供致します。ご連絡をお待ちしております。最後まで読んでいただきありがとうございました。
アバター
はじめに こんにちは。 aptpod Advent Calendar 2022 8 日目を担当する、SRE チームの柏崎です。 SRE チームは、 intdash のインフラ関連の業務はもちろんですが、自社のコーポレートサイトやオフィスのネットワーク等の運用など、いわゆる「社内 SE」的な業務も担当しています。 今回は、社内 SE 業務のうちの 1 つで、私がアプトポッドに入社して以来 8 年ほど面倒を見ている、GitLab の運用についてご紹介しようと思います。 はじめに GitLab 運用ノウハウ 利用するバージョンは 1 つ前 ドキュメントをよく読む Ruby と Node.js Ruby のメモリアロケータ CI 環境 実行基盤 Docker Hub のミラーリング おわりに GitLab 運用ノウハウ ここでは、これまで長く運用してきた GitLab 運用の知見の一部をご紹介します。 ※ 現在 GitLab は、Omnibus と呼ばれる deb/rpm パッケージでのインストールや、Helm chart での k8s へのインストールなど、様々なインストール方式が提供されていますが、アプトポッドでは当初からソースインストール方式を使い続けています。 利用するバージョンは 1 つ前 GitLab は、年 1 回のメジャーリリース、月 1 回のマイナーリリースがあり、都度様々な新機能が追加されています。 私は、「1 つ前のマイナーリリース」の最新を追いかけるようにしています。 GitLab は、バグフィックスやセキュリティフィックスが含まれるパッチリリースが頻繁に行われています。 最新リリースでは、不具合やアップグレードドキュメントの不備があることが多く、そういったものは後追いのパッチリリースで修正されていきます。 当初は最新リリースを追いかけていましたが、前述のような不具合等で切り戻す事も多く苦労しました。 1 つ前のマイナーリリースを使うことで、これにアップグレードする頃には大きな不具合は修正されていて、切り戻しはほとんど発生しなくなりました。 ( こんな 1 行修正 MR を出したこともあります。) ドキュメントをよく読む アップグレード時に注意すべき点を把握するため、アップグレード手順だけではなく、インストール手順も含めてドキュメントをよく読むようにしています。 具体的には下記です。 Installation from source Ruby, Go, Git, Node.js, Yarn などの必要バージョンに更新が無いか、インストール手順に更新が無いか、重点的に確認します。 Installation system requirements Redis, PostgreSQL などの必要バージョンに更新が無いか確認します。 Version-specific upgrading instructions バージョン毎に、アップグレード時の注意点が書かれています。 Ruby と Node.js Ruby は rbenv、Node.js は nodenv を利用してインストールしています。 env 系を利用することで複数のバージョンを手軽に同居させられるので、Ruby や Node.js の必要バージョンが変わった際に、アップグレード作業時間外に事前に準備することができるようにしています。 Ruby のメモリアロケータ GitLab のような Ruby on Rails なアプリケーションを長く稼働していると、メモリ断片化によるメモリ使用量の逼迫に悩まされると思います。 当初は定期的に Puma ワーカーや Sidekiq プロセスを立ち上げ直すことで対処していました。 メモリアロケータを jemalloc にした Ruby を利用するようにしてから、メモリ使用量の上昇がゆるやかになり、このような対処が不要になりました。 jemalloc な Ruby に差し替えてからメモリ使用量が改善した様子 CI 環境 ついでに、CI 環境についても触れておきます。 GitLab は早くから CI サービスが統合されていて、私が GitLab 運用を担当するようになってからは、CI 環境の整備に力を入れてきました。 現在では、製品のアプリはもちろんのこと、プロジェクト独自のアプリも含めて、ほとんどのリポジトリで CI が実行されています。 実行基盤 Docker Machine で、GCP でプリエンプティブル VM インスタンスを利用し、低コストで運用しています。 CI は、ジョブ毎に n1-highcpu-4 (4 vCPU, 3.6 GB) のマシン上で実行され、最大 20 並列で動きます。 プリエンプティブル VM インスタンスを利用していることで、このような「つよつよ環境」を利用しても、月額 1 万強で済んでいます。 月額 1 万強 結構な数の CI が実行されている様子 Docker Hub のミラーリング CI は、ジョブごとに新規の環境で実行されるので、Docker Hub からのイメージの取得が都度行われます。 CI 実行基盤と同じネットワーク内に レジストリのキャッシュ を用意し、イメージ取得の高速化・トラフィックの抑制を行っています。 おわりに いかがでしたでしょうか。 GitLab や CI 環境の運用は、「みんなの業務は俺が支えてるんだ」感を味わえるので、実は結構好きな業務です。 だいぶまとまりが無い内容になってしまいましたが、アプトポッドの GitLab・CI についてのご紹介でした。
アバター
aptpod Advent Calendar 2022 7日目の記事を担当する、intdashグループの落合です。 いきなりですが、あなたは今年はどんなバグの調査をしましたか? 解決に時間がかかったもの、あっさり解決できたもの色々あったかもしれませんね。 私も問い合わせの度に調査してきました。バグだった場合もそうじゃなかった場合もありますが、調査は早く終わらせたいですよね。 この記事では、問題が出た時に早期解決できるように、ありがちな原因と確認コマンドをまとめてみます。 ただし、 IoTデバイス で Linux が稼働しており ネットワーク や USB で通信するシステム を前提として、そのシステムの状態によって起こるアプリケーションの問題をまとめます。 チートシート 原因ごとの解説 空き容量不足 メモリ不足 ファイルディスクリプタ不足 USB未接続 モバイル回線未接続 おわりに チートシート 現象例 原因 調査方法 ファイル保存でエラー 空き容量不足 df -h <確認したいディレクトリ> プロセスがOSに落とされる メモリ確保でエラー メモリ不足 dmesg -T | grep '[kK]ill process' vmstat 1 -a ファイルオープンでエラー ファイルディスクリプタ不足 ls /proc/$(pidof <プロセス名>)/fd' デバイスと通信できない USB未接続 dmesg -T | grep disconnect ネットワーク通信できない モバイル回線未接続 ping -c 1 <対象サーバー> 原因ごとの解説 空き容量不足 ファイルのフラッシュ時に空き容量が足りない場合エラーになります。 例 以下のコマンドでは C言語(久しぶりに書いた!)でファイルを作成をするコードをmain.cとして保存 gccでコンパイル を行います。 $ cat << EOF >main.c #include <errno.h> #include <stdio.h> #include <string.h> const char* contents = "C lang! It’s been a while."; int main(int argc, const char* argv[]) { // File open FILE* f = fopen(argv[1], "w"); if (f == 0) { fprintf(stderr, "fopen() failed: %s (%d)\n", strerror(errno), errno); return 1; } // File write size_t len = fwrite(contents, 1, strlen(contents), f); if (len != strlen(contents)) { fprintf(stderr, "fwrite() failed: %s (%d)\n", strerror(errno), errno); return 1; } // File close if (fclose(f) != 0) { fprintf(stderr, "fclose() failed: %s (%d)\n", strerror(errno), errno); return 1; } return 0; } EOF $ gcc main.c -o nospace-test コンパイルしたプログラムを空き容量が無いディレクトリ(以下の例では/tmp)に対して実行すると、fclose()のタイミングでエラーになります。 $ ./nospace-test /tmp/test fclose() failed: No space left on device (28) fwrite()のタイミングではなくfclose()でエラーににあるため、fclose()のエラーをハンドルしていないと気がつかないかもしれません。 フラッシュのタイミングでエラーになるので、fflush()を呼ぶ場合はそのタイミングでエラーになります。 調査方法 dfコマンドのAvailで空き容量を確認できます。 df -h <確認したいディレクトリ> $ df -h /tmp/test Filesystem Size Used Avail Use% Mounted on tmpfs 1.9G 1.9G 0 100% /tmp メモリ不足 メモリ不足によりメモリの動的確保がエラーになります。または、 OOM Killerによってプロセスがkillされます。 例 以下のコマンドでは、 C言語でメモリ確保を繰り返すコードをmain.cとして保存 gccでコンパイル を行います。 $ cat << EOF >main.c #include <stdlib.h> int main(int argc, const char* argv[]) { while (1) { void* leaked = malloc(1024*1024); // 1MB } return 0; } EOF $ gcc main.c -o nomem-test コンパイルしたプログラムを実行するとOOM Killerによりkillされます。 $ ./nomem-test Killed 調査方法 OOM Killerが実行されたことはログに残るためdmesgを検索することで確認できます。 dmesg -T | grep '[kK]ill process' $ dmesg -T | grep '[kK]ill process' [Mon Dec 5 07:30:05 2022] Out of memory: Kill process 269571 (nomem-test) score 350 or sacrifice child それとは別に、メモリリークしていることを確認したい場合は vmstat 1 -a で active の増加度合いで確認できます。 $ vmstat 1 -a & ./nomem-test [1] 288948 procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu----- r b swpd free inact active si so bi bo in cs us sy id wa st 1 0 0 1416648 2054456 252476 0 0 17 3 63 96 1 1 98 0 0 2 0 0 741920 2054472 700860 0 0 0 48 594 469 6 11 83 0 0 2 0 0 87432 2042036 1199888 0 0 36 24 640 522 7 11 81 0 0 Killed $ kill 288948 余談ですが弊社の intdash Edge Agent はvmstatを含むメトリクス情報をサーバーに送信するサンプル設定が入っています。以下はそのデータの一部を可視化したものです。 vmstatの可視化 ファイルディスクリプタ不足 1つのプロセスで使用するファイルディスクリプタが上限に達すると、新しいファイルを開くとエラーになります。 例 以下のコマンドでは C言語でファイルを繰り返し作成するコードをmain.cとして保存 gccでコンパイル を行います $ cat << EOF >main.c #include <errno.h> #include <stdio.h> #include <string.h> int main(int argc, const char* argv[]) { char path[256]; for (int i = 0; i < 1024 * 1024; i++) { sprintf(path, "/tmp/%d", i); FILE* f = fopen(path, "w"); if (f == 0) { fprintf(stderr, "fopen() failed: %s (%d)\n", strerror(errno), errno); return 1; } } return 0; } EOF $ gcc main.c -o nodescriptor-test コンパイルしたプログラムを実行すると、ファイルディスクリプタが枯渇しfopen()がエラーになります。 $ ./nodescriptor-test fopen() failed: Too many open files (24) 調査方法 特定のプロセスが開いているディスクリプタ番号が列挙されます。 ls /proc/$(pidof <プロセス名>)/fd' $ ls /proc/$(pidof nodescriptor-test)/fd 0 1 10 11 12 2 3 4 5 6 7 8 9 ファイルディスクリプタ数の上限は ulimit -n で確認できます。 $ ulimit -n 1024 USB未接続 USBデバイスが認識されておらず通信ができない。 物理的な切断も含めLinux OSがUSBデバイスを認識しなくなると(当たり前ですが)デバイスとの通信はできなくなります。 調査方法 USBの接続/切断はログに出力されているため、ログを検索することで確認できます。 dmesg -T | grep disconnect $ dmesg -T | grep disconnect [Mon Dec 5 08:39:10 2022] usb 1-2.4: USB disconnect, device number 3 このままだと、どのデバイスかわかりにくいので、 <bus>-<port[.port[.port]]> を検索すると、そのUSBデバイスが接続した時のUSBディスクリプタの情報を確認できます。 $ dmesg -T | grep 1-2.4 [Mon Dec 5 08:38:02 2022] usb 1-2.4: new high-speed USB device number 3 using tegra-xusb [Mon Dec 5 08:38:02 2022] usb 1-2.4: New USB device found, idVendor=2560, idProduct=c123 [Mon Dec 5 08:38:02 2022] usb 1-2.4: New USB device strings: Mfr=1, Product=2, SerialNumber=0 [Mon Dec 5 08:38:02 2022] usb 1-2.4: Product: e-CAM22_USB [Mon Dec 5 08:38:02 2022] usb 1-2.4: Manufacturer: e-con Systems [Mon Dec 5 08:38:02 2022] uvcvideo 1-2.4:1.0: Entity type for entity Processing 2 was not initialized! [Mon Dec 5 08:38:02 2022] uvcvideo 1-2.4:1.0: Entity type for entity Extension 3 was not initialized! [Mon Dec 5 08:38:02 2022] uvcvideo 1-2.4:1.0: Entity type for entity Camera 1 was not initialized! [Mon Dec 5 08:38:02 2022] input: e-CAM22_USB as /devices/3530000.xhci/usb1/1-2/1-2.4/1-2.4:1.0/input/input4 [Mon Dec 5 08:38:04 2022] usb 1-2.4: usb_suspend_both: status 0 [Mon Dec 5 08:39:10 2022] usb 1-2.4: USB disconnect, device number 3 モバイル回線未接続 モバイル回線が接続していない(電波が悪い)ため、通信ができない、通信遅延が大きい。 これも当たり前ですが、電波が悪ければ通信はできません。 調査方法 pingで対象のサーバーまでの接続と RTT を確認できます。 電波状況を ModemManager や ATコマンド などで確認することもできますが、過去に「電波は十分だけどアプリはネットワークに繋がらない」といったケースがあり、これは名前解決ができていなかったことが原因でした。 そのためアプリケーションと同じ状況を確認するという意味でも、まずpingを確認するのが良いと思っています。 ping -c 1 <対象サーバー> (サーバーはpingに応答する必要があるため、 ICMP に対応している必要があります) $ ping -c 1 google.com PING google.com(nrt12s36-in-x0e.1e100.net (2404:6800:4004:822::200e)) 56 data bytes 64 bytes from nrt12s36-in-x0e.1e100.net (2404:6800:4004:822::200e): icmp_seq=1 ttl=56 time=7.60 ms --- google.com ping statistics --- 1 packets transmitted, 1 received, 0% packet loss, time 0ms rtt min/avg/max/mdev = 7.595/7.595/7.595/0.000 ms time=7.60 ms がRTTになります。 またまた余談ですが、 intdash Edge Agent がインストールされたIoTデバイスを、車に乗せて走行した時のpingを含むネットワークのメトリクスはを可視化した例です。 pingの可視化 おわりに この記事の冒頭では、「問題が起きる」→「調べる」という流れを書いていますが、効率が良いのは、「状態を監視」→「問題を未然に防ぐ」の方ですね。 記事の途中でも記載したように、 intdash Edge Agent を使用して、サーバーに送信することですることで、状態を可視化することも可能です。ご興味がありましたら是非お試しください! intdash Edge Agent デベロッパーガイド version 1.24.0
アバター
aptpod Advent Calendar 2022 6日目の記事を担当する、Visual M2M グループの白金です。 弊社製品の Visual M2M Data Visualizer では、計測データを可視化するための様々なビジュアルパーツを提供しています。 その中の一つに、計測データに含まれる位置情報をもとにGoogleマップに現在位置を表示するビジュアルパーツが含まれています。 今回は、下図のように Googleマップのビジュアルパーツを3Dで表現する機能を試してみたので紹介したいと思います。 ビジュアルパーツで Googleマップを3Dで表示 はじめに マップIDを準備する 実装する Data Visualizer の計測データを使用して可視化する おわりに はじめに 弊社製品の Visual M2M Data Visualizer は Google Chrome のWebブラウザで提供しており、Googleマップのビジュアルパーツは、 Google Maps Platform から提供されている JavasScript API を使用しています。 このGoogleマップを3Dで表現するために WebGL Overlay View で構築する 3D マップ エクスペリエンス を参考に試してみました。 マップIDを準備する Google Maps Platform では、Google Cloud Console で作成したマップのスタイルを マップID に関連づけることができます。 JavaScript API で WebGL の機能を利用するためには、ベクター地図を有効にしたマップIDが必要になります。 設定方法については下記リンク先のページを参照ください。 developers.google.com 実装する 細かな実装方法は、各APIの説明については下記リンク先のステップ4〜8で説明が掲載されています。 developers.google.com ここでは下記2点を表示するための実装を紹介します。 3Dモデルで現在位置の表示する GeoJSON を使用して軌跡を表示する 下記NPMパッケージを使用して、TypeScript、React で実装します。 typescript react react-dom google-map-react three @types/google-map-react @types/google.maps npm i -S typescript react react-dom google-map-react three npm i -D @types/google-map-react @types/google.maps React の Component を実装します。 3DモデルのGLTFデータは こちらのサンプルデータ を拝借しました。 import React , { memo , useEffect , useCallback , useRef , useState } from 'react' import GoogleMapReact from 'google-map-react' import * as THREE from 'three' import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js' // WebGLOverlayView のサンプルで公開されているGLTFデータを参照します。 import PIN_GLTF from './pin.gltf' // 当コンポーネントで指定する位置情報の型です。 type Coordinate = { lat: number lng: number heading: number } // 当コンポーネントのPropsの型です。 type Props = { /** Googleマップを表示するための Api Key */ mapApiKey: string /** ベクター地図を有効にしたマップIDを指定します。 */ mapId: string /** Googleマップの初期表示位置情報 */ defaultCenter: GoogleMapReact.Coords /** Googleマップの初期表示ズーム値 */ defaultZoom: number /** 3Dモデルの表示位置情報 */ model3dCoordinate: Coordinate | undefined /** 軌跡の位置情報リスト */ trajectoryCoordinates: Coordinate [] } const MODEL_3D_ALTITUDE = 80 const TRAJECTORY_STROKE_COLOR = '#a00' const TRAJECTORY_STROKE_WEIGHT = 6 export const GoogleMaps3dSample: React.FC < Props > = memo (( props ) => { const { mapApiKey , mapId , defaultCenter , defaultZoom , model3dCoordinate , trajectoryCoordinates , } = props // ロードした Google Maps Api のインスタンスを格納します。 const [ mapApi , setMapApi ] = useState < { map: google.maps. Map maps: typeof google.maps } | null >( null ) // WebGLOverlayView で3Dモデルの表示位置を参照するための変数にコピーします。 const refModel3dCoordinate = useRef < Coordinate | undefined >() useEffect (() => { refModel3dCoordinate.current = model3dCoordinate } , [ model3dCoordinate ] ) // Googleマップに表示する軌跡のスタイルを定義します。 useEffect (() => { mapApi?.map.data.setStyle (() => { return { strokeColor: TRAJECTORY_STROKE_COLOR , strokeWeight: TRAJECTORY_STROKE_WEIGHT , } } ) } , [ mapApi ] ) // 軌跡のデータをGeoJSONフォーマットに変換してGoogleマップに表示します。 useEffect (() => { if ( ! mapApi ) { return () => {} } const geoJSON = { type : 'FeatureCollection' , features: [ { type : 'Feature' , properties: {} , geometry: { type : 'MultiLineString' , coordinates: [ trajectoryCoordinates.map (( { lat , lng } ) => [ lng , lat ] ), ] , } , } , ] , } const features = mapApi.map.data.addGeoJson ( geoJSON ) return () => { features.forEach (( feature: any ) => { mapApi.map.data.remove ( feature ) } ) } } , [ mapApi , trajectoryCoordinates ] ) // WebGLOverLayView を使用してGoogle Mapに3Dモデルを表示します。 useEffect (() => { if ( ! mapApi ) { return } const webGLOverlayView = new mapApi.maps.WebGLOverlayView () let scene: THREE.Scene let camera: THREE.PerspectiveCamera let renderer: THREE.WebGLRenderer const model3dGroup: THREE.Group = new THREE.Group () webGLOverlayView.onAdd = () => { // Scene、Camera の情報をセットアップします。 scene = new THREE.Scene () camera = new THREE.PerspectiveCamera () const ambientLight = new THREE.AmbientLight ( 0xffffff , 0.75 ) scene.add ( ambientLight ) const directionalLight = new THREE.DirectionalLight ( 0xffffff , 0.25 ) directionalLight.position. set( 0.5 , -1 , 0.5 ) scene.add ( directionalLight ) // 3Dモデル(GLTF)をロードします。 const loader = new GLTFLoader () const source = PIN_GLTF loader.load ( source , ( gltf ) => { // ロードしたGLTFのスケール、姿勢角の表示調整 gltf.scene.scale. set( 25 , 25 , 25 ) gltf.scene.rotation.x = ( 180 * Math .PI ) / 180 model3dGroup.add ( gltf.scene ) scene.add ( model3dGroup ) } ) } webGLOverlayView.onContextRestored = ( { gl } ) => { // renderer を作成します。 renderer = new THREE.WebGLRenderer ( { canvas: gl.canvas , context: gl , ...gl.getContextAttributes (), } ) renderer.autoClear = false } webGLOverlayView.onDraw = ( { transformer } ) => { // 3Dモデルを表示する位置情報を作成します。 const latLngAltitudeLiteral = { lat: refModel3dCoordinate.current?.lat ?? 0 , lng: refModel3dCoordinate.current?.lng ?? 0 , altitude: MODEL_3D_ALTITUDE , } // 3Dモデルの位置情報が無効な場合は非表示にします。 model3dGroup.visible = Boolean ( refModel3dCoordinate.current ) // 参照する3DモデルのZ軸の回転角度を設定します。 // heading と回転方向が逆のため、反転しています。 model3dGroup.rotation.z = ( -1 * ( refModel3dCoordinate.current?.heading ?? 0 ) * Math .PI ) / 180 // 3Dモデルの表示情報を renderer に反映します。 const matrix = transformer.fromLatLngAltitude ( latLngAltitudeLiteral ) camera.projectionMatrix = new THREE.Matrix4 () .fromArray ( matrix ) webGLOverlayView.requestRedraw () renderer.render ( scene , camera ) renderer.resetState () } webGLOverlayView.setMap ( mapApi.map ) } , [ mapApi ] ) // MouseDown のイベントハンドラを無効にします。 // Data Visualizer 本体でドラッグイベントを使用するためです。 const onMouseDownEventCancel = useCallback ( ( evt: React.MouseEvent < HTMLElement >) => { evt.preventDefault () } , [] , ) return ( < div role = "button" tabIndex = { 0 } style = {{ width: '100%' , height: '100%' }} onMouseDown = { onMouseDownEventCancel } > < GoogleMapReact bootstrapURLKeys = {{ key: mapApiKey , // ベクター地図を有効にしたマップIDを有効にするため、version に beta を指定します。 version: 'beta' , }} options = {{ mapId , tilt: 60 , heading: 0 , }} defaultCenter = { defaultCenter } defaultZoom = { defaultZoom } onGoogleApiLoaded = { setMapApi } / > < /div > ) } ) 上記ソースコードで実装した React Component を呼び出します。 mapId は、事前に準備したベクター地図を有効にしたマップIDを指定します。 mapApiKey は Google Maps Platform で作成したAPIキーを指定します。APIキーの作成手順については こちら をご確認ください。 < GoogleMaps3dSample mapApiKey = "xxxxxx" mapId = "xxxxxx" defaultCenter = {{ lat: 35.68783052263802 , lng: 139.71728196798034 , }} defaultZoom = { 19 } model3dCoordinate = {{ lat: 35.68781633 , lng: 139.7180315 , heading: 80 , }} trajectoryCoordinates = {[ { lat: 35.68778533 , lng: 139.71701067 , heading: 79 } , { lat: 35.68778533 , lng: 139.71782767 , heading: 79 } , { lat: 35.68778533 , lng: 139.71782767 , heading: 80 } , { lat: 35.68778817 , lng: 139.71784633 , heading: 80 } , { lat: 35.68778817 , lng: 139.71784633 , heading: 80 } , { lat: 35.687791 , lng: 139.71786467 , heading: 79 } , { lat: 35.687791 , lng: 139.71786467 , heading: 79 } , { lat: 35.68779417 , lng: 139.717883 , heading: 79 } , { lat: 35.68779417 , lng: 139.717883 , heading: 79 } , { lat: 35.68779767 , lng: 139.71790067 , heading: 79 } , { lat: 35.68779767 , lng: 139.71790067 , heading: 79 } , { lat: 35.687801 , lng: 139.71791883 , heading: 79 } , { lat: 35.687801 , lng: 139.71791883 , heading: 79 } , { lat: 35.68780417 , lng: 139.7179375 , heading: 79 } , { lat: 35.68780417 , lng: 139.7179375 , heading: 79 } , { lat: 35.687807 , lng: 139.71795633 , heading: 79 } , { lat: 35.687807 , lng: 139.71795633 , heading: 79 } , { lat: 35.68780933 , lng: 139.717975 , heading: 79 } , { lat: 35.68780933 , lng: 139.717975 , heading: 79 } , { lat: 35.68781283 , lng: 139.71799333 , heading: 79 } , { lat: 35.68781283 , lng: 139.71799333 , heading: 79 } , { lat: 35.687815 , lng: 139.7180125 , heading: 79 } , { lat: 35.687815 , lng: 139.7180125 , heading: 79 } , { lat: 35.68781633 , lng: 139.7180315 , heading: 80 } , ]} / > 以上で下図のようにGoogleマップ上に3Dモデル、及び軌跡を表示することできました。 実行結果01 実行結果02 Data Visualizer の計測データを使用して可視化する 次に、Visual M2M Data Visualizer のビジュアルパーツに Googleマップ3Dのビジュアルパーツを表示してみました。 位置情報を含む走行データは、弊社製品の Visual Parts SDK を使用して Visual M2M Data Visualizer から取得し、再生時間に沿って可視化しています。 また、他のビジュアルパーツとの比較、位置情報を確認するため、Open Street Map、緯度、軽度の値を表示するビジュアルパーツも表示しました。 youtu.be Visual Parts SDK を含む弊社製品に関するお問い合わせは下記リンク先までお願いします。 www.aptpod.co.jp おわりに 新しい機能を試して実現できた瞬間は、いつになってもテンションが上りますね。 今回は道路に接している移動体の可視化となりましたが、今後は飛行している移動体の可視化、軌跡も表現してみたいと思います。
アバター
製品開発グループの大久保です。 aptpod Advent Calendar 2022 の5日目を担当します。 社内ではRustのエッジ製品への適用が本格化し、接続するデバイスに応じたプラグインの デバイスコネクタ やSDK等への広がりを見せています。 個人的にもRustでのゲーム開発についての話題を追いかけているのですが、最近は bevy というゲームエンジンに勢いがあるようです。このbevyはWebAssemblyにビルドし、ブラウザ上で動作させることにも対応しています。というわけで、bevyで作ったアプリケーションをブラウザ上で動作させてみます。 bevyとは 実装 ビルド まとめ bevyとは bevyは ECS に基づいたRust製のゲームエンジンで、本体はシンプルに保ちつつ、プラグインを導入して拡張を容易にする設計になってます。bevy用のプラグインは有志によって多数開発されているようです。 Bevy - Assets bevy自体は頻繁にアップデートが続けられているため、サードパーティ製のプラグインも更新されなければ使えなくなってしまう心配がありますが、有用なものはやはり使っていきたいものです。Rustで人気のあるGUIライブラリである egui をbevyで使用できるようにした bevy_egui もあり、今回はこれでGUIを作ってみます。 実装 Cargo.toml を以下のように記述します。bevyは2022年11月時点で最新のバージョンです。 [package] name = "bevy-test" version = "0.1.0" edition = "2021" [dependencies] bevy = "0.9" bevy_asset_loader = "0.14" bevy_egui = "0.17" rand = "0.8" main.rs は以下のように記述します。 use bevy :: prelude :: * ; use bevy_asset_loader :: prelude :: * ; use bevy_egui :: {egui, EguiContext, EguiPlugin}; use rand :: Rng; fn main () { App :: new () . add_loading_state ( LoadingState :: new ( GameState :: AssetLoading) . continue_to_state ( GameState :: Running) . with_collection :: < MyAssets > (), ) . add_state ( GameState :: AssetLoading) . add_system_set ( SystemSet :: on_update ( GameState :: Running). with_system (ui_system)) . add_system_set ( SystemSet :: on_enter ( GameState :: Running). with_system (setup)) . add_plugins (DefaultPlugins. set (WindowPlugin { window: WindowDescriptor { title: "bevy test" . into (), width: 320.0 , height: 320.0 , .. Default :: default () }, .. default () })) . add_plugin (EguiPlugin) . run (); } #[derive(Resource, AssetCollection)] struct MyAssets { #[asset(path = "rust-logo.png" )] img: Handle < Image > , } fn setup ( mut commands: Commands) { let camera = Camera2dBundle :: default (); commands. spawn (camera); } fn ui_system ( mut commands: Commands, mut egui_context: ResMut < EguiContext > , my_assets: Res < MyAssets > , mut tex_entities: Local < Vec < Entity >> , ) { egui :: Window :: new ( "test" ). show (egui_context. ctx_mut (), | ui | { if ui. button ( "add" ). clicked () { let mut rng = rand :: thread_rng (); let id = commands . spawn (SpriteBundle { texture: my_assets.img. clone (), transform: Transform :: from_xyz ( rng. gen_range ( - 160.0 .. 160.0 ), rng. gen_range ( - 160.0 .. 160.0 ), 0.0 , ), .. default () }) . id (); tex_entities. push (id); } if ui. button ( "clear" ). clicked () { for id in tex_entities. iter () { commands. entity ( * id). despawn (); } tex_entities. clear (); } }); } #[derive( Clone , Eq , PartialEq , Debug , Hash )] enum GameState { AssetLoading, Running, } 少し解説を入れます。 App :: new () . add_loading_state ( LoadingState :: new ( GameState :: AssetLoading) . continue_to_state ( GameState :: Running) . with_collection :: < MyAssets > (), ) . add_state ( GameState :: AssetLoading) . add_system_set ( SystemSet :: on_update ( GameState :: Running). with_system (ui_system)) . add_system_set ( SystemSet :: on_enter ( GameState :: Running). with_system (setup)) bevy単体だとアセットの扱いが結構苦行なので、 bevy_asset_loader を使っています。 MyAssets のロードが完了すると GameState が AssetLoading から Running に移行します。 Running に移行したときに SystemSet::on_enter で指定したシステム setup が動作します。 ui_system は Running 状態でしか呼ばれないこともここで指定しています。 #[derive(Resource, AssetCollection)] struct MyAssets { #[asset(path = "rust-logo.png" )] img: Handle < Image > , } AssetCollection を derive で指定して、ロードしたいアセットを定義します。ここでは、 rust-logo.png というファイルがロードされるようにします。 fn ui_system ( mut commands: Commands, mut egui_context: ResMut < EguiContext > , my_assets: Res < MyAssets > , mut tex_entities: Local < Vec < Entity >> , ) { egui :: Window :: new ( "test" ). show (egui_context. ctx_mut (), | ui | { if ui. button ( "add" ). clicked () { let mut rng = rand :: thread_rng (); let id = commands . spawn (SpriteBundle { texture: my_assets.img. clone (), transform: Transform :: from_xyz ( rng. gen_range ( - 160.0 .. 160.0 ), rng. gen_range ( - 160.0 .. 160.0 ), 0.0 , ), .. default () }) . id (); tex_entities. push (id); } if ui. button ( "clear" ). clicked () { for id in tex_entities. iter () { commands. entity ( * id). despawn (); } tex_entities. clear (); } }); } ui_system はGUIを定義するシステムで、eguiで生成したウィンドウ上にボタンを2つ用意します。addボタンはクリックされたとき、 MyAssets で読み込んだテクスチャを乱数で決めた位置に貼り付けます。このとき spawn したエンティティのIDを記録しておき、clearボタンが押されたときに消去するようにします。 ビルド Unofficial Bevy Cheat Book にはwasm向けビルド方法がいくつか紹介されていますが、今回はwasm-bindgenを用います。 wasm-bindgenは以下でインストールします。 cargo install wasm-bindgen-cli 以下のコマンドでビルドできます。 cargo build --release --target wasm32-unknown-unknown wasm-bindgen --target web --out-dir . --no-typescript target/wasm32-unknown-unknown/release/bevy-test.wasm ビルドが成功すると、 bevy-test_bg.wasm と bevy-test.js という2つのファイルができるので、それを呼び出す index.html ファイルを用意します。 < html > < head > < meta charset = "utf-8" /> </ head > < script type = "module" > import init from './bevy-test.js' init () </ script > </ html > あとは適当なHTTPサーバーを用意し、 python3 -m http.server 8000 ブラウザで開けば動作確認できます。addボタンを押せば画像がランダムに配置され、clearボタンを押せばそれが消えるのを確認できるはずです。 まとめ 今回はRust+bevyで簡単なアプリケーションをwasm向けにビルド、動作確認してみました。eguiによりGUIも比較的簡単に記述することができ、ビルド自体も非常に簡単に行えました。Rustでさくっと書いたものがwebブラウザ上で動くのはなかなか感慨深いものがあります。まだまだRustでのゲーム開発は発展途上であり、bevyもまた開発中ではありますが、webブラウザで動かしたい場合にbevyは有力な選択肢になるのではないでしょうか。
アバター
aptpod Advent Calendar 2022 、2日目を担当します、人事グループの照井です。 よろしくお願いします。 自己紹介 制度が迷子、私も迷子 アプトポッドの福利厚生パッケージ制度の検討開始 「Pod's ~ aptpod Employee Benefit ~」ができるまで すごいぞ!デザインチームの腕 今後の「Pod's」 最後に 自己紹介 今年3月にアプトポッドに入社して主に労務業務や制度設計等を行っています。 前職は社員数1,000人ほどの一部上場企業で人事(労務全般~制度設計)をやっていたため、所謂「ベンチャー企業での人事」は私にとって新鮮で未知の世界。 ワクワクしながら入社し、早9カ月が経過しようとしています。 制度が迷子、私も迷子 入社してまもなく、育児介護休業法の改正の対応や給与計算や勤怠処理をするにあたって、アプトポッドにはどんな制度があってどう運用されているかを確認するシーンが増えました。 当時まとまった資料が無く、手あたり次第コンフルエンスを漁っていたのですが、更新日時を見ると数年前だったりすることもあり、それらが正しく運用されているのかもわかりませんでした。 都度マネージャーに確認していましたが、ある時現場のメンバーから制度の問い合わせを受けた際に、 私よりだいぶ社歴が長い方に「そんな制度あるんですね!」と言われ、これは本格的に整理をしなければいけないな…と思ったのでした。 アプトポッドの福利厚生パッケージ制度の検討開始 実は、前職でWork&Lifeバランスに特化した福利厚生パッケージ制度を設計した経験がありました。 今回はその経験を活かして、迷子になっているアプトポッドの制度をきちんと整理して全社員に正しく認識してもらい、有効的に活用できるようにとパッケージの組立を開始しました。 今回のパッケージ化で行ったことは、大きく2点です。 ①現行の制度の洗い出しと整理 ②制度化していないが実態として実施している内容の制度化 今回の目的は、あくまでも現行の制度を表に出して全社の認知度を統一化すること。 そのため、新規施策の検討ではなく「いかに社内に浸透させられるか」に注力しました。 「Pod's ~ aptpod Employee Benefit ~」ができるまで コンフルエンス漁りや先輩社員への確認で、アプトポッドには法定外の福利厚生もいくつかあることがわかり、法定制度も合わせるとボリュームがあったので <Work&Life Design><HealthCare><Communication> の3本柱で制度の組立を行うことにしました。 種別に分けることで、視認性が良くなり必要としている制度が見つけやすくなりました。また、いざとなった時のために「把握しておこう」というケースにも対応ができるようになったのではないでしょうか。 制度の内容は固まりました。 次は「いかに社内に浸透させられるか」において最大の課題ともいえるネーミングです。 正直、私にはネーミングセンスはございません。 そこで、パッケージ制度のロゴをコーポレートマーケティング室のデザインチームにお願いする予定だったのでロゴ制作だけでなく、根本のネーミング考案からお力添えをいただくことにしました。 とても有難いことに、このプロジェクトに手を挙げてくださったデザインチームのメンバーがおり、その方とコーポレートマーケティング室の室長、通りすがりにプロジェクトのスライドを閲覧しているところを捕まえられたCTO、人事マネージャーを巻き込んでのネーミング考案となりました。(羅列すると大所帯w) アプトポッドで今まで制度に名前が付いたことが1度あり、それがコミュニケーション施策に入っているアプトライトです。アプトライトはアプトポッドの「アプト」を取って、縁の下の力持ちにもスポットライトをあてるという趣旨でこの名前になったそうです。 耳障りも良いし、程よい長さだし、なんともスマートなネーミングだなと思っていました。 今回もアプトライトに負けず劣らず素敵なネーミングを!と意気込み、考案する上での方向性/思想を設定し、候補を出し合いました。  <思想/方向性>  ● 安心して活躍できる環境づくり  ● つなぐ(会社⇔社員)  ● 短くて浸透しやすいもの  ● デザインしやすい長さ アプトライトのように、大抵制度の名前をつける際は社名の一部を使用して命名されるシーンが多いように思います。今回もそれに漏れず、「アプトポッド」の名前の一部を使用したものと、全く別物の2パターンの候補案が挙がってきました。 その中でも「apt」の「t」をつなげた造語などもいくつか案として挙がっており、ネーミングセンスに脱帽でした。 候補として挙げられたネーミング案 話し合いの中で、シンプルに「aptpod Employee Benefit」で良いんじゃないか。という意見も出ました。名前をつけたところで対外的にはその名前自体が何を指し示すものなのかがわからないので制度名の後に「〇〇社の福利厚生パッケージ制度」と記載している企業が大多数だったからです。 それであれば、サブタイトルとして制度名の後に付けましょう。ということにしました。 そうなると、必然的に制度名は短い方がいい。 ということで結果、最終的に16案から絞られ選出されたのは「さや状のもの」という意味もある「aptpod」の「pod」を取った「Pod's」と命名することになりました。  ~pod'sに乗せた想い~  ● 安心、包み込む(=安心して活躍できる環境)  ● 皆が含まれる  ● パッケージの中に制度がいくつかあるという意味  ● 短くて浸透しやすい すごいぞ!デザインチームの腕 めでたく命名されたPod'sですが、次はロゴデザイン。 自ら手を挙げて作成してくれたPod’sのロゴがこちら。 そして、各分類のシンボルデザインも、このように考案されました。(ステキすぎる) こうして、Pod'sはアプトポッド初の福利厚生パッケージ制度として2022/11/1にスタートしました。 沢山の方のお力添えあってこそ…!感謝でいっぱいです。 今後の「Pod's」 お蔭様でPod'sができたことによりレポートラインが明確になり、スムーズなエスカレーションが出来るようになりました。 今回は「守り」に徹して目立った新規施策はありませんでしたが、今後は会社の状況、社員のライフイベントの傾向に合わせて、より長く安心してアプトポッドの社員として活躍できるよう、都度バージョンアップを重ねていきたいと思います。 また私自身、入社9カ月経過し、1,000人規模の企業と70人規模のベンチャー企業では求められる制度の質が少し違うのかなと肌で感じています。今度はそれを、カタチにできたらなと個人的に思っています。 最後に アプトポッドは入社初日に有給休暇を付与されたり、かなり自由度の高い働き方ができるので、仕事のやりがい含め、入社してよかったなと心から思う日々です! 2023年も沢山のことに挑戦してアドベントカレンダーに書けるネタが作れるよう、頑張ります!
アバター
aptpod Advent Calendar 2022 1日目の記事です。 みなさまお久しぶりです。アプトポッドで人事をしている神前(こうさき)と申します。 前回の登場が 去年のAdvent Calendar なのでちょうど一年ぶりくらいでの登場となります。 今年もAdvent Calendarの一発目を飾ることになり戦慄してますが宜しくお願いいたします。 今年もCTOからの依頼に答える、の図 今年もあっという間に年末になり、詳細な振り返りはおそらくCTOの梶田が記事にすると思いますが、私は私で激動の1年でした。 簡単に自分の1年を振り返ると 昨年末:経営層から大量採用のオーダーがきて戦慄 12~1月:大量採用のための準備(RPOなんかも初めて使ってみた) 1~4月:ひたすら面談面接の日々(おかげで採用自体はかなりすすんだ) 5月:会社の方針転換に伴い採用活動を一旦停止 6~11月:ワークエンゲージメント活動のような内部施策を実施 12月:事業部に異動 うーん、こう書き出してみてもなかなかのものだなと改めて思います。 さて、今回のブログテーマなのですが、昨年と同じテーマでやっても芸がないので、今年の後半に取り組んでいたワークエンゲージメント活動について振り返りも兼ねて書いていこうと思います。 先に結論を書いておくと、半年間取り組んでみて、学びやよかったこともあるものの、反省する部分も多かったです。あんまりきれいなことを書くというよりかは、「内部施策についての素人が、ない知恵を絞りながら取り組んだ悪戦苦闘の記録」として書いていきたいと思います。これからワークエンゲージメントについて取り組むぞ、みたいな人事の方がもし読者の中にいたら参考になると幸いです。 そもそもワークエンゲージメントとは 自分が担当をするようになった当時の状況 運用側のサイクル 実施実績 数値の変遷 アンケートの変遷 ワークエンゲージメントについて調査をしてわかったこと サーベイフィードバックミーティングについて よかったこと 反省点 まとめ 参考文献 そもそもワークエンゲージメントとは 日本で「ワークエンゲージメント」についてにわかに注目が集まったのは2017年前後になります。きっかけはおそらく こちらの記事 のような「熱意あふれる社員」の割合が日本では6%しかおらず、調査した139カ国中132位と最下位クラスだったというというギャラップ社の調査結果公表ではないかと思います。 グーグルトレンドで見てみると グーグルトレンドでは2016年の年末ぐらいから検索が急上昇しているので上記の記事とは別の契機があるかもしれませんがいずれにせよこのタイミングからいままで右肩上がりですし、いまだにワークエンゲージメントといえばこの2017年の調査結果が引用されることも多いです。その後、2018年に厚生労働省がだした「 平成30年版 労働経済の分析 -働き方の多様化に応じた人材育成の在り方について- 」第Ⅱ部 第3章 第1節内のコラムにて「ワーク・エンゲイジメント」が多様な人材活用と雇用管理の文脈でとりあげられ、翌2019年の「 令和元年版 労働経済の分析 -人手不足の下での「働き方」をめぐる課題について- 」では第Ⅱ部 第3章をまるっと使って「ワーク・エンゲイジメント」についてとりあげられています。いわゆる働き方改革といった文脈のなかで、労働生産性をあげるにはどうしたらいいかという問いに対する解の一つとして語られることが多いようです。 さて、上記の図をみると、2017年前後からの注目とは別に2004年(グーグルトレンドでは2004年以前は調べられない)あたりでも検索をされていることがわかります。それもそのはずで、「ワーク・エンゲイジメント」は最近できた概念ではなく、1990年代ごろからビジネス領域(やコンサル領域)では徐々に使われ始めており、上記の厚労省で引用されているような「ワーク・エンゲイジメント」の概念は2002年にユトレヒト大学のシャウフェリ教授の論文によって提唱されているからです。近しい概念といってもよい「ワーク・モチベーション」などは1950年代にすでにでていたりもするので、概念の歴史自体は実はかなり長いのです。 では、「ワークエンゲージメント」とは一体何なのかというと、少し乱暴なまとめ方にはなりますが、「従業員が職場や仕事に対して熱意をもって取り組む状態」であり、ワークエンゲージメント施策とはつまり「そうした状態にするための環境作りや施策、取り組み」といえるかと思います。ワークエンゲージメントを計るための方法はいくつかありますが、代表的なのは日本でも注目されるきっかけとなったといえるギャラップ社が開発した「Q12」や、上述したシャウフェリ教授の「UWES(Utrecht Work Engagement Scale)」等があります。計測方法やその尺度に違いはありますが、いずれにしてもワークエンゲージメントが高ければその会社の業績に対してポジティブな影響があることが様々な調査によって分かっています。少子高齢化が進む中で、いかに一人ひとりの労働生産性を高めるか、という文脈の中でワークエンゲージメントは近年特に注目をされているものといえるでしょう。 自分が担当をするようになった当時の状況 さて、そんなワークエンゲージメントへの取り組みについてですが、自分が担当をした時(6月ぐらい)に0からまっさらのスタートというわけでは実はありませんでした。というのも、昨年の11月ごろにも一度エンゲージメントサーベイ(サーベイ=アンケート)を実施していたからです。当時はギャラップ社のQ12を利用してアンケートの実施、回答結果をまとめて1月からいくつかの施策につながっています。ですが、この時は自分は基本的にノータッチでした。そこから約半年を経て再開するにあたってまずはどういう風に進めていくかをマネージャーと簡単に話して以下のことを決めました。 アンケートのフォーマットはQ12を引き続き利用する:前回と同じフォーマットを使うことで差分をだしたい アンケートの頻度は月1とする:いわゆるパルスサーベイ的に細かく数字の変化を追えるようにしたい アンケートの文言を調整する:Q12の設問は固いものも多いので回答しやすいものに調整をしたい(例:Q10の「職場に親友はいますか?」について「親友とは?」となったり) アンケートの後にはサーベイフィードバックミーティングを実施する:アンケートをとって終わりではなく、それをベースに議論をして改善点があればなにかしらのアクションにつなげたい サーベイフィードバックミーティングはQ毎に実施する:毎月やるとさすがに現場の負担を大きいので 後述しますが、実施の段階でもっとよく調査をしてからスタートすればよかった、となるのですが(少し詳しい方からみたらQ12はパルスサーベイ的に用いるものではないということはお分かりかと思います)、当時は社内にもこうした取り組みの経験があるメンバーがいなかったこともあり、まずはデータをとるところから進めていこうとなった次第です。 運用側のサイクル 弊社では隔週で「全体会議」と呼ばれる会議体がありまして、オンラインで全員が集まり、事業進捗の報告や入退職者の挨拶、プロダクトのリリース情報共有等がされています。ほぼフルリモートに近い働き方(オフィスへの出社率はだいたい10%前後)になっているため、全社員が集まるこの「全体会議」を軸にワークエンゲージメント活動はサイクルを回していました。具体的にいうと、だいたい月に2回ほど全体会議があるので、月の前半の全体会議にてワークエンゲージメントアンケート実施の告知、翌週を期限一杯としてアンケート回収、月の後半の全体会議にて結果を共有、その次の全体会議にむけてアンケートの準備、というサイクルです。ちなみに集計についてはスプレッドシートを利用し、集計された数字を関数でひっぱってきてそれぞれの部署やグループごとにまとまるようにしました。ある程度数字をひっぱって自動化はしていたのですが、とはいえ手作業になる部分も多く、毎度ここに時間を使う部分もありました。サーベイフィードバックミーティングを実施する場合はアンケート結果を共有したあとに同時並行で実施をしていく、という感じです。 実施実績 そんなこんなで活動実績としては以下のようになっています。 7月末:(再開して1回目の)アンケート実施 8月:サーベイフィードバックミーティング実施 9月:アンケート2回目実施 10月:アンケート3回目実施 11月:アンケート4回目実施 11~12月:サーベイフィードバックミーティング2回目実施(予定) おおよそ当初の予定通りにサイクルとしては進みましたが、初回はアンケートの実施、まとめ、サーベイフィードバックミーティングの実施でまごついてしまい時間を使ってしまいました。それ以降は順調にサイクルとしては回せたかなというところです。 数値の変遷 弊社の組織構造としては部(もしくは室)の下にグループという構成になっています。アンケートでは匿名回答とし、グループを最小単位としてまとめてありますが、組織によってはグループがないところもあります。個々のグループの数値の変遷をだすことはさすがにできませんが、全社での数値の変遷としては下記のように推移しています。 見づらいのはご容赦ください 昨年の11月時点から数値としては徐々にあがり、直近では少し下がっていることがわかります。これらはあくまで全体をならした数値なので、各部や各グループではもちろんばらつきがありますが、全体ではおおよそ4.0付近を推移しています。数値の上下についてはその時々の会社の状況の影響もあるので一概に言えない部分はありますが、いくつかの部分についてはアンケートそのものに手を入れた影響があると考えています。 アンケートの変遷 7月から再開するにあたってアンケートの文言調整をしました。なぜかというと、昨年に実施した段階での文言はほぼネットに転がっているような文言をそのままもってきていたため、どう回答をしていいかわからないという声があったからです。また、当時は各設問の背景や補足の文言もなかったため回答をする人の解釈にかなりの部分を委ねる形になっていたという部分もあります。 (2021/11実施時) 例: Q1 職場で⾃分が何を期待されているのかを知っている Q4 この1週間のうちに、よい仕事をしたと認められたり、褒められたりした Q8 会社の使命や⽬的が、⾃分の仕事は重要だと感じさせてくれる Q10 職場に親友がいる とりわけ上記の図にもある通り、Q10の「親友」をどう受け取っていいのかはわりと困惑する部分であり、それが数値としても顕著にでています。 他にも「これどう解釈すればいいんだろう?」という部分があったため、まずは回答をしやすいように文言を調整しました。 (2022/7~10実施時) 例: Q1 職場で⾃分が何を期待されているのかを知っている(理解している) Q4 直近1週間で自身の担当をした業務に対してポジティブなフィードバックをもらいましたか? Q8 会社のやろうとしていること(=ミッションやビジョン)に自分も貢献をしたいと感じますか?あるいは会社のやろうとしていることに対して自身も共感しますか? Q10 会社に、仕事以外でも付き合える、あるいは付き合いたいと思える人はいますか? いまから振り返れば汗顔の至りなのですが、当時は「もう少し自然な感じの質問にしよう。もう少し解釈の幅を狭めて回答しやすくしよう」と考え調整をしました。その結果といってもよいのか、7月実施の際は前回(2021年11月)実施時よりも全体的に数値が上昇をしました(Q10は特に顕著)。 こうした文言の調整の他にも、追加の質問をその時々で設定し、例えば10月実施時には「フィードバック」にフォーカスをしてより詳細な質問をしていたりもしています。 そんな折、10月実施時に弊社のVPoPである岩田から「Q12の原文はこうなので、いまの設問はちょっとそこからずれているように感じる。こんな感じにしてみてはどうでしょう?」と提案がありました。自身としてもQ12の各設問は具体的にどういうことを聞いていて、どういう背景でそもそもQ12があるのか、この数値をどう解釈していくといいのかという行き詰まりのようなものを感じていたところがあったため、一念発起して「そもそもワークエンゲージメントはどういうものか」の調査を開始しました。そこで新たにわかったものは後述するとして、調査の結果をまとめたものをアンケートとともに展開し、アンケートの文言を再調整して実施したのが11月の実施回となります。元々のQ12の原文に近い形に調整をしつつ、各設問で聞きたいことを補足として付け加えながら元来の設問意図にしっかりと沿うようにしました。 (2022/11実施時) 例: Q1 職場で自分が何を期待されているのかを知っている Q4 直近1週間で自身の担当をした業務に対して褒められたり、認められたりといったポジティブなフィードバックをもらいましたか? Q8 会社の使命や目的が、自身の仕事は重要だと感じさせてくれますか? Q10 職場には(それが友達か親友なのかはさておき)安心して背中を預けられる人はいますか? それ以前の設問は「回答のしやすさ」を意図していたこともあり、無意識的にも「数値が高くなりやすい」ものになっていたと今では思うところです。それを元来の形に近いものに再度調整をし、さらにQ12についての調査結果をまとめたものを展開したことにより、それを読んだ人からは「これはこういうことを聞いていたのか。であればここは前なら(例えば)4だったけど、それなら3だな」というような感じになったのではないかと思います。その結果として11月のアンケートではそれまでとは数値が微減したのではないかと考えています。施策の実施者としては当然数値が高いほうが喜ばしいわけではありますが、その一方で数値がみせかけのものであっても意味がありません。数値としては下がったものの、より会社組織全体の実態に近い形に数値としてはなったのであればその方が良かったと思います。 ワークエンゲージメントについて調査をしてわかったこと ワークエンゲージメントとはそもそも何ぞやというのを調べ、まとめをつくったわけですが(今調べたらだいたい10,000字ぐらいあった)、内容としては ワークエンゲージメントが注目された時期 厚労省での定義 アカデミック文脈でのワークエンゲージメント ビジネス文脈でのワークエンゲージメント Q12とは 各設問の背景 という感じでまとめました。 実際のまとめの冒頭部分 本稿ではQ12の詳細に触れませんが(さすがに字数が膨大になる)、かなり学びがありました(詳細に知りたい方は文末の参考文献をどうぞ)。また、Q12を含む「ワークエンゲージメント」周辺の概要についても知ることができたことも学びになりました。広く言えば「組織開発」に該当する領域だとは思いますが、これまで採用業務を中心にしていた自分としては新鮮でした。 Q12に多少焦点を当てると、例えば「Q12の設問は4つの固まりに分けることができ、全体として連関している」ことも今回の学びの一つです。言われてみれば当たり前のことではあるのですが、実際にアンケートへの回答する時にしかQ12に触れない場合、それぞれの設問がどうつながっているかはやはり見えにくいものです。 Q12の全体像 あるいは歴史や成立背景を知ることも理解を深めるのにとても役立ちました。元々はアメリカの調査会社であるギャラップ社が膨大な調査結果から導き出したものがQ12であるのに対し、例えば厚労省がとりあげているワークエンゲージメントはJD-R理論を背景としていますし、もっと広く言えばポジティブ心理学という「心理学」をベースにしています。ネット上にある「エンゲージメント」についての記事の中にはこのあたりがごっちゃになっているものもあり、それぞれの背景を知らないと、活動として実施するにしても見るべきものを誤ってしまう可能性があります。 細かいところで言えば、例えばQ2では「仕事をうまく⾏うために必要な材料や道具を与えられている」が聞かれるわけですが、ここでいう「材料や道具」はPCやデスクといった物理的なものに限らず、「業務を進めるにあたって必要な情報」や「必要な情報にアクセスできるかどうか」といった非物理的なことまでが含まれます。設問の「文言だけ」をみて「材料や道具」を物理的なものだと認識した場合、「PCは最新のものだし性能もいい、デスクやディスプレイもいいものを使える。でも情報についてはあんまり上から降りてこなかったり、どこにあるかよくわからないことがあるなぁ」という人は「5」や「4」と回答する一方で、「材料や道具」を非物理的なものまで含むと正しく認識をしている場合であれば「3」やそれ以下で回答する可能性はあるでしょう。こういった感じで、細かいといえば細かいのですが、設問が聞いているものを正しく伝えて、それを理解してもらった上で回答をしてもらうことでより実態に近い数値に全体として推移するものと思います。 設問に対する補足部分 サーベイフィードバックミーティングについて 話はガラッと変わり。8月にはその前月にとったアンケートをもとにサーベイフィードバックミーティングを実施しました。実施に際して、実施を前提とした上でまずは各部や室の部門長に実施方法の打ち合わせをしました。打ち合わせ内容としてはざっくりと下記になります。 結果の共有:各部門/室単位での数値結果の共有 実施の有無:アンケート結果をもとに実施の有無の判断 実施単位:グループによっては人数が少ないこともあるので他のグループと合同で実施するかどうか、等 上記をすり合わせたあとに、それぞれのグループマネージャーとより詳細に下記を詰めていきます。 実施タイミング:各グループでの定例があればそこで時間をもらう。難しければ別途時間を設ける。 実施時間:他の業務都合も鑑みながら30分~60分の間で調整 実施の際は以下のように進めました。 冒頭挨拶(3分):サーベイフィードバックミーティングの目的とおおまかなルール説明 結果の共有(3分):そのグループの数値結果を画面共有 議論の時間(残り時間):自身がファシリテーターとして話をふっていく 議論といっても侃々諤々でやるというよりかは、まずは数値結果をみながら率直にどう思ったかを聞いていくような感じで進めます。何かしらのアクションにつながるようなところまでいけるのがベストではありますが、無理にそこまでを目指さずに、また、話題としてもポジティブなことからネガティブなものまで含めて広くヒアリングをしていくように意識しています。 議論を進めながら議事録をつくり、終わった後にメンバーに共有をして終了となります。 よかったこと まだまだ道半ばではありますが、振り返ってみての(会社視点というよりも個人視点ですが)よかったことを書いていきたいと思います。 組織に対するもやもやが可視化された:月一でアンケートを実施したことにより、数値の変化を追えるようになったのはやはりよかったことだと思います。これが年一や半年に一回だと数値の変化を追いにくく、また、その変化の原因を絞るのが難しかったと思います。「なんとなく空気がよくない気がする/よくなった気がする」というのが、主観による思い込みではなく客観的なデータとして数値で表れるので、それをベースに議論を始めるのはとてもしやすかったように思います。また、アンケートではフリーコメントの欄も設けているので、そこでの回答内容も踏まえて、例えば「この施策があったことでこの数値はこう変化したと思います。実際にこういうコメントもありました」という会話がしやすくなったと思います。ただし、可視化はあくまでスタートで、そこからどうアクションにつなげていくか、というのがより大事な部分ではあると思います。 より現場を知るきっかけになった:アンケートのあとにサーベイフィードバックミーティングを実施することで、いろいろな会話をするのですが、そのなかでの気付きというのは多かったと感じています。自分は元々採用をしていたので、現場のみなさんと会話をする機会自体は多い方でしたが、「採用」とは違う軸での会話、さらにいえば「組織課題」であるとか、もっと現実的に「実はこういうところに困っている」といったような話も聞けたのはよかったと思います。特に弊社はフルリモートに近いため、オフィスにいればなんとなく感じれるかもしれないものが見えづらく、どういう風に業務を回しているのか、どういうことを実際にやっているのか、その中で何に困っているのか、というのはどうしても察知しにくい面があります。さらに、「組織をどうよくしていこう」みたいな会話を正面切ってする機会もそもそも多くはないなかで、普通に接しているだけではなかなか聞けないことを聞けるとても貴重な機会だったと感じています。 反省点 よかったこともありましたが、当然反省点もあります。手探りだったところもあるので色々反省点はあるのですが、以下に大きく2つほど反省点を書いてみようと思います。 課題意識を明確にする:今回自分は半ば引き継ぎのような形で担当になったわけですが、「どういう目的で」、「何が課題で」、「そのためには何をすべきか」という点を事前にしっかりと詰めれていたわけではありませんでした。今回調べてわかったように、一口にワークエンゲージメントといっても、計測方法も、その背景にある理論も様々です。今ある組織の課題が何かというのをしっかりと議論をし、明確にすることで、それにあった運用方法、計測方法を選択すべきだったと今では感じています。もちろん、だからといってこれまでの活動が無駄ということはなく、例えばパルスサーベイ的な運用をしたことにより細かい数値の変化を追えたので、「この変化はこういうことがあったからかな」といった推測も立てやすく、組織全体としての変化の影響もポジネガ両面で見ることができたりもしました。また、課題ありきで進めるのではなく、「課題があるかを探るためにまずはアンケートをとって現状把握をしてみよう」というのも考え方の一つだと思います。ただし、その場合は「データをいつまで取るのか」といった期限を設けるとよいと思います。 頭でっかちになりすぎない/アクションまでつなげる:ワークエンゲージメントに限らずですが、いわゆる管理部門がなにかしらのアンケートを取る時に、その結果がどこにどう反映されてるのかがよくわからない、ということは往々にして発生しがちだと思います。今回でいえば、アンケートとサーベイフィードバックミーティングをセットで運用をし、アンケート結果を振り返りながら現場の皆さんと一緒に議論をするところまでは一応実行できたかとは思います。ですが、もっと踏み込んで、例えば数値の変化をもとに各マネージャー陣と会話をし、一人ひとりのメンバーのケアに活用をするといったようなところ、より具体的にアンケートをどう活用していくのかというところまでできればよかったと今では思うところです。 まとめ いかがだったでしょうか。読み返してみてもなかなかの手探り感だったと思います。冒頭でも書いた通り、私自身は今月から部署が異動になるため、ワークエンゲージメント活動に直接的にかかわることは今後ないとは思います。ですが、取り組み自体は引き続き管理部として継続していきますので、今後も間接的に関われればと思います。 こうした人事施策はすぐに結果が出るものではなく、また、目に見えてわかりやすい結果が出るようなものでもないため、粘り強く取り組んでいくしかありません。私自身、アンケートのフリーコメントにあった励ましのコメントで喜びつつ、一方で「これって何のためにやってるんですか?」といったコメントで凹みつつを繰り返しながらやってきました。積極的にこうした取り組みに協力してくれる社内のメンバーはもちろんのこと、「面倒だなぁ」と思いつつも協力してくれるメンバーの皆さんの協力にも感謝です(ネガティブなコメントもとても大事)。みなさんの協力がなければそもそも何もできませんでした(毎回アンケートの回答率は90%以上なのはすごいこと!)。ありがとうございます。 そして、もし今後「うちでもワークエンゲージメント活動やってくぞ!」みたいな方がこれを読んでいる方の中にいて、その方にとって少しでも参考になれば幸いです。 それではまた1年後にお会いしましょう。 参考文献 Q12関連: 『 これが答えだ!: 部下の潜在力を引き出す12の質問 』:Q12を作成したギャラップ社の社員が書いた書籍。Q12それぞれについて詳細な説明があるので把握をするのにはこれがよい。 『 まず、ルールを破れ: すぐれたマネジャーはここが違う 』:同じくギャラップ社の人が書いた本。Q12作成の歴史みたいな側面があるので、Q12の成り立ちから知りたいならこちらもおすすめ。 『 ストレングス・リーダーシップ<新装版> さあ、リーダーの才能に目覚めよう 』:Q12をマネージャーや経営層にフォーカスして書かれたもの。Q12をどうマネジメント視点で活かすかについて知りたい方はこちら。 サーベイフィードバック: 『 サーベイ・フィードバック入門――「データと対話」で職場を変える技術 【これからの組織開発の教科書】 』:サーベイフィードバックに関してはこの本をだいぶ参考にしました。著者の方は組織開発系の書籍も書かれているのでそちらも興味ある方は探してみてください。
アバター
日々使う機器 小物類 終わりに パパエンジニアの週末(おまけ) EDGEPLANTグループの平野です。2021年4月にハードウェアエンジニアとして入社しました。 ハードウェアエンジニアは、お客様の要望を具体的に聞き、どう実現するのかを考えます。 必要な機能・費用・工数を算出して、部品の選定、製造の各工程、守らないといけない規格、製品の完成形などをふまえて提案・設計・製作などを担当します。 入社して1年半ほど経ちますが、今回、Tech Blogに何を紹介できるかかなり悩みました。 グループに相談したところ、同僚の野本さんに「仕事柄、色々な大きい機器を使っているイメージですが、リモートではどうしてるんですか?」と聞かれました。 確かに、仕事では色々な機器を使いますし、会社にはEDGEPLANTグループの様々な機器を置いている"島"もあります。 そこで今回は、ハードウェアエンジニアのリモートワーク環境について、私の例をご紹介します。 日々使う機器 さて、ハードウェアエンジニアの仕事で必要不可欠な機器は四つあります。 オシロスコープ(略称オシロ):製品の機能や様々な現象・疑問がある時、様々な信号の波形・タイミング等の確認につかいます。年中必要です。 マルチメーター:基本大きな電源は要らず、どんな場所でも部品・信号を簡易に確認できて、既に所持しています。 安定化電源:不確定な要素(ノイズ)を排除して、幅広い電流と電圧を供給できます。回路の評価・デバッグに役に立ちます。 半田ごて:基板の配線・修理等に使います。 作業場の風景 コロナ禍で入社してすぐ、リモートワーク用にそれらのすべての機器の支給を提案されました。 そこで、私は半田ごて1式だけ購入させて頂きました。 実は、他の機器は、前職の会社が会社をたたむことになって自分も辞めることになったとき、 ほぼ自分一人が使用していた機器類を譲ってもらったものを愛用しています。 その中に、特にオシロは2・3回修理しまして、愛着があります。20年前の測定器ですが性能は十分現役です。 他に、一人に使うには“贅沢”とも言える電流プローブと信号発生装置を所持しています。 電流プローブは基板のデバッグ、ノイズの解析等、電流の波形には情報豊富で大変役に立ちます。 信号発生装置は今の所出番が少ないですが、アナログ信号関連で使用しています。 リモートワークのために自宅に用意している機器は以上です。 会社には、ここまで紹介したような機器はもちろん、大掛かりな恒温槽、スペアナ等があります。特殊な測定器が必要な場合、レンタルして会社に設置することもあります。 製品の正式な評価では会社の機器やレンタル機器を使うために出社する必要がありますが、検証・デバッグは自宅の機器で行えるので、普段のほとんどはリモートで仕事ができています。 小物類 ここまでご覧になって、皆さん意外に多いと思うのではないでしょうか。 ところが機器が多いだけでは収まりません。 このほかに評価ボード・道具・部品のサンプルというような小物がかなりあるのです。 評価ボードは新しいプロジェクトを始める度に増えてしまいます。 道具は電化製品の修理という趣味もあって、基本衝動買いです。 抵抗・コンデンサ・ダイオード・変換小基板・ケーブル・ネジ類等々は備蓄しています。 自宅にあるサンプル品は測定器と同様にデバッグ・評価機のみに使います。 正式な製品には会社で管理している部品のみ使います。 部品サンプルのごく一部 リモートで多分一番大変な業務はこれら小物の整理・管理でしょう。でも、豊富な小物がすぐに使える状態になっていてこそ、リモートでハードウェアエンジニアの業務を出来ているんだと思います。 終わりに 元々持っている物も多かったけど、アプトポッドはリモートワークにあたって必要な物品の支給を提案してくれました。 よって、よく使う機器や小物は全て自宅にあるので、問題なくリモートワークできています。 以上、長々と自分のリモート環境について述べてしまいました。 でも、お時間がある時、こちらのおまけ(パパエンジニアの週末)も読んで頂ければ嬉しいです。 最後までご覧くださいまして、ありがとうございました。 パパエンジニアの週末(おまけ)  ある週末、長男がいきなり仕事部屋に入りました。 長男:パパ!今日基板できる? 私:何の基板? 長男:プラレールの基板、自動のやつ。 私:自動ってどんな風に?もっと具体的に説明してみて? 長男:電車は衝突しないように、あと、タブレットで操作したい。 私:タブレット操作は難しいな。まず、衝突しないようにすることに絞ってみようか。 長男:横にぶつからない為には緊急停止、前に電車がある時はブレーキ、減速する… 私:そうだね、電車を止めるのもブレーキをかけるのも、スピードを調整する必要があるね。それで、どうやって前に電車があるのを判断するの? 長男:前に使った音波センサーがある。使えない? 私:超音波センサー?良いかも。前に使ったのは電車にのせるには少し大きいから、もっと小さいものか、別の種類のセンサーを探しておくね。 長男:分かった。あとはいろんな電車に取り付けたい。 私:分かった。なるべく小さい基板にまとめれば他の電車にも使えるね。一応、今までの目的をノートに書いておいて。 長男:こんな感じ 目的1:スピードを調整する。 目的2:遠隔操作をする。無線で操作をする。 目的3:センサーで止まるようにする。 目的4:色々な電車にとりつける。 私:いいね。じゃ、今日は目的1をやってみようか。これはプラレールに入っているモーターと同じです。電池を接続するとこう回る。スピードを上げたい時、どうやる? 長男:パワーを上げる、電池を増やす! 私:学校で勉強したと思うけど、電池はどうやって接続する?並列?直列?接続してみて。 長男:直列!並列は電池を長く使いたい時! 私:大正解!直列に電池を増やせばモーターがより速く回せるの。でも、今回はスピードを上げるのではなく、電車を遅くしたり、止めたりしたいんだよね。どんな方法があると思う? 長男:電気切れば止まるけど、スイッチ? 私:そう!スイッチ。電車のスピードを調整するには、素早くON/OFFを切り替えれば いいの。先のモーターと電池の間、自分でスイッチをON/OFFして、動かしてみて。 …PWM制御をしばらく説明して… 私:どう?さすがに手で調整するには限界があるよね。私達は手で1秒間10回ON/OFF出来ないでしょう?そこで、手動スイッチの代わりに電気的なスイッチを使うための回路を作ります。 私:まず、モーターを動かすにはモーターに必要な大きい電流をON/OFFできるスイッチの代わりの「トランジスター」という部品(コレクター-エミッタ)を置くね。そして、こちら側(ベース)に小さなON/OFF出す機器を入れる。私達の手の代わりになる。信号発生措置、英語で“Signal Generator”、”SG“と書いてある。 私:さっきの電池、モーターとあわせてこんな回路になる。そして今回、モーターが止まったときに高い電圧が出ると他の部品が壊れる恐れがあるので、この部品、ダイオードを追加する。 長男:ダイオード…? 私:ダイオードの説明は別の機会に説明するね。そろそろ、回路を組んでみようか。部品はちゃんとデータシートを読まないといけないけど、今日は手持ちの部品から選ぶので、ちょっと違うやり方をする。 長男:どういうふうに? 私:手持ちの部品の中で大きい電流を流しても壊れない部品を選んでいるの。本来は電流のほかに、小ささ、値段、損失など、考慮するポイントが結構あるんだよ! 長男:わかった! 私:できた!電池の代わりにこの電源(安定化電源)を使ってみる。電圧は電池と同じ1.5Vにした。オシロをみて、黄色波形はSGからのON/OFF信号だ。緑はモーターに流れる電流だ。 私:SGのこれ(Duty)を1から99まで調整できる。1にするとONの信号がとても短い、モーターは? 長男:止まってる! 私:では、このつまみを回して、この数字(Duty)を大きくしてみて。 長男:音が大きくなる、モーターが速くなる!ONが長くなる!どこまで上げて良いの? 私:フルパワーは99、通常は75かな? 周波数25Hz, duty 75% 周波数25Hz, duty 25% 長男:75は通常速、5で止まる、高速は85?75とあまり変わらない・・・じゃ、通常速60、高速85、低速20位にしてみようかな・・・停止が1・・・、でも、カクカク言っていて、なんかディーゼル車みたい。結局止まっているけど電流が流れている?これ0に出来ないの? 私:そう、1でも電流は流れるよ。電流の最大値も大きくなっていない?これは止まっているのに無駄にエネルギーを消費していてよくないね。スピードを決めるとき、その辺、ちゃんと確認しよう。この“ON/OFF”ボタンで完全に停止できる。 長男:分かった! 私:今回はSGからON/OFFの信号を出しているけど次はもっと小さい部品から作らないといけないね。 長男:じゃ、レベル1クリアってこと?次はプログラミングも入る? 私:そう、プログラミングに入る。どんなICでやるのか調べて置くね。今日はここまででいい? 長男:分かった、ありがとう!じゃ、行くね! 私:はい、お疲れ! あれっ!週末、結局仕事をしているじゃないの!?次世代のエンジニアが誕生するなら良いか!
アバター
こんにちは。ソリューションプロフェッショナルグループの新崎です。 最近「intdash で収集したデータをユーザー所有のクラウドストレージに転送する」という機能開発を担当しました。ユーザー所有のクラウドストレージにアクセスするためにはユーザー環境の認証情報が必要になります。しかし、認証情報をそのまま受け取ってしまうとセキュリティ対策として管理コストが大きくなったり、ユーザー自身で頻繁に認証情報のローテーションをしていただかなければならなくなったりと、サービスとしてのユーザビリティにも影響が出てしまいます。 今回の開発ではワークロードを AWS Lambda 上に構築していましたので、「ユーザー所有のクラウドストレージ」が Amazon S3 であれば AWS Security Token Service の AssumeRole を利用して一時トークンを発行する方式を採用することで、これらの課題を解決できます。本記事ではさらに一歩踏み込んで「ユーザー所有のクラウドストレージ」が AWS の外、具体的には GCP の Cloud Storage だった場合についても同様の一時トークン方式で実現させる方法をご紹介したいと思います。 Workload Identity 連携 ユーザー環境での準備 事前準備 サービス アカウントの権限借用を許可する権限を外部 ID に付与する サービスワークロードでの処理 まとめ Workload Identity 連携 サービスアカウントキーを使用せずに GCP のリソースへのアクセス権を、オンプレミスまたはマルチクラウドのワークロードに付与するためのサービスとして Workload Identity が活用できます。 Google Cloud のブログ記事 に記載のある以下の手順で設定をしていきます。 GCP プロジェクトで、Workload Identity プールのリソース オブジェクトを作成します。Workload Identity プールは、キーを必要としない連携メカニズムを容易にするために構築された新しいコンポーネントです。このプールは、外部 ID のコレクション用のコンテナとして機能します。 1 つ以上の IdP を Workload Identity プールに接続します。IdP は、OIDC プロトコルをサポートする AWS や Azure のアカウントまたはプロバイダのいずれかになります(SAML もまもなくサポート)。 次の 2 つの IAM ポリシーを定義して、プールにリソースへのアクセス権を付与します。 サービス アカウントに、目的のリソースへのアクセスを許可するポリシー。新しいサービス アカウントを作成することも、既存のサービス アカウントを再利用することもできます。 プールの ID が、サービス アカウントになりすますことを許可するポリシー。これらのポリシーの作成に関する詳しい情報については、ドキュメントをご覧ください。 ワークロードを STS エンドポイントに対して認証し、サービス アカウントになりすまして、目的の GCP API を呼び出します。 ユーザー環境での準備 ユーザー環境(GCP)では以下の手順で設定をしていただく必要があります。 事前準備 事前準備として、GCP のコンソールやコマンドラインツール等を使って こちらの公式ドキュメント を参考に Workload Identity プールとサービス側の AWS アカウントと紐付けたプロバイダを作成しておきます。また、アクセス許可するリソースに対するアクセス権を持ったサービスアカウントも作成しておきます。 サービス アカウントの権限借用を許可する権限を外部 ID に付与する GCP のコンソールで Workload Identity プールのページより事前準備で作成した Workload Identity プールを見つけて開きます。 Workload Identity プールを開いたところ 画面上部の アクセスを許可 をクリックし、開いたナビゲーションに従って必要な項目を入力していきます。 アクセス許可を設定 サービスアカウントには事前準備で作成したサービスアカウントを選択します。また、必要に応じて AWS ロールでのフィルタ条件を設定します。 保存 をクリックすると次のような画面がポップアップします。 構成ファイルをダウンロード プロバイダを選択し 構成をダウンロード をクリックすると構成ファイルがダウンロードされます。このファイルの中身は以下のような JSON になっています。 { " type ": " external_account ", " audience ": " //iam.googleapis.com/projects/************/locations/global/workloadIdentityPools/sample/providers/sample-aws ", " subject_token_type ": " urn:ietf:params:aws:token-type:aws4_request ", " service_account_impersonation_url ": " https://iamcredentials.googleapis.com/v1/projects/-/serviceAccounts/workloadidsample@**************.iam.gserviceaccount.com:generateAccessToken ", " token_url ": " https://sts.googleapis.com/v1/token ", " credential_source ": { " environment_id ": " aws1 ", " region_url ": " http://169.254.169.254/latest/meta-data/placement/availability-zone ", " url ": " http://169.254.169.254/latest/meta-data/iam/security-credentials ", " regional_cred_verification_url ": " https://sts.{region}.amazonaws.com?Action=GetCallerIdentity&Version=2011-06-15 " } } サービスアカウントキーのような認証情報が含まれていないことがご確認いただけると思います。このファイルをサービス側に連携していただき、ユーザー環境での準備は完了です。 サービスワークロードでの処理 サービス側の AWS Lambda では次のようなコードを実行しています。 package main import ( "context" "gocloud.dev/blob" "gocloud.dev/blob/gcsblob" "gocloud.dev/gcp" "golang.org/x/oauth2/google" ) func WriteGCS(ctx context.Context, cred, bucketName, objectName string , content [] byte ) error { // 一時トークンを発行して GCP クライアントを生成 creds, err := google.CredentialsFromJSON(ctx, [] byte (cred), "https://www.googleapis.com/auth/devstorage.read_write" ) if err != nil { return err } client, err := gcp.NewHTTPClient(gcp.DefaultTransport(), gcp.CredentialsTokenSource(creds)) if err != nil { return err } // 以下は通常通り Bucket オブジェクトを生成して書き込み処理を実行 bucket, err = gcsblob.OpenBucket(ctx, client, bucketName, nil ) if err != nil { return err } if err := bucket.WriteAll(ctx, key, bt, nil ); err != nil { return err } return nil } 前提として Go CDK を利用しています。このモジュールはクラウドサービスへのアクセスを抽象化してくれているので、今回のように複数のクラウドサービスを跨いだ処理が必要な際にとても便利です。 WriteGCS 関数の引数には cred : ユーザー環境で取得していただいた構成ファイルの JSON 文字列 bucketName : 対象のバケット名 objectName : 対象のオブジェクト名 content : 対象のオブジェクトのコンテンツ がそれぞれ渡される想定です。 creds, err := google.CredentialsFromJSON(ctx, [] byte (cred), "https://www.googleapis.com/auth/devstorage.read_write" ) ここの3番目の引数はスコープを指定するのですが Google API の OAuth 2.0 スコープ というドキュメントがあるのでここから必要なスコープを指定します。ドキュメント内でも記載がありますが、できるだけ機密性の低いスコープを使用することが推奨されています。今回は Cloud Storage への読み込み/書き込みを可能にしたいので https://www.googleapis.com/auth/devstorage.read_write を指定しています。 以降、クライアントを生成してバケットオブジェクトの読み書きメソッドを呼ぶ流れはサービスアカウントキーを使った場合と同じです。実装時に認証方式をそれほど意識せずに済むようになっています。 まとめ Workload Identity 連携を利用することで、セキュリティリスクを最小限に抑えたシステム構成が実現できました。クラウドを活用したマイクロサービス化が進むとサービス間認証は課題となってくるので、今回のような仕組みを活用できる機会が今後増えてきそうです。
アバター
コーポレート・マーケティング室、デザインチームの高森です。アプトポッドのデザインチームでは、これまで Sketch と Zeplin を利用してデザインと開発側への共有を行ってきたのですが、今後デザインワークフローの改善やプロトタイプの共有しやすさを考慮し、Sketchから Figma へ移行することとしました。 Figmaについては紹介されている記事がたくさんあり、さっと使ってみた感じも使いやすかったため、操作にそこまで不安はなかったのですが、デザインツール変更にあたり確認したポイントを紹介します。SketchからFigmaへの移行を検討されてる方の参考になればと思います。 Figma移行時に確認したポイント ローカルフォントが問題なく使えるか ネットワークに繋がってない時も使えるか アカウント発行無しでデザインを共有できるか パスワード付きURLでデザインを共有できるか Figmaを選択した理由 プロトタイプが作りやすい&共有しやすい 学習コストが低い デザインファイルが管理しやすい 開発者へ共有しやすい コストパフォーマンスが良くなる ツールの安定性が高い 動きが軽い 導入してから気づいた課題 ライブラリは作り直しが必要 ライブラリ更新によるデザインの自動更新 おわりに Figma移行時に確認したポイント FigmaはブラウザベースのためPC環境に依存せずデザイナー以外でも使える点がメリットですが、デザイナー以外も使うからこその懸念点としてまず以下を確認しました。 ローカルフォントが問題なく使えるか aptpodの製品はAxisフォントを使用しているため、デザイナー以外のパソコンでもちゃんと表示されるのかを懸念しておりましたが、閲覧権限で共有すればフォントは問題なく表示されました。編集権限で共有した場合も表示はされますが、ツールバーにアラートが表示されフォントを置き換えまたはインストールするまでテキスト編集はできません。 ツールバーにアラートが表示される ネットワークに繋がってない時も使えるか オフライン状態でファイルを開くことはできませんが、作業途中にオフラインになった場合は問題なく作業を続けられました。変更内容は再度オンライン環境になった時に更新されます。移動中など万が一ネットワーク環境が悪い中で作業が必要になった場合でも使えそうです。 アカウント発行無しでデザインを共有できるか 閲覧権限であれば無料かつアカウント発行無しで共有できます。 デザインの編集やコード情報が不要な社内のメンバーやクライアントにデザインを共有する際に、URLのみで共有できるためとても便利です(Sketchではアカウント発行が必要でした) パスワード付きURLでデザインを共有できるか 共有時のURLにはパスワードが設定できるため、社外のメンバーに共有する際にも問題ありません。(パスワード付きのURLは有料アカウントで利用可能です。無料アカウントではメールアドレスで招待、パスワード無しのURL共有が可能です) Figmaを選択した理由 今回、初めからFigmaへの移行を検討していたわけではなく、デザインデータの運用ルールを定めたりデザインガイドラインを作成する取り組みの一環としてツール検討を進めていました。そのため本格的なプロトタイプツールからデザインドキュメントツールなどを検討し、結果的に以下の観点でFigmaを導入することとしました。(デザインドキュメントツールの検討経緯は こちら でも紹介しています) プロトタイプが作りやすい&共有しやすい Sketchのプロトタイプ機能はページ遷移をつける程度しかできないため今ひとつ利用機会がなかったのですが、Figmaではページ遷移、オーバーレイ表示、ボタン状態の設定など、必要最低限のプロトタイプ機能が簡単に作れる様になっています。 アカウント発行不要で共有できるため社外のクライアントへも共有しやすくプロトタイプ作成⇄レビューのやり取りがしやすくなりそうです。 学習コストが低い FigmaとSketchでは、Symbol(Figmaではコンポーネント)へのアクセス、ArtboardがFrame/Groupになっているなど大きな違いはいくつかあるのですが、基本的なショートカットや機能は共通で、これまでSketchを使っていたメンバーなら習得しやすいと感じています。 Sketchファイルがインポートでき、こちらもレイアウトのずれやシェイプの崩れはいくつかありますが、事前にSketch側でファイルを調整すれば問題なく調整できるレベルなので、これまでのSketchファイルも活用できそうです。 デザインファイルが管理しやすい Sketchには無かったVariant機能によってパーツの状態やタイプをグルーピングできるので、ライブラリの管理がとても便利になりそうです。 開発者へ共有しやすい ブラウザベース且つコーディング情報を取得できるため(要アカウント発行)、これまでZeplinを利用していた開発者への共有をFigmaで完結できるのではないかと考えています。デザインファイル上にコメントも記入できるため、やりとりもしやすそうです。 Inspectタブからコーディング情報取得可能 デザインファイル上に直接コメント可能 コストパフォーマンスが良くなる SketchとZeplinで進めきたワークフローをFigmaで完結できる様にした場合、これまでよりもコストが抑えられそうです。 開発側への共有に必要なデザインの閲覧とコーディング情報取得は無料アカウントの範囲で可能なため、デザイナーのみの有料アカウントで十分になります。 ※aptpodではProfessionalプランを利用することにしましたが、社内にデザインチームが複数あり権限を分ける必要があるといった場合はOrganizationプランが良さそうです。Organizationプランの内容に関しては こちら の記事を参照してます。 ツールの安定性が高い Figmaは現在UIデザインツールとしてメジャーなものとなっていて、 2021 Design Tools Survey によると、UIデザインツールとしてメインでFigmaを使っている人は最も多い割合になっています。サポートやアップデートの観点からユーザー数が多いという点はとても心強いです。 動きが軽い Figmaは動きが軽いと聞いていましたが、実際に使ってみても軽く感じています。Sketchではファイルを開くのに時間がかかったりアプリが突然落ちることも頻発していたため、ストレス無く作業ができる様になりました。今後プロジェクトやページ数が増えていっても軽さが保たれるかは要経過観察ではあります。 導入してから気づいた課題 ライブラリは作り直しが必要 FigmaにもSketch同様ライブラリ機能がありますが、ライブラリは有料版の機能だったため、導入するまでどのような使い勝手か確認できませんでした。 実際に有料版を契約しSketchからライブラリデータを移行したところ、ライブラリから参照しているリンクは切れてしまうため、再度Figma上でライブラリからコンポーネントを割り当てる必要がありました。こちらについてはコンポーネントの階層の扱い方がSketchと異なるため、ライブラリ自体作り直す方が早そうですが、Variant機能があるため作り直しはそれほど手間はかからずできると思います。 ライブラリ更新によるデザインの自動更新 ライブラリを更新することで、古いデザインを残しておけなくなることに気づきました。 これまではZeplin上に切り離して共有していたため、ライブラリを更新した場合もZeplin上のデザインには影響がなかったのですが、デザイナーが作業するファイルと開発者が参照するファイルが同一の場合、開発版とリリース版とデザイン途中のファイル、それぞれの管理をしっかりしておく必要があります。同じライブラリを使っている場合、参照しているコンポーネントが一斉更新されて問題がないかなど、今後ファイルの管理方法に工夫が必要そうです。 おわりに まだまだFigmaを導入し始めたばかりでデータの移行も完了しておらず、実際に導入することになってから気づいた細かい不明点も出始めてきておりますが、現状のところ軽さというのが大きな助けとなっており大きなストレスなく作業できています。使い方については検索すればたくさん出てくる点もとても心強いです。また、最近日本語にも対応されたため、これから導入する際により使いやすくなりそうです。( Figma日本語対応のお知らせ ) デザイン作業だけでなく、ワークフローをスムーズに運営できることを意識して、Figmaをこれから開拓していきたいと思います。最後まで読んでいただきありがとうございました。
アバター