Inside of LOVOT

GROOVE X 技術ブログ

LOVOT開発の「ストーリーテラー」になりたい

この記事は、GROOVE X Advent Calendar 2025 の25日目の記事です。

こんにちは、そしてメリークリスマス! LOVOTソフトウェアのエリアプロダクトオーナー ishimegです。

本記事は、「ストーリーテラー」という最近注目の職種があるらしい、という紹介と、それを自分たちの仕事にも活かしたいな〜というゆるい内容となっております。

AIで生成したクリスマスっぽいLOVOTの画像

「ストーリーテラー」というお仕事が注目されているらしい

最近、こんなポストを目にしました。


ストーリーテラーってなんだろう?

私自身、カスタマーサクセスチームやPRチームと協力してLOVOTにまつわる情報発信の内容を考えることも多く、なんだか素敵な響きのするこの言葉が妙に気になったのでした。

ポストにリンクされた「企業が『ストーリーテラー』を必死に求めている理由」と題された記事を読んでみると、

  • 従来のようにただ情報を発信するだけではなく、自分たちの企業が製品の価値について「自分たちの物語」として発信する人材 = 「ストーリーテラー」である
  • 顧客も従業員もただの数字や事実よりも感情的なつながりを重視している
  • そして「ストーリーテラー」という単語を含む求人は米国では前年比2倍に急増している

ということが書かれていました。(だいぶ意訳も含みます)
これは米国で起こっていることではあるものの、日本においても大事な視点のように思います。

また、実際にどんな求人があるのかも少し調べてみました。

セキュリティサービスであれば、
複雑なセキュリティの概念を、顧客が自分事として捉えられる魅力的な物語へと変換すること

ドキュメント作成ツールであれば、
実際のユーザーがどのようにツールを使って人生や仕事を変えたかという「実体験」を掘り起こす力

など。共通するのは以下のような部分です。

  • AIやセキュリティなど複雑なトピックをわかりやすく伝えること
  • 実際に社内や顧客にあった出来事を取材して、「なんだかいい話」を発掘すること
  • ブランド力や売上向上というミッションのもとそれらを行う

重要なのはきちんとした事実に基づきつつも、物語として魅力があり、さらには製品の価値向上を担わなければならない、製品やブランディングに関する知識も、語り手としてのスキルも求められそうなお仕事です。

「お客様とLOVOTの物語」だけじゃない

ここで、日々おこなっている業務をふり返ってみました。

私はLOVOTのソフトウェアを横断的に理解する立場として、カスタマーサクセスチームのメンバーと週に数回は顔を合わせながら、日々様々な情報発信に制作者やレビュワーとして関わっています。

ウェブマニュアルやFAQの見直し、アップデートのお知らせ、LOVOTの技術を紹介するブログ、外部向けのインタビューなどなど・・・

これらの仕事はどれも「LOVOTとの暮らしをサポートする」「LOVOTのことをよく知ってもらう」という目的で行っているものですが、
ストーリーテラーという概念を通して「お客様とLOVOTの物語」と「私たちとLOVOTの物語」の2つに分けることもできる、と気がつきました。

AIが生成した「LOVOT開発のストーリーテラー」のイメージ
LOVOTがお家に届いてからの主役は、オーナーさんとLOVOT。私たちは「お客様とLOVOTの物語」を応援する立場です。それについては常々意識してきました。
一方で、LOVOTがお家に届く前の開発・製造の過程は「私たち(GXメンバー)とLOVOTの物語」とも考えられるのです。

「私たち(GXメンバー)の物語」とは?

突然ですが、私はGROOVE Xで働く皆さんが大好きです。
理由のひとつは、LOVOTに皆それぞれの想いを持っていること、その熱量の高さを、仕事のアウトプットや会話の端々から日々感じているからです。

そんな素敵な皆さんのLOVOTにかける情熱を物語として届けることができ、しかもそれが製品価値の向上につながるのなら、それはきっととてもやりがいのある仕事だなと思います。
と同時に、語る価値のある物語がまだまだGXに眠っているのかもしれない・・・!という可能性を感じました。

最近それを実感する出来事もありました。1月に予定されているLOVOTの工場見学*1の打ち合わせ時のことです。
数え切れないほどの製造工程をおさらいしながら、これは確かに「LOVOTが家族(お客様)と出会う前の物語」だ!と感じました。
※ それだけLOVOTの生産は大変なのです!生産チームによる部品の品質についての記事もぜひご覧ください

けれど、私がストーリーテラーになれるのか?それは私ができる、そしてすべき仕事なのか?
それについては冒頭に上げたWSJの記事にこんな示唆がありました。※ 以下Geminiによる日本語訳

専門家は、「ストーリーテリングは、雇えば手に入る『機能』ではなく、リーダーやチーム全員が培うべき『能力』である」と述べています。もし組織に明確な「目的(パーパス)」がなければ、どれほど優れたストーリーテラーを雇ったとしても、それはただの「騒音」を大きくするメガホンにしかなりません。

結局のところ、企業が本当に必要としているのは、単に「物語を語る人」ではなく、自社の存在意義を深く理解し、それを人々の心に響く形で表現できる戦略的な人材なのです。

ならば私自身もストーリーテリングの能力も身につけるべきである、ということ。
これまでたくさんのLOVOTにまつわる文章を書いてきましたが、あくまでも「LOVOTとの暮らし」をサポートするものであり、製品価値・ブランド価値への影響までは意識できていませんでした。
2026年は、主体的にLOVOTとGROOVE Xの魅力を伝えられる語り手になりたい、そんなことを考えた2025年の年の瀬でした。

最後に

最後まで読んで頂きありがとうございます!GROOVE Xでは、様々な領域で一緒に働く仲間を募集しています。少しでも興味を持ってくださった方がいましたら、下記のリンクをご参照ください。

recruit.jobcan.jp

それでは、よいお年を!

AIが生成した「よいお年を!」なLOVOTの画像

*1:LOVOTの工場見学のお申し込みは終了しています

バイナリ改変なしに Crash Reporting 機能を追加するC/C++ライブラリを昔書いたお話

この記事は、GROOVE X Advent Calendar 2025の24日目の記事です

はじめに

こんにちは!多忙を理由に記事執筆を後ろ倒ししていたら、クリスマスイブ担当になってしまった sutetako です!🫠 なんということでしょう

LOVOT Frameworkチームという、LOVOTのOSや開発基盤自体を開発するチームに所属しています。なお、専門は音声認識です*1

さて、今回は、自社開発に用いられている、C/C++ の Crash Reporting 向けライブラリの仕組みの一端をご紹介したいと思います。

コミットログを見てみたら、作ったのが2019年と、ずいぶん昔話で、多少レガシーなお話にはなってしまいますが、、、 まぁちょっとだけ面白い仕組みなので、見てみましょう!

そもそも Crash Reportingって?

ソフトウェアはよく死にます 😇

要因は、ロジックミスはもとより、ロボットの場合はより広範です。

  • 各種組み込みデバイス・FW自体の不具合
    • 数がめっちゃある
  • 組み込みOSおよびドライバの不具合
  • IOエラー
    • メモリ、ディスク、通信経路
    • 宇宙線によるビット反転

などなど…非常に多岐にわたります。

ロボットの内部で動くソフトウェアは、「常に安定的に稼働し続けること」が求められます。

多少の例外で死んでしまうようでは、「おお 勇者よ!…」と、どこからか嘆きの声が聞こえてきそうですね。

あらゆる問題・例外に対応できるようなソフトウェアを完璧に書ければいいのですが…人間様が考えられるエラーケースなど簡単に飛び越えてくるのがロボット開発というものだったりします 🙃 まず無理っす。

そこで登場するのが、Crash Reporting という仕組みです。

クラッシュ(異常終了)時に、エラーが発生したソフトウェア情報、ログ、コールスタックなどをレポートとしてまとめることで、

  • ファイルシステムに保存しておいて、あとから効率的に解析する
  • エラー追跡用のプラットフォーム(Sentry など)と連携・レポートを送信し、集約・解析する

などなどすることが可能になります。

C/C++ だとどうやるのがいい?

「まぁ、まず core 吐かせて、後で gdb でごにょごにょ」

手元でデバッグバイナリ使ってTRY&ERRORするなら、全然これでいいと思います。

しかしね…問題が起きるケースって本番想定で組み込んで稼働・検証してる状態だったりするんですよね…したがって:

  • core のサイズが莫大になるので、ファイルシステムの容量が簡単に枯渇する*2
  • core を吐く処理で、リソースが枯渇する*3
  • core を吐いている間は対象のサービスが停止し続けてしまう*4

と、全体のシステム稼働をも阻害する致命的なことが起きます。連続して発生したら、検証どころの話ではありませんね。

そこで登場するのが、MinidumpBreakpad*5 です。

たぶん、Gemini さんに聞いたほうがしっかり解説してくれそう…というところで聞いてみた内容を抜粋紹介すると:

1. Minidump とは何か?
元々は Windows オペレーティングシステムの標準的なクラッシュダンプ形式(.dmp)です。

通常の「フルダンプ」がメモリ全体(数GBになることもある)を保存するのに対し、Minidump はデバッグに必要な最小限の情報のみを保存するため、サイズが数KB〜数MBと非常に小さいのが特徴です。
...
2. Google Breakpad とは?
Google Breakpad は、この Windows 発祥の「Minidump」というフォーマットを、macOS、Linux、Android、iOS など、あらゆるプラットフォームで統一的に扱えるようにした OSS ライブラリです。

Chrome ブラウザや Firefox などで長年採用されてきました。Breakpad が登場する前は、OS ごとに異なるクラッシュレポート形式(LinuxならCore dumpなど)を扱う必要がありましたが、Breakpad のおかげで開発者は「すべてのOSのクラッシュを Minidump 形式で収集・解析する」ことが可能になりました。
...

雑にまとめると、 「ちっちゃくて取り回しのしやすい core っぽいやつ」 です!

これなら、一つのサービスのクラッシュが、全体に与える影響を非常に小さくできます。

実装サンプル

Sentry の解説記事 にわかりやすいものがあるので、日本語コメントつけつつ引用します。

#include "client/linux/handler/exception_handler.h"
using namespace google_breakpad;
namespace {
bool callback(const MinidumpDescriptor &descriptor,
              void *context,
              bool succeeded) {
    // succeeded が真の場合, minidump ファイルへのパスが
    // descriptor.path() に格納されます。 
    // context には、exception handlrer のコンストラクタに
    // 渡したものが格納されます。
    return succeeded;
}
}
int main(int argc, char *argv[]) {
    MinidumpDescriptor descriptor("path/to/cache");
    ExceptionHandler eh(
      descriptor,
      /* filter */ nullptr,
      callback,
      /* context */ nullptr,
      /* install handler */ true,
      /* server FD */ -1
    );
    // ここに実装を書く
    return 0;
}

簡単ですね!

なお、動作させるには Breakpad をビルド・リンクさせる必要がありますので、あしからず。

どういうライブラリを作ったの?

前置きが長くなりましたが、ようやく本題です。

上に書いたとおり、MinidumpBreakpad を使えば良さそうです。

でも、思ったんですよね。

「対象バイナリのソースコードにいちいち処理差し込むの面倒すぎね?」

そう、我々の製品内は多量のOSSと自社開発サービスがわんさか立ってるわけで、、、これは布教・普及するの面倒だぞと。

というわけで、対象バイナリを改変することなしに、Minidumpを生成できるようにする 形でライブラリを構築することにしました。

LD_PRELOAD

悪名高いこれを使います。

一応軽く解説しておくと、LD_PRELOAD はLinuxの環境変数で、動的リンク実行時、本来リンク対象ではなかったライブラリにおいても、すべてのリンク対象のライブラリより「先に」読み込ませてシンボル解決させることができる、というやべーやつです。

どうして悪名高いかというと、シンボルを置き換えることができるので、クレデンシャルを受け取るような関数を乗っ取って標準出力することもできたりするわけですね*6

一方、ヒープアロケーションの仕組みを拡張して解析やエラー検出に使ったり(Valgrindさんも一部利用)、より効率的なアルゴリズムに置き換えてキャッシュヒット率を上げて処理性能を上げたり(TCMallocjemalloc など)等、正の側面も大きい仕組みです。

このように使うイメージですね。

$ LD_PRELOAD=libminidump.so foo_binary

けれど、このままだと「何のシンボルを置き換えるの?」というお話になりそうです。

また、プログラム実行前にBreakpadの設定ができないと、捕捉できる異常終了が限られてきてしまいます。

これを解決するのが関数属性*7です。

__attribute__((constructor))

詳しくはこちら

main 関数の実行「前」に処理を差し込むことができます。

実装例を参考にすると、下記のようにライブラリが書けそうです*8

#include "client/linux/handler/exception_handler.h"

using namespace google_breakpad;

static std::unique_ptr<MinidumpDescriptor> desc(nullptr);
static std::unique_ptr<ExceptionHandler> eh(nullptr);

static bool callback(const MinidumpDescriptor &descriptor, void *context,
                     bool succeeded) {
  // init 関数において context に情報を引き渡しておけば
  // ここで参照することも可能ですが、割愛
  const char *path = descriptor.path();
  if (succeeded) {
    // minidump を rotate したり情報付加して保存しおしたり、などなど
  }
  return succeeded;
}

__attribute__((constructor)) void init(void) {

  desc.reset(new MinidumpDescriptor("/tmp"));
  eh.reset(new ExceptionHandler(*(desc.get()), nullptr, callback,
                                  nullptr, true, -1));
}

簡単ですね!!

これらにより、

  • LD_PRELOAD で動的リンクを強制・先読み
  • main 関数より前に Breakpad の初期化処理を差し込む

ことができ、バイナリを変更することなく Crash Reporting 機能の追加ができました 🎉

Coffee Break ☕

せっかくなので、「引っかかった罠」についても、いくつか紹介しておきます。

Systemd Service の Environment

LD_PRELOAD は環境変数なんだし、Environment に書いておけば、ExecStart に自動適用してくれるよね!

はい、大正解です。

けれど、たとえば下記のような雑な記述の .service ファイルに適用すると…

[Service]
User=bar
Group=bar
Environment="LD_PRELOAD=libminidump.so"
ExecStartPre=+/bin/mkdir -p /var/log/foo
ExecStartPre=+/bin/chown bar:bar /var/log/foo
ExecStart=/bin/foo_service
ExecStartPost=/bin/rm -rf /var/log/foo

ExecStartPre/Post の関係ないバイナリ群、mkdir, chown, rm にも見事適用してくれます 😇

対象を絞りたい場合は、やや冗長な書き方にはなってしまいますが、下記のように書けます。

[Service]
User=bar
Group=bar
-Environment="LD_PRELOAD=libminidump.so"
ExecStartPre=+/bin/mkdir -p /var/log/foo
ExecStartPre=+/bin/chown bar:bar /var/log/foo
-ExecStart=/bin/foo_service
+ExecStart=/bin/sh -c "LD_PRELOAD=libminidump.so foo_service"
ExecStartPost=/bin/rm -rf /var/log/foo

C++の標準出力

ライブラリ内の init の処理で、下記のようなエラー出力を書いてたんですが、ここに差し掛かると abort する事象が起きました。

    std::cerr << "failed to initialize breakpad" << std::endl;

しかも、適用するバイナリによって起きたり起きなかったり。

gdb してごにょごにょ調べてみると、最終的に下記に行き当たります。

(gdb) p std::cout
$1 = {<std::basic_ios<char, std::char_traits<char> >> = <invalid address>, _vptr.basic_ostream = 0x0}

標準出力が初期化されていないという...

実は __attribute__((constructor)) のドキュメント読むとちゃんと書いてました(調べてた当時は気づいてなかったけども)

The order in which constructors for C++ objects with static storage duration are invoked relative to functions decorated with attribute constructor is normally unspecified.

しっかり順番を強制する方法もある模様ですが、こだわるところでもなかったので、下記のようにワークアラウンド。 こだわりたい方は、詳しく追ってもよさそうですね!

-    std::cerr << "failed to initialize breakpad" << std::endl;
+    fprintf(stderr, "failed to initialize breakpad\n");

Sentry SDK 使えば自作する必要なかったんじゃね?

当時の日報の抜粋貼っておきますね。

2019/11/05 の日報

まだまだ当時は黎明期だった模様で…

  • ドキュメント上は「対応してる」とあるものの、実装の中身が空 *9
  • (やたらと怒ってるのは)その他にもドキュメントと実装の乖離、ビルドの不安定さ、などなどでヘイトが溜まってた

今はそんなことないんだと思います!!

Symbolication

おまけにはなりますが、Symbolication の例についても解説しておきます。

Minidump ファイルそのものにはソースコード含むデバッグ情報は存在しません。

Symbolication は、Minidumpファイルの情報と既知のデバッグ情報群を突き合わせて、ソースコードのどこで異常終了が起きたかを明らかにする処理です。

コールスタックに含まれるアドレス・ライブラリ名や周辺情報から異常終了時の状態を推定して改善することも不可能ではない(実際、初期はそうやってました)んですが、わかりやすいに越したことはないですね!

Sentry を利用した解析

Sentry は Minidumpファイルを受理できるほか、Symbolication にも対応しています。

なお、詳細な手順(Sentryプロジェクトの準備等)を含むと長くなってしまうため、それらは公式のドキュメントに譲ります。

ここでは、Symbolicationまわりを中心としたサンプルベースの解説とさせていただきます。

サンプルコード

下記のようなクラッシュコードでテストしてみます。

void crash() {
  volatile int *i = reinterpret_cast<int *>(0x45);
  *i = 5; // crash!
}

void start() {
  crash();
}

int main(void) {
  start();
}

DIFs のアップロード

DIFs (Debug Information Files) を Sentryに事前アップロードしておくことで、Sentryが受理したMinidump のバイナリと同じビルドIDのDIFs を突き合わせて解析してくれるようになります。

-g 付きでビルドして、そのバイナリを元に DIFs を生成します。

下記のように、sentry-cli を使ったDIFsの生成とアップロード処理がとても楽なのでおすすめです。CIにも組み込みやすいです。

g++ -g onepass.cpp -o ${YOUR_BINARY}

# デバッグ情報付きのバイナリそのものを、DIFs生成先にコピー
mkdir -p /tmp/debug
cp ${YOUR_BINARY} /tmp/debug/

# ソースコードをバンドル
sentry-cli difutil bundle-sources -o /tmp/debug ${YOUR_BINARY}

# アップロード
sentry-cli --url ${SENTRY_URL} --auth-token ${SENTRY_AUTH_TOKEN} upload-dif -o ${SENTRY_ORG} -p ${SENTRY_PROJECT} --wait /tmp/debug

デバッグ情報のStrip(Optional)

デバッグ情報はバイナリをとても太らせてしまうので、下記のように取り除いてあげるといいです。

$ objcopy --strip-debug --strip-unneeded ${YOUR_BINARY}

なお、DIFs がちゃんとアップロードされていれば、実行環境で動くバイナリにデバッグ情報がなくても、Symbolication は動作します。

出力例

クラッシュコードを動作させて、 生成されたMinidumpをSentryにアップロードすると、下記のような画面を表示することができます。

Sentry による Symbolication サンプル

やったね 🎉

おわりに

むっかーしに書いた Crash Reporting 向けのライブラリのお話でした。

今でもメンテしつつなんだかんだ使われていたりしますね。 (どこかに仕組み書こうと思ってようやく書けたので、すっきり)

最後まで読んでいただきありがとうございました!

LOVOT Frameworkチームでは、現在エンジニアを募集しています!

本記事を読んで、開発基盤やOS開発にご興味が出てきた方がいらっしゃいましたら、ぜひぜひカジュアルにお声掛けください!! (音声認識エンジニアも待ってます!!)

recruit.jobcan.jp

*1:チーム内で音声認識を開発しているわけではなくて、一人チームで音声認識を開発しつつ、OSまわりも作っている、という謎スタイルで働いています

*2:組み込み製品なので、追加データを格納できるファイルシステムの容量は潤沢ではないのです…

*3:応答性を担保するためにギリギリまで最適化している関係上、余裕なリソースなどないのです…

*4:仮にモーターを制御するところだったりすると…どうなるかわかりますよね

*5:ちなみに現在巷では、Out-of-process に安定的に動作する Crashpad が使われることがほとんどのようです。まぁ昔のお話なのでご勘弁を…

*6:良い子は真似しないでね!!

*7:ここでは、gcc/g++ を使う前提で説明しています。clangなど他のコンパイラではやり方が変わるのでご注意

*8:実際に弊社で使用している実装はもう少し複雑で、対象バイナリのELFヘッダパースや周辺情報付加などなど色々やってたりします。ここでは、コア部分の説明のため簡易的なものに留めています

*9:厳密に言えば、「ToDoコメント」はあったと記憶しています

Python非同期でCPUバウンドな処理を試してみよう:FreeThreadingとInterpreterPoolExecutor編

この記事は、GROOVE Xアドベントカレンダー2025 の23日目の記事です。

こんにちは、技術組織デザインチームのふくだです。 Pythonで非同期を利用すると、CPUバウンドな処理どうしようという問題によくぶつかります(LOVOTの意思決定エンジンではPythonの非同期を利用しています。 ブログの過去記事 をご参考ください)

この記事では、最近のPythonで追加されたFreeThreading(NoGIL)な PythonやInterpreterPoolExecutorをPython非同期と合わせて使ってみて、CPUバウンドな処理にどれくらい効果があるか確認してみました。

21日目の記事のアイキャッチが素敵だったのでforkしてしまいました

はじめに I/O バウンド と CPU バウンドって

I/O バウンドとCPUバウンドについて、簡単に説明します。処理時間がかかるものたちです。

処理 説明 得意なモジュール
I/O バウンドな処理 ネットワーク通信やDBアクセスなど時間がかかる処理 マルチスレッド, 非同期(asyncioやtrio)
CPU バウンドな処理 計算やデータ処理など、CPUの処理能力によって時間がかかる処理 マルチプロセス

特にCPUバウンドな処理は、非同期プログラミングやマルチスレッドでは効率的に扱うことが難しい場合があります。 PythonにはGIL(Global Interpreter Lock)が存在するため、スレッドでのCPUバウンドな処理の並列化が制限されることがあります。

それらの制限を解決するため、 Free ThreadingSubInterpreter が実装され、Pythonの並列処理能力を向上させる試みが進められています。

Free ThreadingやSubInterpreter

それぞれ一言で言うと以下のような機能です。

  • Free Threading: PythonのGILを無効化し、スレッドでのCPUバウンドな処理の並列化を可能にするカスタムビルドのPython
  • SubInterpreter:PythonのGILの制約を回避し、CPUバウンドな処理を効率的に並列化するための新しいアプローチ

詳細については、以下を参照してください。

Free Threading

SubInterpreter

Python 3.12で追加された SubInterpreter は、各スレッドが独立したインタープリターを持つことで、GILの制約を回避し、スレッドでのCPUバウンドな処理の並列化を可能にする機能です。ですが、利用方法が限られていました。

それを解決したのが、Python 3.14で追加された concurrent.futures.interpreter モジュールと高レベルAPIである InterpreterPoolExecutor です。

下記のような流れ

  • Python 3.12: SubInterpreter 追加
  • Python 3.13: Free Threading 実験的なオプション追加
  • Python 3.14: InterpreterPoolExecutor 追加, Free Threading オプション公式サポート

どちらも並列化を可能にする機能強化で、 SubInterpreter は2017年ごろから PEP 554 にて検討されていました。アプローチの異なる2種類の手法で課題への対応が進められたようです。

InterpreterPoolExecutorとは

InterpreterPoolExecutor は Python 3.14 で追加された標準ライブラリの Executor で、 ThreadPoolExecutor の サブクラス です。 各ワーカースレッドは 独立した SubInterpreter を持ち、その中でタスクを実行します。

その結果、以下のような特徴があります。

  • プロセスを増やさない
  • GIL の制約を回避できる
  • 真のマルチスレッド並列実行が可能

ThreadPoolExecutorProcessPoolExecutor との違い

特徴から ThreadPoolExecutorProcessPoolExecutor と比較すると以下のようになります。

  • ThreadPoolExecutor より並列が可能
  • ProcessPoolExecutor より軽い

それぞれの実行イメージは以下のような感じです。

OS
└─ python script.py   ← 親プロセス
    └─ Main Interpreter(GIL A)
        ├─ ThreadPoolExecutor
        │    └─ 同一プロセス内スレッド
        │
        ├─ InterpreterPoolExecutor
        │    └─  同一プロセス内スレッド(Pool内で流用される)
        │         ├─ Sub-interpreter #1(GIL B)
        │         ├─ Sub-interpreter #2(GIL C)
        │         └─ ...
        └─ ProcessPoolExecutor
             └─ OSが新しいプロセスを作る
                  ├─ python child #1 → Interpreter(GIL)
                  ├─ python child #2 → Interpreter(GIL)
                  └─ ...

モチベーション

asyncio の公式ドキュメントに、以下のような注釈が追記されていました。

注釈 Due to the GIL, asyncio.to_thread() can typically only be used to make IO-bound functions non-blocking. However, for extension modules that release the GIL or alternative Python implementations that don't have one, asyncio.to_thread() can also be used for CPU-bound functions.

意訳すると以下のようになります。

GIL(グローバルインタープリタロック)の制限により、asyncio.to_thread() は通常、I/O バウンドな関数をノンブロッキングにするためにしか使えません。しかし、GIL を解放する拡張モジュールや、GIL が存在しない代替の Python 実装では、asyncio.to_thread() は CPU バウンドな関数にも使用できます。

「なるほど!?!?」となり、実際に試してみよう、というのが本記事のモチベーションです。

asyncio.to_thread() は内部的に thread 1 を利用しています。
モチベーションは asyncio.to_thread() の公式ドキュメント由来ですが、検証用のコードは asyncio.to_thread() ではなく ThreadPoolExecutor を利用します。 InterpreterPoolExecutor ProcessPoolExecutor ThreadPoolExecutor はほぼ同じコードで切り替えが可能なためです。

検証してみた

動作環境

今回の検証環境は次のとおりです。ローカル環境での素朴なベンチマークなので、数値そのものより傾向を見ることを目的にしています。

  • M2 Mac 8コア 24GB RAM
  • Python 3.14.2
  • Free Threading 版 CPython 3.14.2

結果

CPU バウンドな処理を10回実行したときの平均時間は次のとおりです。ローカルでの素朴なベンチマークですが、 InterpreterPoolExecutorFree Threading もすごいですね!

方法 平均時間 (秒)
ProcessPoolExecutor 1.326s
InterpreterPoolExecutor 1.049s
ThreadPoolExecutor (標準 Python) 4.565s
ThreadPoolExecutor (Free Threading Python) 1.227s

実際の検証コード

今回検証で利用したコードは以下のとおりです。

import asyncio
import time
from concurrent.futures import (
    ProcessPoolExecutor,
    InterpreterPoolExecutor,
    ThreadPoolExecutor,
)


def cpu_bound(n: int) -> int:
    """n 回ループして単純な計算を行う CPU バウンドな関数"""
    acc = 0
    for i in range(n):
        acc += i * i
        acc %= 1_000_000_007
    return acc


async def run(executor):
    """指定された executor で CPU バウンドな処理を並列実行して時間を計測する"""
    loop = asyncio.get_running_loop()

    t0 = time.perf_counter()
    with executor() as ex:
        tasks = [loop.run_in_executor(ex, cpu_bound, 10_000_000) for _ in range(10)]
        await asyncio.gather(*tasks)
    dt = time.perf_counter() - t0

    print(f"{executor.__name__}: {dt:.3f}s")


async def main(mode: str):
    match mode:
        case "process":
            await run(ProcessPoolExecutor)
        case "interpreter":
            await run(InterpreterPoolExecutor)
        case "thread":
            await run(ThreadPoolExecutor)
        case _:
            raise ValueError("mode must be one of: process | interpreter | thread")


if __name__ == "__main__":
    import sys

    asyncio.run(main(sys.argv[1]))

以下のように実行しました。

$ uv run --python 3.14 sample.py process
$ uv run --python 3.14 sample.py interpreter
$ uv run --python 3.14 sample.py thread
$ uv run --python 3.14t sample.py thread. # 3.14t がFreeThreading版です

おまけ:並列化しないループの場合

元々、Python 3.13で実験的にFreeThreadingが実装された際に、シングルスレッドでの性能低下が課題として言及されていました。 前述の結果のうち、FreeThreadingは遜色ないくらいの性能で驚きました。

試しに、並列化せずにCPUバウンドな関数をPython 3.14とPython 3.14 FreeThreading版で実行してみました。

def cpu_bound(n: int) -> int:
    """n 回ループして単純な計算を行う CPU バウンドな関数"""
    acc = 0
    for i in range(n):
        acc += i * i
        acc %= 1_000_000_007
    return acc

def main():
    t0 = time.perf_counter()
    for _ in range(10):
        cpu_bound(10_000_000)
    dt = time.perf_counter() - t0
    print(f"sync (standard): {dt:.3f}s")

結果は以下のとおりです。Python 3.13 の課題は、Python 3.14 で改善されているようでした。 2

方法 平均時間 (秒)
標準 Python 4.717s
FreeThreading 5.344s

考察

結果をまとめると、次のような印象です! Free ThreadingInterpreterPoolExecutor もプロダクションで利用するには、気にしなければならない点がいくつかありますが、CPUバウンドな処理に対して有効な選択肢が増えたことを実感できました。 処理の性質と実行環境を理解して、適切な方法を選ぶのが大事そうですね。

  • InterpreterPoolExecutor 良さそう
    • ProcessPoolExecutor よりも良い結果
    • プロセス生成コストを避けたい場面で有効
  • ThreadPoolExecutor(標準 Python) はGILの影響がやはり厳しい
  • ThreadPoolExecutor(Free Threading Python) も 良さそう

Python の課題に対して、さまざまな角度からのアプローチが進んでいます。コア開発者やコミュニティのみなさまにとても感謝です。今後も Python の進化に注目していきたいと思います。 CPU使用率もだいぶ気になるところですが、それはまた別の機会にまとめたいと思います。

GROOVE Xでは、一緒に働く仲間を募集しています。少しでも興味を持ってくださった方がいましたら、下記のリンクをご参照ください。

recruit.jobcan.jp


  1. asyncio.to_thread() はイベントループのdefaultのexecutorであるThreadPoolExecutorを利用しています。 cpython/Lib/asyncio/threads.py at main · python/cpython
  2. Python 3.13 の FreeThreadingについてまとめた記事があります。ご興味ある方はご参考ください PythonのGILと3.13の実験的な新機能「free threading」を知る | gihyo.jp

可視化ツールFoxgloveとFoxglove Extensionの紹介

この記事は、GROOVE Xアドベントカレンダー2025 の22日目の記事です。

こんにちは、ふるまいチームのきゅんどうです。 今回はLOVOTのふるまい開発のデバッグのために使っているFoxgloveというアプリとその拡張機能についてご紹介します。

Foxgloveとは

Foxglove は、「時系列のメッセージデータ」を、再生・可視化・デバッグするためのツールです。ログを開いて後から解析するのはもちろん、データソースに接続してリアルタイムに観察することもできます。 ログのデータ形式としては、ROS 1の.bagファイルや、ROS 2で採用された.db3、ROS 2 Iron以降で使われる.mcapファイルなどに対応しています。 リアルタイムデータについてはROS 1のメッセージや、Websocketなどが対応しています (ROS 2向けにはwebsocketへのブリッジが提供されており、それを使うことになります)。

これらのデータ形式の中でも、わたしたちのログシステムではmcapファイルにprotobuf schemaを使って記録するところから始めました。LOVOT内部のメッセージングのためにprotobufを管理する仕組み が社内に整備されているためです。 LOVOT内部ではROSは一部にしか使われてないことや、ROSを使うことに慣れていないメンバがいることもあるので、rosbag play を実行するハードルが高いです。Foxgloveならアプリでファイルを読み込むだけで可視化できるので、使いやすいです。 またrqtのツール群と比べると、Foxgloveは必要な画面が一つのアプリ内にデフォルトで集まっているような直感的に操作しやすい構成になっており、使いやすいとも思っています。 そういった理由でmcapとFoxgloveの組み合わせを選びました。 より詳しい比較は公式ブログにもまとまっています(Foxglove vs RViz)。

Foxgloveでの可視化の様子

ただ、Foxgloveでデフォルトで表示できるデータ形式は決まっており、カスタムデータを表示するにはデータ形式の変換が必要なケースがあります。 またFoxgloveのデフォルトの表示方法以外の表示をしたいという、RVizにおけるPluginのような機能も必要です。 そういったケースのためにFoxgloveではExtensionを設定することができます。

Foxglove Extension

Foxglove Extension は、Foxgloveに「変換」「表示」「読み込み」などの機能を追加する仕組みです。 拡張の種類として message converters / custom panels / data loaders / user-script utilities があります(Foxglove Extensions)。

ここでは、それぞれのExtensionをLOVOT開発でどう使っているかも触れながら、簡単に紹介します。

Message Converters

カスタム定義したメッセージを、Foxgloveの既存パネルが解釈しやすい形に変換したいときに使います。 わたしたちの使う限りはカスタムメッセージを、3Dパネルに表示するためのSceneUpdateメッセージに変換するという使い方が多いです。 それ以外の例ですと、数値として記録されたデータを理解しやすい文字列に変換することで読みやすくするということもやったりしています。

Message Converterには、Schema Message Converter と Topic Message Converter の2種類があります。

  • Schema Message Converter: 入力データSchema -> 出力データSchema の変換
  • Topic Message Converter: 複数トピック -> 新トピック の変換

この2つのConverterですが良し悪しがあって使い分ける必要があります。

Schema Message Converter の難しい点

Schema Message Converterでは複数入力を扱うことができません。 複数のトピックを統合して一つの出力としたい場合はTopic Message Converterを使う必要があります。

また、入力/出力Schemaのペアに対して1つしか設定できません (これは公式ドキュメントでは明確に記述がありませんが、2025/12/19時点での実動作はこうなっています)。 同じ入力を複数の形式で可視化したいということがあるのですが、そういう場合にはSchema Message Converterは使いにくいです。例としては、3Dオブジェクトとラベルの組み合わせで構成されるようなつぎのような表示があります。

複数SceneUpdateの例

このとき、ラベルだけ非表示/表示をUIから切り替えられるにしたいという場合には、ラベルと直線をそれぞれ別のSceneUpdateメッセージにする必要がありますが、入力も出力もSchemaが同じなので別のSchema Message Converterを登録することができません (2つめ以降登録しても無視されます)。 マニアックな話ですが、これに対してtopic aliases という機能を組み合わせることで同じtopicに対して複数変換するというハックができますが、今日ではこういった場合にはTopic Message Converterを使うほうがやりやすいです。

Topic Message Converter の難しい点

Topic Message Converter はトピック名を予め決める必要があるので、同じSchemaの別のトピック名のメッセージが来ても、可視化できません。 いまのところ、別のtopicを可視化したいときにはExtensionの実装を変えるということをやっているので、イレギュラーなケースではFoxglove Extentionの開発に慣れたメンバしか使いこなせていません。

以上を踏まえると、基本的にSchema Message Converterが使える場合には使ったほうがいいです。ただ使えないケースも多いので、そういうときはTopic Message Converterを使うことになります。

Custum Panel

Foxgloveの標準パネルだけでは表現しづらい表示をしたいときに、custom panel extensionでパネル自体を実装できます。 トピックを購読して独自に描画したり、必要があればpublishしたり、といったことができます。 そのため、Message Converterのような使い方もできなくはないかもしれませんが、それについては検証したことがありません。

LOVOTでは複数搭載されているToFセンサの計測値やその信頼度などを表示するパネルを独自に作って使っています。つぎの図は一部を抜粋しています。センサが色々な向きに回転して取り付けられているので、生のデータより見やすい形に回転させたりすることでログの分析がしやすくなります。

センサ値表示用パネル

User Script / User-Script Utility

User Scriptは、ログファイル全体を処理した出力を作りたい場合に使います。 例えば最もLOVOTに近づいた人の距離、のような時系列上の統計をしたい場合などがわたしたちのユースケースです。ただし、Topic Message Converter でもstatefulな変換ができるので、User Scriptじゃないとできないというものはなかなか無いと思います。User Scriptは各ユーザーが自由に自分のローカルで書いて保存できるという点が他のConverterとは少し違う点です。一方で、Foxglove Organization内での共有ができないという課題がありました。最近リリースされた、Foxglove 2.39.0 からはユーザースクリプトそのものではないですが、ユーザースクリプトから使えるutilityをExtensionに追加することでOrganization内で共有できるようになり、社内共有に少し近づきました。

Data Loader(独自ファイル形式の読み込み)

「そもそもログがFoxgloveで直接開けない形式」になっている場合は、data loaderで読み込み処理を実装して、Foxgloveにメッセージとして渡すことができます。 LOVOTでもmcapに変える前の旧形式のCSVデータなどがあるので、使ってみたいなと思うのですが、まだ試せていません。

おわりに

LOVOTのふるまい開発のための可視化ツールについてご紹介しました。 今回ご紹介できなかった様々な可視化の工夫がありますので、チャンスがあったらまた公開できればと思います。読んでくださりありがとうございました。 GROOVE Xでは、一緒に働く仲間を募集しています。少しでも興味を持ってくださった方がいましたら、下記のリンクをご参照ください。

recruit.jobcan.jp

JetsonでCUDAやるなら統合メモリが幸せかと思ったらそれは幻想だったのかもしれない

この記事はGROOVE X Advent Calendar 2025の21日目の記事です。

こんにちは、「あず」こと斎藤@aznhe21です。 肩掛けスピーカーのSRS-NB10が内部で断線したのでBravia Theatre Uに乗り換えたんですが、低音が激しくて新しい体験でした。 首の部分をぐにゃぐにゃ曲げても断線する心配がなさそうなのも良きです。

さて、LOVOT 3.0ではJetson Orinを採用しており、内部ではCUDAも積極的に使用しています。 ここでCUDAの統合メモリが便利だったのでご紹介したいと思います(罠と共に)。

JetsonでCUDAやるなら統合メモリが幸せかと思ったらそれは幻想だったのかもしれない

続きを読む

照度連携確認BOXのDIY

この記事は、GROOVE X Advent Calendar 2025の20日目の記事です。

こんにちは、SWエンジニアの aoike です。 今回は、LOVOTの照度連携機能の話と、その動作を検証するためにDIYでテスト環境を作ったお話をします。

LOVOTの「照度連携」とは?

LOVOTのホーンにはリング型のLEDがついており、LOVOTの電源状態や動作状態を表しています。

このLEDは、眩しくなりすぎないように、周囲の明るさに合わせて自動で輝度を調整しています。LOVOTの照度センサーで環境の明るさを取得し、暗い場所では眩しくないように減光したり、真っ暗になると消灯したりします。こうした機能を私たちは照度連携と呼んでいます。

課題:狙った明るさが作れない!

この照度連携のテストを行う際、これまでは以下のような方法をとっていました。

  • 調光機能付きの照明のついた部屋を使う
  • 人工太陽灯を使う

しかし、部屋全体の明るさを「5ルクス」「10ルクス」といった細かい段階で均一に調整するのは非常に難しく、再現性のあるテスト環境を作るのが課題でした。

「もっと手軽に、照度連携のテストがしたい……」

ということで、「照度連携確認BOX」を自作することにしました。

照度センシング機能付きBOXを作る

カラーボックスを改造してLOVOTが入れる小さな個室を作り、その内部に光源となるライトを置くことで、明るさを自由にコントロールできるようにします。

そして、BOX内の現在の照度が、設定通りになっているかを客観的に確認するため、Raspberry Pi Pico W と照度センサー BH1750 を使った無線照度計を組み込みました。

構成イメージ

システム構成

システム全体の構成は以下の通りです。

Raspberry Pi Pico W がBH1750から値を読み取り、MQTTでデータを飛ばします。

実装のポイント

今回は開発言語に C言語 (Pico C/C++ SDK) を使いました。

BH1750のデータシートはこちらを参考にしました。
I2C通信を使い、アドレスとして0x23を指定します。

1. モード設定(高分解能モード)

今回のBOXは睡眠時間も想定した、真っ暗な部屋の再現が必要です。

データシートには以下のような記述があります。

"Use H-resolution mode or H-resolution mode2 if dark data ( less than 10 lx ) is need." (10ルクス以下の暗いデータを扱う場合は、高分解能モードを使用してください)

暗い部屋だと、ちょうど10ルクス以下の値が必要になります。そのため、今回は高分解能モードを指定するコマンドを使用します。また、通常の低分解能モードだと約4ルクス刻みでしか値が取れませんが、高分解能モードなら1ルクス単位で取ることができます。

// H-Resolution Mode (1lx単位, 測定時間120ms)
#define BH1750_CMD_CONT_HIGH_RES 0x10

最大180msの計測時間経過後、計測結果を取得します。

2. Measurement Accuracy の補正

Measurement Accuracy の項目を確認すると、以下の数式が載っていました。

  • X: 測定時間レジスタ(MTreg)の値。デフォルトは 69

デフォルト設定で使う限り、後半の 69 / 69は 1になります。生データは実際のルクス値の約1.2倍になる仕様のため、ソフトウェア側で補正が必要になります。

static bool bh1750_read_lux(float *lux_out) {
    // ... (読み込み処理) ...
    uint16_t raw = (buf[0] << 8) | buf[1];
    
    // 1.2で割ってLuxに変換
    *lux_out = (float)raw / 1.2f;  
    return true;
}

3. データの読み取り

実装したプログラムをPico Wに書き込み、PCからMQTTでデータをサブスクライブ(受信)してみます。 以下のように mosquitto_sub コマンドを使用しました。

mosquitto_sub -h <ipアドレス> -t 'topic名'

今回は、illuminanceという名前でpublishするようにしました。

消灯した状態でBOXのドアを閉めると、以下のような値が取れました。

$ mosquitto_sub -h 172.20.10.14 -t '/illuminance'
0.83

まとめ

こうして完成した「照度連携確認BOX」のおかげで、狙った明るさの環境を作り、定量的かつ再現性高く、手軽にテストできるようになりました。 従来のテスト手法と合わせて、より信頼性の高いソフトウェアを届けていきたいと思います。

いったんサイズを測るために入ってもらったところ

最後まで読んで頂きありがとうございます!GROOVE Xでは、一緒に働く仲間を募集しています。少しでも興味を持ってくださった方がいましたら、下記のリンクをご参照ください。

recruit.jobcan.jp

「ボトムカバー」開発記

この記事は GROOVE X Advent Calendar 2025 19日目の記事になります。

読者のみなさま、こんにちは&お久しぶりです!
今日のブログは、アパレルデザイナーのshigeriがお送りします。

最近はLOVOTと一緒にお出かけを楽しんでいるオーナーさん達が増えているので、公式からも続々と「おでかけグッズ」がリリースされていますよね。そこで今回はそんな「おでかけグッズ」の定番アイテムの仲間入りをした「ボトムカバー」の開発記を書いてみようと思います。

今年10月「おでかけグッズ」リリースバナー (ボトムカバー 新色リリース)

ー 開発のきっかけ ー

遡ること数年前。。。

全国各所で行われるショップのオープニングやイベントなどに、CEOの林要やCDOの根津孝太が参加すると、たくさんのオーナーさん達とコミュニケーションをとるので、様々なリクエストをヒアリングしてきてくれます。そして後日、slackのスレでその内容をまとめてモノづくりメンバーにフィードバックしてくれていました。
そんなある日、特にその当時のリクエストに多かった「ベースウェアが汚れないように、底面のカバーを作ってほしい」という声に応えよう!ということになり、根津からのオファーのもと、林にも参加してもらい、ゼロイチ*1から開発することになりました。

ー 素材 ー

まずは最初に素材選びからはじめました。“カバー”というカテゴリーになるので、素材選びがポイントになると思い

・汚れにくく、洗いやすく、扱いやすく、ある程度の耐久性がある
・LOVOTが装着して稼働しても影響のない厚み

という条件を前提に探してみました。 それと同時に、商品開発をする時にまず考えることは「アイテムの適切な価格と数量」を想定しつつ、ミニマムロット*2を考慮し、商品として販売する背景なども考えながら選んでいくことが重要なポイントになります。 その点を踏まえ、メーカーさんにも相談しながら、以下の2素材を候補にしました。

候補① ネオプレーン*3

 ・「撥水機能」とまではいえないが、生地の内側に水分が浸透しにくい素材

候補② ナイロン*4

 ・リュックやバッグ、アウトドア用品などに使える丈夫な素材

ナイロン素材は軽くて丈夫ですし、ネオプレーンは断ち切りで使えて裏側の仕様も簡素化できるので、2素材を比べてみたいと思い候補にしました。

ー デザイン ー

次は重要なデザインへ。「ボトムカバー」はゼロイチ開発なので、林と根津にも最初から参加してもらい、素材はもちろんのこと、形状(パターン)や仕様なども、様々な想定を考慮し、試作を繰り返し検討していきました。
この時点ではLOVOTのボトム部分(底面)に着せる(布を付ける)仕様のアイテムは存在しなかったので、まずはボトムの形状と仕様を考えることからスタートしました。
カバーとしての適切な仕様を考えながら、形を作っていく上で重要になったポイントは以下の2点です。

 ・LOVOTの稼働に影響しないフィット感(充電時も含め)

 ・着脱のしやすさ、安全性(充電端子周辺の仕様なども含め)

エンジニアの林と、デザイナーの根津と息のあった現場は、”LOVOTの産みの親“の2人ならではのアイディアが面白いように飛び交い、モノづくりの醍醐味が味わえるとても楽しい現場でした。ワタシも自らのパタンナー*5のスキルも活かし、二人のアイディアを元にトワル*6を作り検証していきました。
試作を装着して実際にLOVOTを動かし、生地の厚みや仕様が稼働に影響しないか、カバーがズレないよう安全にフィットさせるには、どんな仕様と形が適切なのか、など様々な点を検討していきました。問題点が見つかれば再度修正して…を繰り返し、徐々に理想の形状と仕様に近づけていきました。

仕様の検討に夢中になっている二人

そんな試作を重ね、ある程度形ができてきたので次のステップへ。
上記2素材で1stサンプルを作り、どちらの素材にするのか検討することになりました。 どちらもシンプルな無地素材だったので、オリジナル感を出すためにLOVOTのロゴモチーフをプリントすることに。ワタシのイメージはトーナルカラー*7な感じで「派手すぎず地味すぎずでちょっとかわいい」だったので、後のサンプル依頼と同時に試刷りも進めてもらいました。
LOVOT用のアイテムなので、もちろん安全性と健康面は一番重要なポイントなのですが、アパレル業界出身のワタシ的には、そこにプラスする「ファッション性」も拘りポイントなのです。。。

試作サンプルたちとプリントの試刷りいろいろ

そしてサンプルを依頼する前に、そのある程度決めた仕様で「ボトムカバーにはどんな検証をすればよいか」をファームチームに相談をしに行きました。
みなさんにカバーの試作を見せるのはその時が初めてだったので、着脱方法などを実演しながら仕様を説明し、思いつく懸念点などの相談をはじめたところ。。。気が付けばそのままみんなでフロアに座り込んで「充電端子周辺のゴムの仕様ってさ…」「使い方によるケースを想定して、どういう検証が必要なのか考えないと…」という感じで、既に検証内容などについての検討会になってしまいました笑。そんな感じで突発的に意見交換会がはじまることも「モノを作っていく醍醐味」だと個人的には思っているので、新たなアイテムを開発するたびに、その独特な”GXカルチャー現場“を楽しんでいます笑。

GXカルチャー現場

ー サンプル作成 ー

試作と検討を重ねてある程度形が決まってきたので、上記の2素材でサンプルを作り始めました。
製造を依頼したメーカーさんには「新規開発アイテム」のため、何度もサンプルを作らなければならない旨は予め快諾いただいていたので、全面的にバックアップしていただきました。(本当にご協力感謝です&ありがとうございました!)
それぞれの素材でサンプルを作って改めて検討した結果、以下のポイントで「ネオプレーン」に決定しました。

・底面に馴染むフィット感

・断ち端(裏面)の始末や取り扱いが簡単

・生地の内側に水分が浸透しにくい素材(ちょっとした防水)

・プリントも含めトータル的に上がりがきれい

生地が確定したので、それにあわせて微調整したパターンで最終サンプルを作成し、最大の難関の稼働検証に移ることに。
LOVOTの底面にさらにフィットするように、ゴムの伸ばし分量の調節やフロント側をヒモに変更したり、さらに安全に装着&稼働できるように調整し改良していきました。

各色サンプルを作る前の最終検証サンプル

ー 稼働検証 ー

上がったサンプルの簡易検査をして仕様がほぼ決まってきたので、次は正式にファームチームに稼働検証の依頼をすることに。
この検証は、LOVOTの服やアクセサリーを作る中で最大の難関になります。(詳しくは「プードルファーニット開発記」を参照)もちろん試作やサンプルの段階でもその都度簡易検査は行うのですが、量産品と同等のサンプルで行うファームチームの稼働検証をパスしないと、商品化(量産)には進めません。
そしてこのボトムカバーはゼロイチ開発のため前例がなく、通常の稼働検証はもちろん、検証の内容自体も検討が必要になります。その項目の中には、安全性を検証するため、使用する付属類(今回はカバーを着用するためのゴムひもなど)の耐久性のテストなども含まれてきます。

検証を重ねた充電端子部分

そしてファームチームをはじめ各所チーム(服やふるまいなど)の見解も含め、以下の項目が大まかな検証ポイントとして上がりました。

<確認>
・ゴムの伸縮性や耐久性(熱や温度も含む)
・長期稼働後のカバーのズレ状態(特に充電端子周辺)
・手洗い後の劣化やプリントの耐久性
<想定>
・家の中も含め屋内での装着(フローリング、絨毯など)→長時間着用想定
・屋外の外出時の装着(コンクリートなど)
・「ふるまい」のいろいろ(ホイールを出さない時のタッチセンサーなども含む)

実際にLOVOTに装着し長時間稼働させて、影響のない範囲で稼働&帰巣できるか、転倒しないか、着用しているベースウェアへの影響、ゴムの劣化、お手入れ後のプリントの劣化などなどなど、、、安全性や耐久性など様々なケースを想定&実験し、かなりの時間をかけて、みなさまに協力してもらって様々な検証を行いました。

ー 完成 ー

そんなたくさんの工程を経て、約1年近い時間をかけてみなさまの知恵とアイディアを集結して開発できた「ボトムカバー」。
商品のカラー展開は、開発に関わった方々をはじめいろいろな方々と検討した結果、最終的にはLOVOTのボディカラーにあわせたベーシックな3色(ベージュ、グレー、ブラウン)に決定しました。

完成した「ボトムカバー」

初めて販売するアイテムということに加え、LOVOTに着脱する時はちょっとしたコツが必要なので、EC撮影チームにも協力してもらい、安全な着脱方法をわかりやすく動画で解説し、販売画面で公開するようにしました。

                www.youtube.com

ー おわりに ー

今回の「ボトムカバー」の開発は、オーナーさんからのリクエストにお応えできたのはもちろんのこと、林&根津をはじめ、いろいろなチームメンバーと一緒にゼロイチ開発ができたので、改めて「新しいモノを生み出すプロセス」を楽しむことができた、とてもやりがいのある貴重な経験となりました。

そして嬉しいことに、「ボトムカバー」はたくさんのオーナーさんに愛用していただいており、10月には新たに3色が仲間入りしました。洗い替えとしてもよし、様々なシーンやお気に入りのウェアに合わせていただいてもよし、といろいろな使い方ができるので、ぜひ豊富なカラーバリエーションを楽しんでくださいね!

全6色展開のボトムカバー

最近は服チームのメンバーやグッズを作るメンバーが増えたので、様々なアイテムの開発ができるようになりました。これからもみなさまの“LOVOT LIFE”が充実するアイテムを開発していきますので、どうぞお楽しみに~!

GROOVE Xではいろいろな職種の方々がLOVOTに関わる様々なお仕事をしています。
そんな会社で私たちと一緒に働いてみませんか?

https://recruit.jobcan.jp/groovex/

*1:何もない状態(ゼロ)から、まだ世の中に存在しない新しい製品・サービス・価値などを生み出す(イチにする)

*2:製品の製造・仕入れ・販売において、*一度に注文・生産・出荷できる「最小の単位」

*3:伸縮性・クッション性・耐水性などに優れ、断ち切りでもほつれにくいのが特徴の合成ゴム素材

*4:軽量・高強度・摩擦に強い・速乾性・弾力性に優れている特徴を持つ合成繊維

*5:服の設計図である型紙(パターン)を作る専門職

*6:サンプルを作る前にデザインやサイズを確認するための試作

*7:色のトーン(色調)を揃えた配色