【2025年】作ったもの振り返り
今年作ったり買ったりしたもの(買ったけど積んであるもの)を振り返ってみます。 (以下の記事からの続きなのでぎりぎり2024年末のものも入っています)
ジャイロコンパス
2024年の大晦日は自作のマルチIMU基板でジャイロコンパスを作ってました。
(大晦日に他にすることもなかったのかという話ですが、修論に追われている時期であんまり外に出る気もなかったので基本部屋に引きこもっていました)
もともと1万円程度でマルチIMU基板を自作していたものの「そういえばジャイロコンパスやったことないな」と思ってやってみたところ、本当に地球の自転の角速度が計測できてしまい、そこから方位を算出することができました。
理屈自体は高専生だった頃から分かっていたし他人に説明するのも簡単ですが、本当に実現できるんだと感動していました。
自作マルチIMUボードのジャイロと加速度から地球の自転を読んで方位を計算するジャイロコンパス出来たった pic.twitter.com/zZaEL4VsIw
— こたっく (@Kotakku_07) 2024年12月31日
IMUの積分で位置を出してみる
そこまで真面目にやったわけではないですが気になったので自作マルチIMU基板で加速度を2回積分して位置を出してみました。 激しく動かさなければ10秒程度まで発散せずに耐えてました。
最近SPRESENSEの公式exampleに位置を計算するサンプルが追加されたらしいのでいつか比較してみたいです。
単純な2回積分でも上手くいくと4,5秒は持ちそう pic.twitter.com/gAL1pjnbxb
— こたっく (@Kotakku_07) 2025年4月8日
XROBOCON 倒立振子ロボット
今年の個人的な一番の話題なんですが、大阪万博で行われたXROBOCONという大会に参加してきました。この大会のルールは20cm、30cm、40cmの段差を登りフィールド上に存在するコインをより多く取ったチームの勝ちというものでした。もともと大会の存在は知っていましたが自分は最初は参加するつもりはありませんでした。
そんな中、大学ロボコンサークルの時の同期から「ただ登るだけでは面白くない、ジャンプして登るロボットを作ろう」という話を社会人になったばかりの自分に持ちかけられ、まんまと(ノリノリで)誘いに乗って参加したのが本大会でした。

すーぱーあらっとはうすチームの倒立振子ロボットのROS 2周りとマイコン周りの開発を担当してました。自分の今までのロボコンとは全く異なった体勢の中で開発はかなり貴重な経験になりました。
— こたっく (@Kotakku_07) 2025年8月27日
練習でできていた40cmの段差をジャンプで登る動作を本番でも見せたかった…#XROBOCON pic.twitter.com/uHudqjKOi7
エキシビションで20cmの段差を登った時の配信スクショ pic.twitter.com/CUMoqlu9cT
— こたっく (@Kotakku_07) 2025年8月27日
結果は振るわなかったですが、練習ではしっかり40cmの段差もきれいにジャンプで登ることができていたので個人的には満足でした。 初めてジャンプが成功したときはメンバー全員ドーパミンがドバドバだったと思います。
Ethernet CAN変換基板修正
ずっとやるやる詐欺していたEthernet CAN変換基板の修正をXROBOCONに合わせて発注しました。 この基板もXROBOCONの開発中に使われました。
そういえば修正した基板が届きました pic.twitter.com/TyLS1aQU7C
— こたっく (@Kotakku_07) 2025年5月20日
CasADiでFATROPを使ってみた
自作のMPCライブラリでFATROPを使えるようにしました。 IPOPTからソルバーを切り替えるだけで4〜5倍も高速になることもあり、最近はもうデフォルトでFATROPを使用するようになりました。
こちらももちろんXROBOCONで大活躍しました。これがなければ実時間でMPCを回すのは無理だったでしょうね。
記事を投稿しました! CasADiでFATROPを使用してモデル予測制御を行う [IPOPT] on #Qiita https://t.co/if4C15oHlh
— こたっく (@Kotakku_07) 2025年3月7日
IPOPTと比較して結構速くなりました https://t.co/tfXPT8KhG6 pic.twitter.com/XUWUD023TB
— こたっく (@Kotakku_07) 2025年3月7日
CasADiのMPCライブラリ JIT/AOTコンパイル実装
FATROPを使えるようにしてかなりパフォーマンスが改善しましたが、そもそもCasADiのシンボリック変数の評価のオーバーヘッドが大きかったため、JITコンパイルを実装したところさらに3倍以上の高速化ができました。
久しぶりにCasADiに戻ってきてJITコンパイルに対応したら計算時間で割とacadosと戦えそうなレベルまで速くなってきた pic.twitter.com/hvlrLcyDbw
— こたっく (@Kotakku_07) 2025年9月25日
JITコンパイルはコンパイル結果がキャッシュされるように設定しているので2回目以降はほぼノータイムで起動できますが、規模によっては1回目のコンパイル時間が馬鹿になりません。
なのでAOTコンパイルにも対応しました。これはJITコンパイルに相当するコンパイルをプロジェクト全体のコンパイル時にcmakeマクロでフックして同時にビルドしてしまいます。 追加のcppファイルとCMakeLists.txtの修正が必要になりますが、実行時のコンパイルなしに高パフォーマンスを得ることができます。
STM32N6 Lチカ
これはArm Heliumを使ってみたくてNucleoボードを買ってみたけどLチカで力尽きたままです...。Arm Heliumの面白さのみに惹かれて購入したものの適用するアプリケーションが思いつかず...。自分の知り合いで試食してみたい人いたら貸出可能です。
STM32N6でLチカできた
— こたっく (@Kotakku_07) 2025年2月12日
まだTrustZoneなにそれおいしいの状態
ARM Cortex-M55のHelium使ってみたさから買っちゃったけどコンパイラの問題があるとかないとかいうツイート見かけた🤔 https://t.co/s5hugqSgBZ pic.twitter.com/MoisKqxwEe
robstride 05 倒立振子
XROBOCONでRobStrideモーターを使って割と使いやすかったので一番小さい05を買って倒立振子を作ってみました。 高専時代に似たようなものを作って立たせられなかったのでリベンジ成功です。
立った! https://t.co/kOJRaoB4tT pic.twitter.com/frn8cnPes0
— こたっく (@Kotakku_07) 2025年9月23日
ros2-for-unity jazzy&android対応
2023年にhumble版をandroid対応したのですがそろそろjazzy移行しそうなのでこちらも合わせて対応しました。 そもそもros2-for-unityのjazzy対応がまだだったのでUbuntu用のjazzy対応もしています。
ポストの画像に写っていますがOdin2というハンドヘルド機を新しく購入しました。 これで将来ロボットを作ったとき用のコントローラも確保できました。
勝ったな(確信)
— こたっく (@Kotakku_07) 2025年11月12日
風呂入ってくる pic.twitter.com/9aS0EdraMS
最適経路のパフォーマンス改善
ほぼNHKロボコン専用ですが最適経路のソルバーをちまちま改善してました。 最近は大体の経路が40ms〜1sぐらいで引けるようになってきて、最適化の成功率も9割超えてきた気がします。 経路の複雑さに比例して最適化にかかる時間が伸びるとは限らないようでココらへんは深追いしていきたいところでもあります(obstacleの数かな?)
去年はまだ10秒ぐらい掛かったり成功率も6〜7割ぐらいだったのを考えるとだいぶ改善してきました。 最近は調子に乗って各年のロボコンの経路を引いて遊んでます。
もう参加することもない(と思っている)ロボコンでの運用を考えるとやはり理想的には安定して100ms以下ぐらいで解けるようにしたいです。 MPCと違って問題構造や運用面を考えるとJIT/AOTコンパイルがなかなかしづらい気がしていてまだできていないので、次に高速化するとしたらここですかね〜。
このロボットで何人がロボコン沼に沈んでいったんだろ pic.twitter.com/TLgsCadfjF
— こたっく (@Kotakku_07) 2025年12月12日
10秒かからずにこの経路が出せるようになったのでもう満足です pic.twitter.com/hYo9kUBAtD
— こたっく (@Kotakku_07) 2025年12月11日
こっちは安定して100msぐらいで計算できるようになった。
— こたっく (@Kotakku_07) 2025年11月30日
こっちはフェンス貫通することないけどなにが違うんだろ https://t.co/qMtyYlVFIg pic.twitter.com/Co52gpiZqS
久しぶりに最適経路改良してた
— こたっく (@Kotakku_07) 2025年11月29日
最悪計算時間は割と短くできて計算の成功率もだいぶ高くなったけどこの競技の経路が安定しなくて鬼門すぎる... pic.twitter.com/KIwaBDwwhA
simple_casadi_mpcのpinocchio対応(WIP)
もともとsimple_casadi_mpcのissueに寄せられていたもので(当時対応できなくて申し訳ない)今になって自分も欲しくなって来たので現在実装途中です。
urdfを用意すればpinocchioが勝手に状態方程式を導出してくれるので、より簡単にMPCを定式化することができるようになりました。 まだ実験的な実装でmainにマージされるまでには時間がかかりそうです。
simple_casadi_mpcとpinnochioを繋げることに成功したので運動方程式を手で導出しなくてもurdf読み込ませるだけでMPCが動くようになってテンション爆上げ
— こたっく (@Kotakku_07) 2025年12月27日
最適化の計算時間も止まってる間は0.5msで振り上げ時に最大2msぐらいだから500Hzぐらいなら回せそう pic.twitter.com/iWUjHkT01a
To Be Continued?
基本的にここに上げた個人開発は「ロボットを作りたい」というモチベーションから来ていて、現在はそこに繋がりそうな技術を集めている段階です。 来年、再来年のうちに何か一つ実機が完成することを目標に引き続き頑張っていきたいです。
ロボコンを引退してから趣味で作ったものを振り返ってみる
久しぶりにはてなブログに記事を書きます。こたっくです。 自分は元々ロボコンに関係なく趣味でいろいろ作ったりしているのですが、学生生活最後の年末のこの機会に自分が作ってきたもの(と少しだけ遊んだもの)を振り返ってみようと思います。 振り返る期間はABUロボコン2022の大会後からとし、基本的にTwitter(現:X)での自分の呟きをもとに振り返っていきます。
2022年
jsk-visualizationのROS 2移植版の公開
ROS1を使っていた人ならほとんどの人が一度は目にしたであろうjsk-visualizationは、rvizでいろんなトピックを可視化するのにとても便利です。 しかしROS 2には移植されていなかったので自分で移植しました。 元々一人でコツコツ移植してて、ABUロボコン期間中も活用していたのですが、ロボコンを引退したタイミングで公開しました。
需要もあってかこのリポジトリが一番リアクションが多かった気がします。 実は作り始めたのは高専5年生のときで、robosemiで途中経過を発表していたりします。
jsk_visualizationの自分がROS2に移植した部分を以下に公開しました。実装状況はREADME_ROS2.mdにまとめてありますがまだrviz_pluginの移植途中です。https://t.co/lIWNer9i23
— こたっく (@Kotakku_07) August 27, 2022
お待ちかね(主に自分が)OverlayPickerツールの移植が出来てマウスでグリグリできるようになったよ https://t.co/88rOPJyZd2 pic.twitter.com/6G37Mb8O6m
— こたっく (@Kotakku_07) September 9, 2022
cpp-roboticsの公開
ロボコン中に書いたコードや趣味で勉強した制御工学に関するコードをまとめたライブラリです。 思いついたときに更新しているだけなのでかなり散らかってます。 実はABUロボコンのプログラムにも一部流用していたりします。
線形MPCの実装
Eigenのみ縛りで線形モデル予測制御を実装しました。 ロボコンではcasadiを用いてMPCを実装していたのですが、自分で実装してみることでかなり理解が深まりました。
外部ライブラリはEigenだけ縛りでMPC実装できた
— こたっく (@Kotakku_07) October 11, 2022
ちゃんと入力制約扱えてる pic.twitter.com/YGvidMtX5d
前のやつはレギュレータだったけどちゃんと目標追従できるようになった https://t.co/mY4g2Osano pic.twitter.com/TiVrHn8UOs
— こたっく (@Kotakku_07) October 20, 2022
SBDBTのSTM32版
SBDBTの完全ピンコンパチなSTM32基板を作りました。 DualShock4とも簡単に繋がってくれます。 ネタ基板として思いつきで作ったわりにはかなり実用的でした。
LEDのチップ抵抗の値ミス以外は大丈夫そう
— こたっく (@Kotakku_07) November 19, 2022
実装ミスとかもなかった pic.twitter.com/nRF0sq4k1x
STM32でファミコンエミュレータを作った
APUは実装してないです。 12FPSしか出ませんでした(悲しい)
なにこれ https://t.co/PdktIvyxIY pic.twitter.com/lytvvgDCxi
— こたっく (@Kotakku_07) November 30, 2022
2023年
webotsに触れる
ちょっとだけwebotsを触りました。普段使いするようにはならなかったです。 シミュレータってどれが良いんですかね?
オムニかわいい pic.twitter.com/NqBb55D85B
— こたっく (@Kotakku_07) January 27, 2023
n回見た機構 pic.twitter.com/L8RAKQv4JB
— こたっく (@Kotakku_07) January 29, 2023
ros2-for-unityのAndroid移植
ロボコン現役の時にスマホコントローラを導入し、ロボットに搭載しているPC(ROS2)との通信はROS TCP Connector/Endpointを使っていましたが、すぐに通信が重くなってしまいいろいろとチューニングが必要でした。独自のTCP/IPパケットに変換するオーバーヘッドが効いてそうなのでUnityから直接DDSをしゃべらせたくなります。 ROS2とUnityを連携させるためにはもう一つros2-for-unityを使うという手段があり、これはUnityが直接DDSをしゃべってくれます。 しかしWindows/Ubuntuのみのサポートだったため、Androidようにビルドができるようにビルドスクリプトを書き、Android端末でも動作するようにしました。 これでUnityの豊富なUI作成用のコンポーネントを活用しつつROS2と快適な通信ができるようになりました。
ros2-for-unityがAndroidタブレットで動いたので勝ち✌️
— こたっく (@Kotakku_07) March 14, 2023
WindowsとかUbuntuでros2-for-unityを使う時と全く同じコードでPublisher/Subscriptionが動きました https://t.co/zRw52sZWf0 pic.twitter.com/gsArLvdlWn
Unityでスマホのセンサ読んでrvizで表示させてみるやつ pic.twitter.com/BESwvlDANc
— こたっく (@Kotakku_07) July 21, 2023
VRFTを実装
PIDゲインのデータドリブンなチューニング方法として知られるVRFTを実装してみました。 シミュレータでしか確認してないですが一発でゲインが求まるのは気持ちいいです。 いつか実機で確認してみたいですね。
VRFTの実装ヨシ!
— こたっく (@Kotakku_07) July 3, 2023
適当なステップ応答実験でPIDゲイン出してくれるの面白い https://t.co/qHaTihjcjb pic.twitter.com/T1NcH8rIg5
simple_casadi_mpc
このころはcasadiで遊ぶのにハマっていてcasadiでモデル予測制御をするためのライブラリを作りました。 ロボコン現役の時はここまできれいにコードがまとまらなかったのでかなり満足しています。 exampleもいくつか用意したのでよかったら動かしてみてください。
動画に起こすと楽しい https://t.co/TZyjn6aXFj pic.twitter.com/7kKxPUZjyQ
— こたっく (@Kotakku_07) September 5, 2023
ボックス制約のみ書けるように絞ってsimple_casadi_mpcとか名前つけたのに結局任意の制約を追加できるように変更するなどhttps://t.co/oogvDDYIG8 pic.twitter.com/m3EMGuD9ME
— こたっく (@Kotakku_07) October 22, 2023
小型BLDC基板(設計だけ)
まるた先生のツイートに触発されて設計だけしました。
こんなもんで良いか pic.twitter.com/4FD4jTLu8V
— こたっく (@Kotakku_07) 2023年10月9日
ぜんぜんわからない 俺たちは雰囲気で基板設計をやっている
— まるた (@marurur) July 28, 2023
(製造はJLCPCB、すごく細かい部品を両面につけてくれてすごい。) pic.twitter.com/gr6sSiwZfq
SimpleFOCを真面目にチューニングすることで、倒立振子を完全に止めるという素人には全くウケない一発芸ができるようになりました pic.twitter.com/8etclek88z
— まるた (@marurur) October 23, 2023
最近はODrive microという基板が発売されたのでいつか買ってみたいなと思っています。
SwitchにUbuntu入れて遊んだ
良い子はマネしないでね。
micro-ROSのC++ラッパ
ArduinoやSTM32マイコンなどの組み込み環境で動作するmicro-ROSはrclcで書く必要がありなかなか面倒だったため、rclcppライクにかけるようにしたヘッダオンリーのライブラリです。 今見返すと何やってるかさっぱり覚えてないですが、マクロの黒魔術が展開されていました。 (今でも動くかな?)
FeetechシリアルサーボのユーティリティソフトのUbuntu移植
Feetechのシリアルサーボは比較的入手性も性能もよくホビー用として遊ぶにはかなり使えると思います。 動作確認、パラメータチューニング、データロギングなどに使うユーティリティソフトが公式から配布されているのですがUbuntu上では動きません。 自分は普段使いがUbuntuで、このためだけにWindowsに切り替えるのも面倒なので、Ubuntu版を作りました。 本家のソフトと見比べながらできるだけ同じような見た目になるように調整するのはなかなか楽しかったです。 ビルド済みイメージも配布しているので使ってみたい方は下のGithubリンクのReleaseからダウンロードしてってください。

micro_behaviortree_cpp
ロボコンでは自動制御の意思決定の部分をBehaviorTree.CPPというライブラリで行っていました。 小規模な自動制御を行うにはとても便利なライブラリなのでマイコン上で動いたら高専ロボコンなどでも使えるんじゃないかと思って依存関係を極限までなくして作りました。 STM32F4上で動作することを確認しています。 基本的な使い方は本家BehaviorTree.CPPとほとんど同じです。 ぜひ興味があれば使ってみてください。
2024年
AL-iLQR
高速な軌道最適化手法のALTROに用いられるAL-iLQRを実装してみました。 分かりやすい動画などは無いのですが倒立振子を立たせる軌道を計算するのに自分のノートPCで14msぐらいでした。
デバッグ用に-O0にしてた(アホ)
— こたっく (@Kotakku_07) January 3, 2024
-O3で14msぐらい。悪くないのでは? https://t.co/khMs4Rfxgw pic.twitter.com/H2pcSFlOWq
FMT*とDWAでナビゲーション
FMT*という経路計画法を実装したついでにDWAで追従までシミュレーションさせてみた動画です。 なかなか簡単かつ強力な方法ではないでしょうか。
マージン持たせたら安心して見れるようになった https://t.co/QPKsfzIcUB pic.twitter.com/wUYU6wDUd3
— こたっく (@Kotakku_07) January 22, 2024
OSQPに使われているADMMベースのQPソルバの実装
二次計画法ソルバーとして知られるOSQPはADMMベースの手法でかなり性能が良いとされています。 もとの論文を読んでみると分かりますがかなり分かりやすく細かなところまで解説をされており、自分でも実装できそうと思ったので実装してみました。 cpp-roboticsで元々内点法ベースの別のQPソルバーは実装していたのですが、性能ではADMMベースの方法が圧勝でした。
ロボコン用軌道生成ライブラリ
ABUロボコン中に使用していた軌道生成プログラムがかなり遅く、かつ成功率がそこそこ低かったので別の手法で実用的なものが作れないかと作ったものです。 4〜10秒くらいで解けるようにはなりましたが理想的には0.1秒ぐらいで解いてほしいです(だれか作って)
いろんな経路作ってみる pic.twitter.com/7yeN91n4XH
— こたっく (@Kotakku_07) July 18, 2024
CADの勉強
Fusionで見たことあるロボットっぽい形状を作ってurdfを作って遊んでました。 まだ表示しただけ
最近研究全然進まないのでここ3日ぐらい現実逃避でFusion入門してた pic.twitter.com/rprXVjjHvY
— こたっく (@Kotakku_07) August 2, 2024
fusion2urdfでちゃんと変換できた pic.twitter.com/niqM61pUW3
— こたっく (@Kotakku_07) August 14, 2024
マルチIMU基板
こちらもかなりリアクションを貰ったものです。 元々はSONYがSPRESENSE用の基板として作成しMaker Faireなどのイベントで展示していたものですが、発売が待てず自分で作ってみたものになります。 本家は1基板に16個のIMUが載っていますが自作基板は欲張って32個載せています。 アラン分散を計測してもかなり本家に近いデータが取れていて感動しました。 (これで何か作りたいけどまだ思いついてないです) 本家が発売されたらどの程度再現できているのか比較実験もしたいですね。
ガーバーデータとファームウェアを公開しているので作ってみたい方はJLCPCBで発注して動かしてみてください。
例のIMU基板Ver.2来たわね😎
— こたっく (@Kotakku_07) July 23, 2024
今度はSTM32積んでおります pic.twitter.com/5IOcOaJOx4
干渉抑制フィルタ入れてないけど性能評価してみたらすでに論文の結果(バイアス安定性の0.5deg/h)に結構近い値が出てる
— こたっく (@Kotakku_07) July 24, 2024
0.53deg/hぐらい pic.twitter.com/X6kPsL6gKY
EthernetCAN変換基板
ロボコンでROS(というかPC)を使うようになると「もう少しマイコンとPC簡単につながらないかな~」とよく考えるようになります。 通信レイヤーの開発とデバッグで時間を取られるのは無駄でしかなく、作りやすくて使いやすいやつ欲しいな~ってことでEthernetCAN変換基板を作ってみました。 1回作ってみて配線ミスと仕様変更したい箇所ができたので設計の修正まではしたんですが、お金の事情により発注の段階で止まっています。
今日の夜はオンライン聴講しながらこれやります pic.twitter.com/bwzKDdkSWU
— こたっく (@Kotakku_07) May 21, 2024
修正とSPI追加done
— こたっく (@Kotakku_07) August 12, 2024
まだ通しただけなので配線汚い pic.twitter.com/xyRdGJNTAi
FPGA入門
Ariexpressで安いZynqボードを買って入門してみました。 VerilogでLチカして、PSからHello Worldして、HLSでモジュールを作ったところで自作のHLSのモジュールを入れるとプログラムが走らなくってしまい、デバッグ中に挫折して一旦止まっています。 あとで再チャレンジします。 (FPGAもっと安くならないですか)
React入門
今までwebで使われている技術にほとんど触れてこなかったのでNode.jsやらReactやらに触れてみています。 コードで思った通りのUI作るの難しすぎませんか...?
今後作ってみたいものとか
振り返ってみるとかなりソフトウェア寄りでしたね。社会人になったらハードウェアにも挑戦していきたいです。 いつかはロボットを一人で作ってみたいですね。
今の目標はDisney Researchの二足歩行ロボットです。 (ギリギリ部屋に置けそう)
連続な関数の最適化手法を紹介したい
この記事は TUT Advent Calender 2022 の7日目の記事です。
はじめに
はじめまして、豊橋技科大1系B4のこたっくです。ついこの前まで豊橋技科大のロボコンサークルであるとよはし☆ロボコンズの制御班に所属し、NHK学生ロボコン2022・ABU Robocon 2022に参加していました。
またロボコンが終わってからはOUXTのメンバーとして船の速度制御系の開発を担当しています。OUXTはMaritime Robotx Challengeという完全自動運転な船を作って様々なタスクにチャレンジするロボコンに参加する団体で日本各地から学生・社会人いろんな人が集まって活動しています。
OUXTではROSを活用してロボットを動かしますがなんとコードは全て公開されています。「なんとなくROSは知ってるけど実際にコード書こうと思ったら分からない」「パッケージの設計どうしたらいいか分からない」みたいに思ったらOUXTのリポジトリを覗いてみると解決するかもしれません。自分も学生ロボコン中にめちゃくちゃ参考にさせていただきました。
豊橋の大学のアドベントカレンダーなので豊橋のことも軽く触れておきましょう。皆さん中華料理屋「美楽」はご存知でしょうか? とよはし☆ロボコンズでは美楽の唐揚げ定食を食べきれると良いロボットが作れるとされています。詳しくは以下の記事で詳しく解説されています。ロボコンやってる人もやってない人も豊橋に来た際にはぜひ食べてみてください。
shouyuzukenotako.hatenablog.com
本題
最近はロボコンを言い訳に後回しにして遅れに遅れていた研究を巻き返すためにひーひー言ってる毎日です。無事に卒業できるといいですね(白目)
タスクに追われてぎりぎりで生きてると次こそは効率的にやろうとか思うんですけどなかなか上手くいかないもんですね。特に試行錯誤でいい感じにするタスクは時間を使うばかりで進捗効率は悪いことが多いです。
ということでやはりそういうタスクは最適化問題に落とし込んで効率的に行うべきです。
ということで今回は制約付き非線形最適化法である逐次二次最適化(SQP法)について紹介しようと思います。
二次計画法(QP法)
逐次二次最適化に触れる前にいくつかの前提となる手法について紹介します。 まずは二次計画法です。二次計画法とは以下の二次形式で表される問題を最適化する手法を指します。
制約がなければ最急降下法やニュートン法で解くことが出来ます。最急降下法やニュートン法は高専や技科大の授業でやった人も多いのではないでしょうか。
制約が在る最適化問題ではKKT条件というものを満たすような解を探します。
まずはスラック変数を導入して不等式制約を等式制約に置き換えます。
この式に問題におけるKKT条件は
ここで各変数を微少量だけ変化させた場合を考えます
上式をKKT条件に代入して微小変化量についてまとめると以下のようになります。
ここで
です。
この連立方程式を解いて各変数の更新量を求めて更新する作業を収束するまで繰り返すことで解を求めることが出来ます。
なにやら複雑な式に見えますが制約の数が0の時を考えると左辺は係数行列の左上のだけ残り右辺は一番上の成分の
が残る形になり、ニュートン法と一致することが分ります。ここでは制約を考慮しながら解くニュートン法ぐらいに捉えてもらって大丈夫です。
BFGS法
次にBFGS法について紹介します。
BFGS法とは準ニュートン法等で使用される目的関数のヘッシアンを近似する行列を求める手法です。 連続関数の最適化問題が収束するためには目的関数のヘッシアンが半正定値である必要がありますが、任意の非線形な目的関数のヘッシアンが半正定値である保証はないのでヘッシアンを半正定値の行列で近似してやります。
以下の更新式を使ってイテレーションごとに近似ヘッシアンを更新します
近似ヘッシアンの初期値としては単位行列などが使われます。
また実際にはSQP法ではを満たすとは限らないためパウエルの修正BFGS公式が使われます。
逐次二次最適化(SQP法)
ようやくですが本題の逐次二次最適化について紹介します。 逐次二次最適化とは以下のような形式の問題を最適化する手法の一つです。 目的関数や制約関数が非線形の問題に対して使用することが出来ます。
「逐次」で「二次最適化」な名前から分かるようにこの最適化手法は任意の最適化問題を最適化変数周りで二次近似して問題を解き最適化変数を更新する手順を解が収束するまで繰り返し行います。
SQP法の手順はおおまかに以下になります。
- 最適化変数
、近似ヘッシアン
の初期値を決定する
- 現在の最適化変数
周りで目的関数と制約関数のヤコビアン、制約関数を評価する。
- サブ問題であるQP問題を解き探索方向を決定する。
- メリット関数の直線探索でステップ幅を計算する
を更新する
- メリット関数の制約重みを更新する
- BFGS法で
を更新する
- 収束していなければ2.に戻る
ここで一番大事なのは3. のサブ問題を解いて探索方向を決定することです。 二次形式に近似して二次計画法で解くことを考えるとサブ問題であるQPは以下のように書くことが出来ます。
この問題を解くと探索方向が求まるのでステップ幅を直線探索で求めて
を更新します。
この作業を収束するまで繰り返します。
ここではサブ問題をニュートン法ベースの二次計画法で解く方法を紹介しましたが、修正コレスキー分解と最小二乗法によって解くものをSLSQP(Sequential Least SQuares Programming)と言います。 SLSQPは論文とFORTRANのルーチンが公開された後、PythonのScipyやCのnloptにも移植されています。
気になる方は以下のタイトルで論文を調べてみてください
Kraft, D. A software package for sequential quadratic programming. 1988. Tech. Rep. DFVLR-FB 88-28, DLR German Aerospace Center -- Institute for Flight Mechanics, Koln, Germany.
例題
実際にSQP法を使ってみましょう。
以下の個人開発しているライブラリの中にSQP法を実装してあります。 github.com
cpp_roboticsは自分が実装したいものを実装する趣味用のC++ライブラリです。
問題設定
以下の問題を最適化してみましょう。
目的関数はグラフ化してみるとこんな感じの関数です。

図は下記より引用
制約なしの時の最適解はです。
制約の1つ目は解が原点から半径1の円の中に収まっていること、2つ目が2つある最適解のうち正の方に収束することを制約にしています。
コード
#define CR_USE_MATPLOTLIB #include <iostream> #include <cpp_robotics/optimize/optimize.hpp> #include "cpp_robotics/third_party/matplotlib-cpp/matplotlibcpp.h" int main() { using namespace cpp_robotics; SQP solver; SQP::Problem prob; //////////////////// 問題設定 //////////////////// // 目的関数 prob.func = [](Eigen::VectorXd x) -> double { return 100*( std::pow( (x(1) - std::pow(x(0),2)), 2) ) + std::pow(1 - x(1), 2); }; // 制約1 prob.con.push_back({ Constraint::Ineq, [](Eigen::VectorXd x) { // |x| <= 1 return (x(0)*x(0) + x(1)*x(1)) - 1; }, }); // 制約2 prob.con.push_back({ Constraint::Ineq, [](Eigen::VectorXd x) { // x1 >= 0 return -x(0); }, }); // 解の初期値 Eigen::VectorXd x0(2); x0 << 0, 0; //////////////////// 解く //////////////////// // 反復によって生成される点列の可視化用 std::vector<double> x1_, x2_; // 解く auto result = solver.solve(prob, x0, [&](auto x){ x1_.push_back(x(0)); x2_.push_back(x(1)); }); //////////////////// 結果表示 //////////////////// std::cout << "iter: " << result.iter_cnt << std::endl; std::cout << "x1 = " << result.x(0) << std::endl; std::cout << "x2 = " << result.x(1) << std::endl; std::cout << "x norm: " << result.x.norm() << std::endl; // 点列のグラフ化 namespace plt = matplotlibcpp; plt::plot(x1_, x2_, "o--"); // 補助線 plt::plot({1,-1}, {1,1}, "xk"); // 最適解 std::vector<double> edge_x(100), edge_y(100); for(size_t i = 0; i < 100; i++) // 制約によるxの取る範囲の境界 { double theta = i/99.0 * 2 * 3.141592; edge_x[i] = std::max(0.0, std::cos(theta)); edge_y[i] = std::sin(theta); } plt::plot(edge_x, edge_y, "--"); plt::xlim(-1.1, 1.1); plt::ylim(-1.1, 1.1); plt::set_aspect(1.0); plt::show(); }
実行結果
実行するとこんな感じで解とグラフが表示されます。グラフは反復による解の収束を見ることが出来ます。
ターミナルの表示
iter: 19 x1 = 0.785066 x2 = 0.618036 x norm: 0.999149

青が反復によって生成された点列、オレンジが制約による実行可能領域の境界、黒のバツが制約なしの時の最適解です。 原点からスタートして最適解に近づきつつも制約を満たすところで止まってるのが分ります。実際にターミナルの出力を確認すると最適化した変数のノルムがほぼ1になっています。
最後に
今回は最適化手法の紹介と自前実装のソルバーを使って実際に最適化問題を解いてみました。 整数の最適化問題とか整数混合問題とかも勉強してみたいですね。
記事にミスがあった場合はコメントしてもらえるとありがたいです。
最後に宣伝ですが来年は学生ロボコン2023で後輩達がかっこいいロボット作って優勝してくれると思うので応援よろしくおねがいします!