tag:blogger.com,1999:blog-91983725545188890602024-03-19T17:47:03.867+09:00試行錯誤な日々面白がって貰えたり参考になれば嬉しいですAsuki Konohttp://www.blogger.com/profile/07813182469285556500noreply@blogger.comBlogger485125tag:blogger.com,1999:blog-9198372554518889060.post-88854957878868971052024-03-17T23:05:00.000+09:002024-03-17T23:05:20.939+09:00cppでconst値を参照してエラーを出したいときはstatic_assertが使える<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjuy9Buz0zR7sOSI_F0n5nzlHUUcQvcxMw4LiGRgRcxHrWsLdmILvpjTLaAIF8TN9HZeqqriE0gNeR3PYsZs2X2a6WZO1TO9QiA17nqS0TjNDUbrDSwI4vUfMi38lhxhYtS2TpAprh3DklDYQyRVXznLf22MKbptwjgEiqcIJdij4U9A7Ndbm_3_zHZI9Q/s308/Screenshot%20from%202024-03-17%2022-57-47.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="98" data-original-width="308" height="127" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjuy9Buz0zR7sOSI_F0n5nzlHUUcQvcxMw4LiGRgRcxHrWsLdmILvpjTLaAIF8TN9HZeqqriE0gNeR3PYsZs2X2a6WZO1TO9QiA17nqS0TjNDUbrDSwI4vUfMi38lhxhYtS2TpAprh3DklDYQyRVXznLf22MKbptwjgEiqcIJdij4U9A7Ndbm_3_zHZI9Q/w400-h127/Screenshot%20from%202024-03-17%2022-57-47.png" width="400" /></a></div><br /><h1 style="text-align: left;">背景</h1>cppで固定値(const値)を参照してビルド時にエラーを出すのはstatic_assertを使えば良いと分かったので、利用例を備忘録として記事に残します。<br /><br /><h1 style="text-align: left;">使ったもの</h1>c++11かそれより新しいc++の環境<br /><br /><h1 style="text-align: left;">利用例</h1>const値を参照して条件を記述し、その条件に合わなかったときに第2引数で渡した警告文をビルドエラーとして表示させれます。<br /><pre>const int a = 0;<br />const int b = a + 1;<br />const int c = b + 1;<br />const int d = c + 2; // wrong adding 2<br />static_assert(d == 3, "d sould be 3");<br /></pre><br />ビルド時のエラー<pre>main.cpp:6:17: error: static assertion failed: d sould less than 3<br /> 6 | static_assert(d < 4, "d sould less than 3");<br /> | ~~^~~</pre><br />VSCodeを利用すれば、静的解析時に異常を検知してくれます。<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj7pM58RmosX5flnbquA4X5ItTuchlLME3ikiy2Y2oeU-UCOpMZpBHvMJGwWu21Oef9HiGTqrWoA1MICXrwHRiAdzqanEJN4bOCYLJcTC6-1e41_mS8KIHzp9UQnWGs5aeGSxzukhgcPsQNlajzwR6forXWH5cZwx8BUEyTTgX1IQVUu4T2cP0OFLp1D9c/s461/Screenshot%20from%202024-03-17%2022-13-33.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="79" data-original-width="461" height="110" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj7pM58RmosX5flnbquA4X5ItTuchlLME3ikiy2Y2oeU-UCOpMZpBHvMJGwWu21Oef9HiGTqrWoA1MICXrwHRiAdzqanEJN4bOCYLJcTC6-1e41_mS8KIHzp9UQnWGs5aeGSxzukhgcPsQNlajzwR6forXWH5cZwx8BUEyTTgX1IQVUu4T2cP0OFLp1D9c/w640-h110/Screenshot%20from%202024-03-17%2022-13-33.png" width="640" /></a></div><br />条件の記述にはcastや演算式も利用可能です。<br /><pre>const unsigned char sizeA = 50;<br />const unsigned char sizeB = 50;<br />const unsigned char sizeC = 50;<br />const unsigned char sizeD = 50;<br />const unsigned char sizeE = 60;<br />static_assert((int)sizeA + sizeB + sizeC + sizeD + sizeE <= 0xff,<br /> "total size sould less or equal 0xff");<br /></pre><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhR3I5SZDXOcCuFWDvimynoxF6MGj_FxUdzCMCJ00msG4E-xyZmcibj0_Cf7LFv3N9jNFgpH_qQ4GtN9dWhVSrCsLJ1g-RgfbXpDkBzQEsYEG2k3c6Qb5krLMgnW8JCjPrlm08I9u2DdVYs38KmXnBGauhfEHKjazCOtUyNAmD8Da6KtqylfCAinfdSm-w/s552/Screenshot%20from%202024-03-17%2022-34-05.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="106" data-original-width="552" height="122" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhR3I5SZDXOcCuFWDvimynoxF6MGj_FxUdzCMCJ00msG4E-xyZmcibj0_Cf7LFv3N9jNFgpH_qQ4GtN9dWhVSrCsLJ1g-RgfbXpDkBzQEsYEG2k3c6Qb5krLMgnW8JCjPrlm08I9u2DdVYs38KmXnBGauhfEHKjazCOtUyNAmD8Da6KtqylfCAinfdSm-w/w640-h122/Screenshot%20from%202024-03-17%2022-34-05.png" width="640" /></a></div><br /><h1 style="text-align: left;">やれても良さそうだができないこと: constでない変数は識別不能</h1>関数の中で定義して操作したconstでない変数はstatic_assertの対象外でした。<br /><pre>int main() {<br /> int a = 0;<br /> ++a;<br /> ++a;<br /> static_assert(a < 2, "a sould less than 2"); // できない<br /> return 0;<br />}<br /></pre><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh_TQ-Y90s4NuIw5M8BIPJf8bMQIGcOPRYRyRE4BA771wePczbpK8JbETjCOiTze3Fe2DKKbGOjgygRfyEibJNtqTjJWyBIrMYFHjFcvrHlBUAtcdorYPDhNq9PRKaqBXdKqo4HAqyoVgNcUJ02mZi-GMGbiFXMNtG698MU28kNnuho76JxXD9lp8FupRk/s679/Screenshot%20from%202024-03-17%2022-52-15.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="153" data-original-width="679" height="144" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh_TQ-Y90s4NuIw5M8BIPJf8bMQIGcOPRYRyRE4BA771wePczbpK8JbETjCOiTze3Fe2DKKbGOjgygRfyEibJNtqTjJWyBIrMYFHjFcvrHlBUAtcdorYPDhNq9PRKaqBXdKqo4HAqyoVgNcUJ02mZi-GMGbiFXMNtG698MU28kNnuho76JxXD9lp8FupRk/w640-h144/Screenshot%20from%202024-03-17%2022-52-15.png" width="640" /></a></div><br /><h1 style="text-align: left;">おわり</h1>const値とstatic_assertを利用してビルドや静的解析でエラーを出せました。<br />要所で活用すると不具合を防げそうです。<br /><br /><h1 style="text-align: left;">参考</h1>static_assertの存在を知ったstack overflowのスレッドです。<br /><a href="https://stackoverflow.com/questions/69501472/best-way-to-trigger-a-compile-time-error-if-no-if-constexprs-succeed">Best way to trigger a compile-time error if no if-constexpr's succeed?</a><br /><br />static_assertの仕様紹介ページです。<br /><a href="https://en.cppreference.com/w/cpp/language/static_assert">static_assert declaration (since C++11)</a><br /><br />Asuki Konohttp://www.blogger.com/profile/07813182469285556500noreply@blogger.com0tag:blogger.com,1999:blog-9198372554518889060.post-47909096621697716722024-03-11T00:03:00.000+09:002024-03-11T00:03:06.814+09:00virtual boxのクライアントにドライバを入れる<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgxVc4U3eYILjTav6VlZI-SW0hM0_RU9eCUpbo36chNL5yWwrextjTNMfE0gsczPmc_Gb24UpQ8H0iT7-eUzd7KVyf93jepJK3jOubj0Yv32Rz-l9ciXcS0037cvbwPK_FHT1RshKEGo3L2reGWbS8ukdSk84PpX0s_kTmkS63VBE6o12Po_q44MZDGPjU/s535/Screenshot%20from%202024-03-10%2022-05-17.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="298" data-original-width="535" height="356" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgxVc4U3eYILjTav6VlZI-SW0hM0_RU9eCUpbo36chNL5yWwrextjTNMfE0gsczPmc_Gb24UpQ8H0iT7-eUzd7KVyf93jepJK3jOubj0Yv32Rz-l9ciXcS0037cvbwPK_FHT1RshKEGo3L2reGWbS8ukdSk84PpX0s_kTmkS63VBE6o12Po_q44MZDGPjU/w640-h356/Screenshot%20from%202024-03-10%2022-05-17.png" width="640" /></a></div><br />上記画像の通り、クライアント(virtual machine)の画面のメニューからデバイス -> Guest Additions CDイメージの挿入 を選びます。<br />必要があればCDのファイルがダウンロードされます。<br /><br />メニューバーが表示されてない場合は下記の操作で表示させてください<br /><ul style="text-align: left;"><li>「キーボードの右の Ctrl」 + c を入力してスケールモードを切り替え</li><li>「キーボードの右のCtrl」+ s を入力し設定画面を出して ユーザーインターフェース設定画面の右上のチェックを有効にしてOKを押す</li></ul><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjJvOaF6uXqbeYihESm0WvAP5a6NW9BzwvEHTaewEy558lmgPbNIICz8zp15ERkbPIc_Afrq8OeeT4jPlS-wD1uoIWZDh20CNE3hUmoXkT3l0Xuw5mKypZBsCdJ7NQbJ7Qokhsvzllt7MOxymf1u_sdkLM_UK77JMXAEyrd80G-NI0_ZelamVqkCCAxokc/s992/check_and_ok.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="677" data-original-width="992" height="436" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjJvOaF6uXqbeYihESm0WvAP5a6NW9BzwvEHTaewEy558lmgPbNIICz8zp15ERkbPIc_Afrq8OeeT4jPlS-wD1uoIWZDh20CNE3hUmoXkT3l0Xuw5mKypZBsCdJ7NQbJ7Qokhsvzllt7MOxymf1u_sdkLM_UK77JMXAEyrd80G-NI0_ZelamVqkCCAxokc/w640-h436/check_and_ok.png" width="640" /></a></div><br />CDがマウントされたら、中にあるファイルを実行すると関連ドライバがインストールされます。<br />クライアントがubutuの場合はautorun.shを実行します。<br />(クライアントがwindowsなら多分exeファイルを実行したら良いのだと思います。)<br /><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgbDJJDVpt0dGED2Ufp2QQvD1AY6lHX6o12Dh9Wa8oxKjaIO_wSMP8W-fKt90AtHAaZhLDLyQkp3qUjhrxH1L9nxCnhpZLT7n7wo1rl4Hwp7n-0Ifjgtb6msr20hSKj3DCrcM9ed_vJl1_G55fxda-wmeI58I7_-kBoMGRAOCXpCFOVT9o0eCJWIuDksqY/s697/Screenshot%20from%202024-03-10%2023-12-25.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="223" data-original-width="697" height="204" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgbDJJDVpt0dGED2Ufp2QQvD1AY6lHX6o12Dh9Wa8oxKjaIO_wSMP8W-fKt90AtHAaZhLDLyQkp3qUjhrxH1L9nxCnhpZLT7n7wo1rl4Hwp7n-0Ifjgtb6msr20hSKj3DCrcM9ed_vJl1_G55fxda-wmeI58I7_-kBoMGRAOCXpCFOVT9o0eCJWIuDksqY/w640-h204/Screenshot%20from%202024-03-10%2023-12-25.png" width="640" /></a></div><br />Press Returnと出たら処理が終了しているので、エンターを押して画面を閉じ、クライアントをシャットダウンします。<br /><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhIZuWsioeVM4uefzIAVHTj8tn1LnVOtJp8DCTEQn7k1ivf44rpCea46jJCTtiUXiCNDX2vfedQIgEqTb9pkRnQJwa5QxYqzG65OKmSwAk4nBnSOIDklsTKjRv-M5W2Js6docPLN_axQ4eYHMwNPCepAJ_XsqCKkmwP4e7Q7g_glNalQ0k39otYB5_Yz9Y/s746/Screenshot%20from%202024-03-10%2023-16-43.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="120" data-original-width="746" height="102" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhIZuWsioeVM4uefzIAVHTj8tn1LnVOtJp8DCTEQn7k1ivf44rpCea46jJCTtiUXiCNDX2vfedQIgEqTb9pkRnQJwa5QxYqzG65OKmSwAk4nBnSOIDklsTKjRv-M5W2Js6docPLN_axQ4eYHMwNPCepAJ_XsqCKkmwP4e7Q7g_glNalQ0k39otYB5_Yz9Y/w640-h102/Screenshot%20from%202024-03-10%2023-16-43.png" width="640" /></a></div><br />シャットダウンすると設定が反映されます。<br /><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjUvDFFuEvBDpNLTp_GU6hMAD20K9Ahi4MkPAZfSZ8YoiYYvTxjtc30hkUvS9YCYJM1jE7xeRfAWzY0PzNeGXmiUHKOHVKhhJvl_xM31_thQ30Xlbg6EO4YshDhU_yne520ekPorAbRZWBT_UoVVGnGw7lmEPowTq9KhUTgiMlS6LCZXCIENk-oKf_jkTE/s359/Screenshot%20from%202024-03-10%2023-26-54.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="213" data-original-width="359" height="238" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjUvDFFuEvBDpNLTp_GU6hMAD20K9Ahi4MkPAZfSZ8YoiYYvTxjtc30hkUvS9YCYJM1jE7xeRfAWzY0PzNeGXmiUHKOHVKhhJvl_xM31_thQ30Xlbg6EO4YshDhU_yne520ekPorAbRZWBT_UoVVGnGw7lmEPowTq9KhUTgiMlS6LCZXCIENk-oKf_jkTE/w400-h238/Screenshot%20from%202024-03-10%2023-26-54.png" width="400" /></a></div><br />適用されたら、画面の伸縮やクリップボードの共有設定が反映されました。<br /><br />isoを手動でダウンロードしたり、aptコマンドでクライアントに関連プログラムをインストールする情報が出てきたり、メニューバーが表示されてなかったり、手間取りましたが標準の機能を利用してクライアントにドライバを入れれました。<br />OSを入れ直してVirtual Boxを再設定する頃には忘れて再度検索すると思ったので、備忘録として記事を残します。<br /><br />参考<br /><a href="https://www.virtualbox.org/manual/ch04.html#additions-linux">4.2.2. Guest Additions for Linux</a><br /><a href="https://superuser.com/questions/42134/how-do-i-enable-the-shared-clipboard-in-virtualbox">How do I enable the shared clipboard in VirtualBox?</a><br /><a href="https://superuser.com/questions/1176587/i-hid-the-menu-bar-in-virtualbox-how-to-show-it-again">I hid the menu bar in VirtualBox, how to show it again?</a><br /><br />Asuki Konohttp://www.blogger.com/profile/07813182469285556500noreply@blogger.com0tag:blogger.com,1999:blog-9198372554518889060.post-31357753040387439232024-03-04T00:44:00.003+09:002024-03-04T00:44:41.431+09:00ubuntu22.04で最新のnpmを使おうとしたら発生したsemver関係の不具合はhash -rコマンドで直る場合がある<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEigNCeOXh6vbzTg5t_Myp4_f4er39QWyBgqw1k7xa3JxtBMmlkWZCrDayTxysWnZbW5s71Oy1jeB5Y6fkNRWZG0QZD-iabMCEukhyphenhyphenCMglhATToWJ402rASEGEPAlypRDr2g92Yl1Q7LlLojA5FiBbgETKb-ONd4byUyuCd9xvuc1e8H-tHOEi0zYvJgxik/s457/Screenshot%20from%202024-03-03%2012-21-35.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="356" data-original-width="457" height="498" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEigNCeOXh6vbzTg5t_Myp4_f4er39QWyBgqw1k7xa3JxtBMmlkWZCrDayTxysWnZbW5s71Oy1jeB5Y6fkNRWZG0QZD-iabMCEukhyphenhyphenCMglhATToWJ402rASEGEPAlypRDr2g92Yl1Q7LlLojA5FiBbgETKb-ONd4byUyuCd9xvuc1e8H-tHOEi0zYvJgxik/w640-h498/Screenshot%20from%202024-03-03%2012-21-35.png" width="640" /></a></div><br />問題解決のためにこの記事にたどり着いた方は、下記のコマンドを実行してnpmを再実行してみてください。<br /><pre>harh -r</pre><br /><h1 style="text-align: left;">背景</h1>ubuntu22.04で最新のnpmを使おうとnコマンドを利用して更新したところ、semverが見つからないというエラーが発生して動かなくなりました。<br />試行錯誤したところ、nコマンド実行後に表示されるhashコマンドを実行すると直りました。<br />備忘録として関連情報を記事に残します。<br /><br /><h1 style="text-align: left;">利用環境</h1>ubuntu22.04<br /><br /><h1 style="text-align: left;">hash更新コマンドを実行しないと発生した不具合</h1>npmコマンドを実行すると下記のようなエラーが発生して困りました。<pre>node:internal/modules/cjs/loader:1144<br /> const err = new Error(message);<br /> ^<br /><br />Error: Cannot find module 'semver'<br />Require stack:<br />- /usr/share/nodejs/npm/lib/utils/unsupported.js<br />- /usr/share/nodejs/npm/lib/cli.js<br />- /usr/share/nodejs/npm/bin/npm-cli.js<br /> at Module._resolveFilename (node:internal/modules/cjs/loader:1144:15)<br /> at Module._load (node:internal/modules/cjs/loader:985:27)<br /> at Module.require (node:internal/modules/cjs/loader:1235:19)<br /> at require (node:internal/modules/helpers:176:18)<br /> at Object.<anonymous> (/usr/share/nodejs/npm/lib/utils/unsupported.js:2:16)<br /> at Module._compile (node:internal/modules/cjs/loader:1376:14)<br /> at Module._extensions..js (node:internal/modules/cjs/loader:1435:10)<br /> at Module.load (node:internal/modules/cjs/loader:1207:32)<br /> at Module._load (node:internal/modules/cjs/loader:1023:12)<br /> at Module.require (node:internal/modules/cjs/loader:1235:19) {<br /> code: 'MODULE_NOT_FOUND',<br /> requireStack: [<br /> '/usr/share/nodejs/npm/lib/utils/unsupported.js',<br /> '/usr/share/nodejs/npm/lib/cli.js',<br /> '/usr/share/nodejs/npm/bin/npm-cli.js'<br /> ]<br />}<br /><br />Node.js v20.11.1<br /></pre><br /><h1 style="text-align: left;">最新のnpmをインストールするコマンド</h1>下記のコマンドでubuntuのnpmを最新にしました。<br />nodejsのページからtarをダウンロードする方法もありますが、自分はaptでダウンロードしたnpmでnをインストールし、そのnで最新版に更新しました。<pre>sudo apt install -y npm<br />sudo npm install -g n<br />sudo n stable<br />hash -r<br /></pre><br />上記の最後のhashコマンドが重要です。<br />nでnode環境を更新すると下記の情報が表示されたのでそれに従いました。<br /><pre>Note: the node command changed location and the old location may be remembered in your current shell.<br /> old : /usr/bin/node<br /> new : /usr/local/bin/node<br />If "node --version" shows the old version then start a new shell, or reset the location hash with:<br />hash -r (for bash, zsh, ash, dash, and ksh)<br />rehash (for csh and tcsh)<br /></pre><br />自分はbash環境を使っているので「hash -r」を実行しましたが、cshやtcshを利用している方は「rehadh」を実行してください。<br /><br /><h1 style="text-align: left;">余談: npm全消し(アンインストール)コマンド</h1>試行錯誤のときにnode環境を全消ししてインストールし直すのを繰り返した際に実施した全消しコマンドです。<br /><pre>sudo apt purge -y nodejs npm<br />sudo apt autoremove -y<br />sudo rm -rf /usr/local/bin/npm /usr/local/share/man/man1/node* ~/.npm<br />sudo rm -rf /usr/local/lib/node*<br />sudo rm -rf /usr/local/bin/node*<br />sudo rm -rf /usr/local/include/node*<br />sudo rm -rf ~/.npm<br /></pre><br />この後aptでnpmをインストールすると、古いnpmが実行可能な環境に戻ります。<br /><br /><h1 style="text-align: left;">おわり</h1>nコマンドを実行するとnpmが壊れて戸惑いましたが、「hash -r」(もしくは「rehash」)コマンドを実行すれば直ると分かって良かったです。<br /><br /><h1 style="text-align: left;">参考</h1><a href="https://qiita.com/nanakochi123456/questions/0e42c35f80490fbd46f0#answer-a80bdccb50156457e48e">npmが動かない(Cannot find module 'semver')</a><br /><a href="https://askubuntu.com/questions/1152570/npm-cant-find-module-semver-error-in-ubuntu-19-04#_=_">Npm can't find module "semver" error in Ubuntu 19.04</a><br /><br />Asuki Konohttp://www.blogger.com/profile/07813182469285556500noreply@blogger.com0tag:blogger.com,1999:blog-9198372554518889060.post-60001915909844067832024-02-25T23:42:00.002+09:002024-02-25T23:42:20.139+09:00graphqlの動作確認をcurlで実施<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgHtecg9yklQLB6qA2ZyMgGR28BM8Ewpwt6OWUloXJ63ZPuF841F64_Bv2JhR5SiAne6jSoCZz9_S6Cgq6Sn1UGArPa1Bn6Ai1ujp5ysiBABz8wh48osQHX6XBM1GEkzJ_nJplBIgrdmJAXXN7PKvg11_nTi8AVYI5wMIVVkKDbZBUj2hltpcNtLvAHqyU/s753/Screenshot%20from%202024-02-25%2023-27-30.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="199" data-original-width="753" height="170" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgHtecg9yklQLB6qA2ZyMgGR28BM8Ewpwt6OWUloXJ63ZPuF841F64_Bv2JhR5SiAne6jSoCZz9_S6Cgq6Sn1UGArPa1Bn6Ai1ujp5ysiBABz8wh48osQHX6XBM1GEkzJ_nJplBIgrdmJAXXN7PKvg11_nTi8AVYI5wMIVVkKDbZBUj2hltpcNtLvAHqyU/w640-h170/Screenshot%20from%202024-02-25%2023-27-30.png" width="640" /></a></div><br /><h1 style="text-align: left;">背景</h1>graphqlとはサーバーのAPIの記述方式の1つです。<br />動作確認時のコマンドを組み立てるのがなかなか手間だったので、備忘録として内容を記事に残します。<br /><br />紹介するコマンドは下記のログ取りサーバーの動作確認のために作りました。<br /><a href="https://github.com/asukiaaa/clj-server-practice">clj-server-practice</a><br /><br /><h1 style="text-align: left;">作ったコマンド全体</h1>コマンドの全体はこちらです。<br />ubuntu22.04のbashで動作を確認しました。<br /><pre>AUTH_BEARER="XXYYZZ"<br />HOST=http://localhost:3000<br /><br />function escape_str () {<br /> echo "$1" | sed 's/\\/\\\\/g' | sed 's/\"/\\"/g'<br />}<br /><br />WHERE="[{\"key\": [\"data\", \"camera_id\"], \"action\": \"not_null\"}]"<br />ESCAPED_WHERE=$(escape_str "$WHERE")<br />ORDER="[{\"key\": \"created_at\", \"dir\": \"desc\"}]"<br />ESCAPED_ORDER=$(escape_str "$ORDER")<br />QUERY="{ raw_device_logs(where: \"$ESCAPED_WHERE\", order: \"$ESCAPED_ORDER\") { total } } }"<br />ESCAPED_QUERY=$(escape_str "$QUERY")<br />JSON="{\"query\": \"$ESCAPED_QUERY\"}"<br /><br />RECEIVED_JSON=$(curl -X POST ${HOST}/graphql \<br /> -H "Authorization: Bearer $AUTH_BEARER" \<br /> -H "Content-Type: application/json" \<br /> -d "$JSON")<br />echo $RECEIVED_JSON<br /></pre><br />要所を解説します。<br /><br /><h1 style="text-align: left;">graphQLのリクエストはjsonのqueryキーに必要な情報を記述してpostする</h1>jsonのqueryキーにgraphqlのquery(取得したい情報)の<b>文字列</b>を渡します。<br /><pre>HOST=http://localhost:3000<br />curl -X POST ${HOST}/graphql \<br /> -H "Content-Type: application/json" \<br /> -d "{\"query\": \"{ raw_device_logs { total } }\"}"<br /></pre><br />文字列なので、query内部で文字列を扱う場合はダブルクオートやバックスペースなどのエスケープ(文字列の中で表示する文字列の形式に変換)が必要です。<br /><pre>HOST=http://localhost:3000<br />curl -X POST ${HOST}/graphql \<br /> -H "Content-Type: application/json" \<br /> -d "{\"query\": \"{ raw_device_logs(where: \\\"[{\\\\\\\"key\\\\\\\": [\\\\\\\"data\\\\\\\", \\\\\\\"camera_id\\\\\\\"], \\\\\\\"action\\\\\\\": \\\\\\\"not_null\\\\\\\"}]\\\", order: \\\"[{\\\\\\\"key\\\\\\\": \\\\\\\"created_at\\\\\\\", \\\\\\\"dir\\\\\\\": \\\\\\\"desc\\\\\\\"}]\\\") { total } } }\"}"<br /></pre><br />上記のような3階層以上の文字列エスケープは手動入力が困難なほど「\」が多いです。<br /><br /><h1 style="text-align: left;">bashでの文字列エスケープは関数を作って使うのが便利</h1>echoとsedコマンドを組み合わせて文字列エスケープを行う関数を作り、必要な箇所で呼びました。<br />(bashの<a href="https://www.gnu.org/software/bash/manual/bash.html#Shell-Parameter-Expansion">Shell Parameter Expansion</a>( ${STR//a/b} で aをbに変えられる表現)も試しましたが、2回連続で処理する記述方法は無さそうだったので、今回はecho1回とsed2回で関数を組みました。)<br /><br /><pre>function escape_str () {<br /> echo "$1" | sed 's/\\/\\\\/g' | sed 's/\"/\\"/g'<br />}<br /></pre><br />これを使うことで、「\」の数の把握が困難な階層のエスケープも手動入力に比べて楽に作れます。<br /><pre>WHERE="[{\"key\": [\"data\", \"camera_id\"], \"action\": \"not_null\"}]"<br />ESCAPED_WHERE=$(escape_str "$WHERE")<br />ORDER="[{\"key\": \"created_at\", \"dir\": \"desc\"}]"<br />ESCAPED_ORDER=$(escape_str "$ORDER")<br />QUERY="{ raw_device_logs(where: \"$ESCAPED_WHERE\", order: \"$ESCAPED_ORDER\") { total } } }"<br />ESCAPED_QUERY=$(escape_str "$QUERY")<br />JSON="{\"query\": \"$ESCAPED_QUERY\"}"<br />echo $JSON</pre><pre>{"query": "{ raw_device_logs(where: \"[{\\\"key\\\": [\\\"data\\\", \\\"camera_id\\\"], \\\"action\\\": \\\"not_null\\\"}]\", order: \"[{\\\"key\\\": \\\"created_at\\\", \\\"dir\\\": \\\"desc\\\"}]\") { total } } }"}<br /></pre><br />更に良い書き方や便利コマンドがあれば、コメントなどで教えていただけると嬉しいです。<br /><br /><h1 style="text-align: left;">必要に応じてヘッダに認証情報を追加</h1>curlコマンドなので、一般的なAPIのpostと同様に必要があれば認証情報を付与できます。<br /><pre>AUTH_BEARER="XXYYZZ"<br />curl -X POST ${HOST}/graphql \<br /> -H "Authorization: Bearer $AUTH_BEARER" \<br /> -H "Content-Type: application/json" \<br /> -d "$JSON"<br /></pre><br /><h1 style="text-align: left;">おわり</h1>graphql動作確認用のcurlコマンドを作って動かせました。<br />エスケープの「\」が多かったの人力でのコマンドを組み立ては早々諦めてbash芸に集中しました。<br />この記事の情報がコマンドでgraphqlの動作確認をcurlで行いたい人(将来の自分も含む)の助けになれば嬉しいです。<br /><br /><h1 style="text-align: left;">参考</h1>公式のREADMEです。<br /><a href="https://docs.github.com/ja/graphql/guides/forming-calls-with-graphql">GraphQLでの呼び出しの作成</a><br /><br />今回は使わなくなりましたが、bashの変数の文字列を置き換える表現の関連情報です。<br /><a href="https://qiita.com/r_plus/items/ac0093fd8c317ed96b4b">echo | sedなんていらなかったんだ!</a><br /><a href="https://stackoverflow.com/questions/13210880/replace-one-substring-for-another-string-in-shell-script">Replace one substring for another string in shell script</a><br /><a href="https://www.gnu.org/software/bash/manual/bash.html#Shell-Parameter-Expansion">Shell Parameter Expansion</a><br /><br />bashの関数で変数を扱うには$1や$2を使えば良いと把握したフォーラムです。<br /><a href="https://stackoverflow.com/questions/6212219/passing-parameters-to-a-bash-function">Passing parameters to a Bash function</a><br /><br />Asuki Konohttp://www.blogger.com/profile/07813182469285556500noreply@blogger.com0tag:blogger.com,1999:blog-9198372554518889060.post-189197991608646092024-02-18T22:53:00.007+09:002024-02-18T22:58:30.003+09:00ZED-F9PとNEO-D9Cを繋げてL6電波を利用する単独測位<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgACWO6QA5Wnhm140LKyGQ0BHP45NpERCJiAAq3U48fJh8Kc9_hRmplArK8787D9jr0aslpgYF4hEuGFIPhw0p9nkucj0YXXfObhmrvLXu0pEuS9O615GODM5m-wA-I9FDRhS2gqY593sBl-o4Os1mIp14nmDB9jeZ6wb7UC1NKxNiSdUKslhvSlfEqRCc/s2513/original_495273ff-741b-4701-946e-062fe2bd12da_IMG_20240218_202636.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1508" data-original-width="2513" height="384" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgACWO6QA5Wnhm140LKyGQ0BHP45NpERCJiAAq3U48fJh8Kc9_hRmplArK8787D9jr0aslpgYF4hEuGFIPhw0p9nkucj0YXXfObhmrvLXu0pEuS9O615GODM5m-wA-I9FDRhS2gqY593sBl-o4Os1mIp14nmDB9jeZ6wb7UC1NKxNiSdUKslhvSlfEqRCc/w640-h384/original_495273ff-741b-4701-946e-062fe2bd12da_IMG_20240218_202636.jpg" width="640" /></a></div><br /><h1 style="text-align: left;">背景</h1>日本の衛星測位システム「みちびき」のL6電波を受信可能なNEO-D9CをZED-F9Pと連携させれば単独測位でもcm級誤差の精度を得られるらしいと知ったので、装置を買って動かしてみました。<br />備忘録として設定方法と取得できる値を記事に残します。<br /><br /><h1 style="text-align: left;">使ったもの</h1><ul style="text-align: left;"><li><a href="https://store.shopping.yahoo.co.jp/geosense2/d9cx1.html">ジオセンス みちびき CLAS L6受信用 NEO-D9C開発ボード D9CX1</a><br />これでL6電波を受信します。<br />説明書はこちらです。<br /><a href="https://www.geosense.co.jp/d9cx1_manual/">D9CX1使用説明書</a><br /></li><li><a href="https://store.shopping.yahoo.co.jp/geosense2/f9px1.html">ジオセンス ZED-F9P RTKシステム開発用ボード F9PX1</a><br />これでL1とL2の電波を受信します。<br /><a href="https://asukiaaa.blogspot.com/2024/01/build-ntrip-client-and-server-with-using-double-zed-f9p-and-pygpsclient.html">以前の記事</a>で利用したF9P基板も使えますが、D9CX1と組み合わせて使いやすいように信号線の位置が工夫されていたので、D0CX1やアンテナと共に購入しました。<br />説明書はこちらです。<br /><a href="https://www.geosense.co.jp/f9px1_manual/">F9PX1使用説明書</a></li><li><a href="https://store.shopping.yahoo.co.jp/geosense2/bt345aj.html">L5/L6対応多周波RTK(ZED-F9P対応)GPS/GNSSアンテナ BT-345AJ</a><br />L1,L2,L5,L6を受信できるアンテナです。<br />D9CとF9Pが同時に利用します。<br /></li><li><a href="https://akizukidenshi.com/catalog/g/g100167/">ピンヘッダ</a> 7P、<a href="https://akizukidenshi.com/catalog/g/g105779/">ピンソケット</a> 7P<br />F9PとD9Cに付けて信号線を接続します。<br /></li><li>はんだ + はんだごて<br />ピンヘッダとピンソケットの取り付けに利用します。<br /></li><li>microB USBケーブル 1本<br />今回利用するF9PとD9Cの基板にはmicroBのUSBポートが付いているので、それを介してPCに接続します。<br /></li><li>u-centerやpygpsclientなど、ublox製品の設定を行えるソフトウェアをインストールしたPC<br />D9Cの設定変更に使います。<br /></li></ul><br /><h1 style="text-align: left;">F9Pで「みちびき」のL6情報を扱うにはファームウェアは1.30以上が必要</h1><a href="https://www.geosense.co.jp/d9cx1_manual/">D9CX1使用説明書</a>によるとみちびきの情報を扱うにはファームウェア1.30以上が必要です。<br /><br />「使ったもの」の一覧で共有したF9Pには現時点で最新の1.32のファームウェアが書き込まれていたのでそのまま使えましたが、1.30未満のファームウェアが書き込まれているF9Pを利用している場合はファームウェア1.30以上への更新が必要です。<br /><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgY0dPkDSpussqXX7VnlHF2Qi5zJknu7f0OKCL5dig_Uk5QpoeW9z3CJtilghYZkESglHvsC-pewIzVQAspq1gsIEBrQv4QGjiJUMusUsRC_ZPeM01L-23kiSTi9IH2zCz_e_w3Uj-FyqUXuzl5U4QZb3dcP9qTk2P2VTd_eynTG974yrt54ZGVdvJP44w/s426/Screenshot%20from%202024-02-18%2019-37-39.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="102" data-original-width="426" height="154" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgY0dPkDSpussqXX7VnlHF2Qi5zJknu7f0OKCL5dig_Uk5QpoeW9z3CJtilghYZkESglHvsC-pewIzVQAspq1gsIEBrQv4QGjiJUMusUsRC_ZPeM01L-23kiSTi9IH2zCz_e_w3Uj-FyqUXuzl5U4QZb3dcP9qTk2P2VTd_eynTG974yrt54ZGVdvJP44w/w640-h154/Screenshot%20from%202024-02-18%2019-37-39.png" width="640" /></a></div><br />ファームウェアの更新にはとu-center(とwindows pc)が必要です。<br />下記のページが参考になります。<br /><br /><a href="https://www.geosense.co.jp/tech_firmware_verup/">ZED-F9Pファームウェアのバージョンアップ</a><br /><br /><h1 style="text-align: left;">D9CのUART2 TXとF9PのUART2 RXを接続</h1>ジオセンスのD9CとF9PはUART2のRXとTXが入れ替わるように配置されているので、端の端子をそれぞれ繋げばUART2を接続できます。<br /><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhllbLXDyuoWDumWPjuL01X3St5qrSqMk4ohRm1LEaPRREtmazZPSmK7BdconKehN7f21fTIU_ceJGq-ZInomKeb4BF5-5GC1w8IO_NXk5QOFV4aK6ZSq4SwILONfeCY6mfabc7GRaUWKm5SyqFVXelB-6HbjMFIGZKuKL5B5F5HSPzIA8MqRGRt4OCfNA/s1337/IMG_20240217_190149~4.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="857" data-original-width="1337" height="410" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhllbLXDyuoWDumWPjuL01X3St5qrSqMk4ohRm1LEaPRREtmazZPSmK7BdconKehN7f21fTIU_ceJGq-ZInomKeb4BF5-5GC1w8IO_NXk5QOFV4aK6ZSq4SwILONfeCY6mfabc7GRaUWKm5SyqFVXelB-6HbjMFIGZKuKL5B5F5HSPzIA8MqRGRt4OCfNA/w640-h410/IMG_20240217_190149~4.jpg" width="640" /></a></div><br />どちらもUSBケーブルでPCに繋ぐ場合はD9CのUART2 TXとF9PのUART2 RXだけの接続で良いですが、今回はF9Pへの給電でD9Cも動いて欲しいので、RXとTXがあるピンの並び全て(GND、V5V、PWR、RX2-TX2、TX2-RX2)を接続します。<br />PWRピンはどちらも1.8~4Vの電源の入力端子なので、繋いでも無意味ですが故障はしません。<br /><br />さて、購入した装置の「アンテナ接続用の端子の背の高さと足の出っ張り」が「ピンヘッダとピンソケットを組み合わせたときの高さ」を上回るため、実装面を同じ向きにするとピンソケットとピンヘッダでは繋げません。<br /><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjlbW-9XldM7SUnViZZ8Yd4JmPbcXNoPxCQwwbRUkup4nBGdfDbliHG-U3lj_MRIFFYx0bGWWfKoWd5iE0DlPXSM7Sz-2IK9CQ-RJkXODgnDMmpMgRkoDABWMiyEr7soFuj_B2iZLcfALQpz_7e4W1oxoR88BfJ6igFHiMWrN0PEF4OCbqE7ltt4OUZhys/s1278/IMG_20240217_193439.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="940" data-original-width="1278" height="470" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjlbW-9XldM7SUnViZZ8Yd4JmPbcXNoPxCQwwbRUkup4nBGdfDbliHG-U3lj_MRIFFYx0bGWWfKoWd5iE0DlPXSM7Sz-2IK9CQ-RJkXODgnDMmpMgRkoDABWMiyEr7soFuj_B2iZLcfALQpz_7e4W1oxoR88BfJ6igFHiMWrN0PEF4OCbqE7ltt4OUZhys/w640-h470/IMG_20240217_193439.jpg" width="640" /></a></div><br />幸い欲しい信号線は基板の端にあるため、実装面を互い違いにするとピンソケットとピンヘッダで繋げました。<br /><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjrrzIVau_lUW3Iu0NeOQfWxQ0QJ9Bb5NyyXB5C3gNyNPuZKp10AGZV_C51G1ymHynnjpHsFBFNoo1sH60Gdy6NA76em-jP4JrDJH1luxlaBFnqNqPXlPqsSAnGL1lfNrEa6LMY_LNQGgMYgxjDjYSELw84geX-dORhm9D0AJHRDX5gdPL951vIZq4k0hY/s1809/IMG_20240217_194235.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1801" data-original-width="1809" height="638" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjrrzIVau_lUW3Iu0NeOQfWxQ0QJ9Bb5NyyXB5C3gNyNPuZKp10AGZV_C51G1ymHynnjpHsFBFNoo1sH60Gdy6NA76em-jP4JrDJH1luxlaBFnqNqPXlPqsSAnGL1lfNrEa6LMY_LNQGgMYgxjDjYSELw84geX-dORhm9D0AJHRDX5gdPL951vIZq4k0hY/w640-h638/IMG_20240217_194235.jpg" width="640" /></a></div><br />繋ぐとこうなりました。<br /><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgDME6rKfF6JCiuV7pvZn317KqHQGblXO9JgEl_pU3OJMBRR-KswhUxE07iLWOwx0MZ-ABqEU4Ysa7DCvvd67AoA_uCSED3T3cLyobIXbGlgCgmMU3Vzd8cdfqUHrF5AjjHWy72oA_qiQLGC3tvzTutNSFFtYVdcHZBXduSejy6_oq6gANar6bPKzOHj_U/s2608/IMG_20240217_194323.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1745" data-original-width="2608" height="428" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgDME6rKfF6JCiuV7pvZn317KqHQGblXO9JgEl_pU3OJMBRR-KswhUxE07iLWOwx0MZ-ABqEU4Ysa7DCvvd67AoA_uCSED3T3cLyobIXbGlgCgmMU3Vzd8cdfqUHrF5AjjHWy72oA_qiQLGC3tvzTutNSFFtYVdcHZBXduSejy6_oq6gANar6bPKzOHj_U/w640-h428/IMG_20240217_194323.jpg" width="640" /></a></div><br />D9Cのアンテナへの電力供給線は開放したままにします。<br />F9Pから供給されるからです。<br /><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhrxkPzX2glev5YEMhqrI6Vqn7EYPGLt8cCLFUyzNwNPGyXusj44e7c5vwNJGPDABv7vOacXirKSQcFzUBs8ln5A7S1iOC9Lb54zjKNXCEj-rX7Bi7hjGIOGLd79YxSJftlt4XUT1fzZFr-kgnud7MwSSYwfNbqCDWVYMkiE-nLA12K3A6qu_-dCFFirkw/s834/original_60701b7c-3cdc-4b83-a19c-584154ded2e2_IMG_20240218_202125.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="733" data-original-width="834" height="281" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhrxkPzX2glev5YEMhqrI6Vqn7EYPGLt8cCLFUyzNwNPGyXusj44e7c5vwNJGPDABv7vOacXirKSQcFzUBs8ln5A7S1iOC9Lb54zjKNXCEj-rX7Bi7hjGIOGLd79YxSJftlt4XUT1fzZFr-kgnud7MwSSYwfNbqCDWVYMkiE-nLA12K3A6qu_-dCFFirkw/s320/original_60701b7c-3cdc-4b83-a19c-584154ded2e2_IMG_20240218_202125.jpg" width="320" /></a></div><br /><h1 style="text-align: left;">D9CのUART2の設定を変更</h1>F9PにUART2経由でL6電波の情報を送るために、u-centerやpygpsclientを利用してD9CのUART2設定を下記のように変更します。<br /><ul style="text-align: left;"><li>CFG_UART2_BAUDRATE を 38400<br /> F9PのUART2の工場出荷時の通信速度が38400なので、それに合わせます。</li><li>CFG_UART2OUTPORT_UBX を 1<br />UART2からのUBX配信を有効にしてL6の受信情報を配信できます。<br /></li></ul><br />上記の設定はRAMだけでなくFLASH書き込みが可能なので、FLASHも書き換えるとD9Cを再起動しても設定を維持できて便利です。<br /><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgeJDAE_2EyDpJO1R897e6yhTKtOwYwDJogzSXM0r-KYLhZQGkCUGZmQBHxeP0YuQI7ikI9ugXm5z95NgwPqufv2Rehs8h0aZkBpMoa14nsVcV4G284B3_ed2jjLdMEZIipdstk2IMLbgyVXEjAuw5nwh3CogLT0J40akmp6CajQU3UIMt3yi8biL5UnO0/s434/Screenshot%20from%202024-02-18%2020-23-36.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="359" data-original-width="434" height="331" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgeJDAE_2EyDpJO1R897e6yhTKtOwYwDJogzSXM0r-KYLhZQGkCUGZmQBHxeP0YuQI7ikI9ugXm5z95NgwPqufv2Rehs8h0aZkBpMoa14nsVcV4G284B3_ed2jjLdMEZIipdstk2IMLbgyVXEjAuw5nwh3CogLT0J40akmp6CajQU3UIMt3yi8biL5UnO0/w400-h331/Screenshot%20from%202024-02-18%2020-23-36.png" width="400" /></a></div><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjeI7G6rVDXQs0mNUD0Bqm4TB-XuwLzRhUsJjdVVrmYZq-9IwrmbNgmDiy0Dg1NxLovYhnVGpOHFtJLRgsTn1pEr1F6KtaR5uNsoZQOi5ijGUtM1lKb1_nX-LE4nugeRHoe-dV0PFHMS4K3yjORmCauX0TweUIpW8tYD8xp8GOcjbcgSOOipvy-KD6xgBY/s434/Screenshot%20from%202024-02-18%2020-23-48.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="359" data-original-width="434" height="331" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjeI7G6rVDXQs0mNUD0Bqm4TB-XuwLzRhUsJjdVVrmYZq-9IwrmbNgmDiy0Dg1NxLovYhnVGpOHFtJLRgsTn1pEr1F6KtaR5uNsoZQOi5ijGUtM1lKb1_nX-LE4nugeRHoe-dV0PFHMS4K3yjORmCauX0TweUIpW8tYD8xp8GOcjbcgSOOipvy-KD6xgBY/w400-h331/Screenshot%20from%202024-02-18%2020-23-48.png" width="400" /></a></div><br /><h1 style="text-align: left;">F9PとD9Cとアンテナを繋いでF9Pから配信される情報を確認</h1>空が開けたところで装置をUSB接続して情報を取得すると測位情報がFix状態になります。<br /><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgACWO6QA5Wnhm140LKyGQ0BHP45NpERCJiAAq3U48fJh8Kc9_hRmplArK8787D9jr0aslpgYF4hEuGFIPhw0p9nkucj0YXXfObhmrvLXu0pEuS9O615GODM5m-wA-I9FDRhS2gqY593sBl-o4Os1mIp14nmDB9jeZ6wb7UC1NKxNiSdUKslhvSlfEqRCc/s2513/original_495273ff-741b-4701-946e-062fe2bd12da_IMG_20240218_202636.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1508" data-original-width="2513" height="384" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgACWO6QA5Wnhm140LKyGQ0BHP45NpERCJiAAq3U48fJh8Kc9_hRmplArK8787D9jr0aslpgYF4hEuGFIPhw0p9nkucj0YXXfObhmrvLXu0pEuS9O615GODM5m-wA-I9FDRhS2gqY593sBl-o4Os1mIp14nmDB9jeZ6wb7UC1NKxNiSdUKslhvSlfEqRCc/w640-h384/original_495273ff-741b-4701-946e-062fe2bd12da_IMG_20240218_202636.jpg" width="640" /></a></div><br />会社の駐車場で動作確認しました。<br /><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjudgos9Ndh5GRU-4DnCn_hOCRP9SJvWWbaWjYkxP-WGcOaidDS0lR210K-dwZ2GupO0HOsydtJ-_6ZJzEwm-zPa_YedKEKkKy91dI_ZBU_zuqLzVmmpbHjmlz5_Qlit7eXeykkmf7y4Ln4DkPBj1XXi5yidLPVydAbeBIrgUgbdRLyUUysMrMGPGfrTdI/s4096/IMG_20240218_151950.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="3072" data-original-width="4096" height="300" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjudgos9Ndh5GRU-4DnCn_hOCRP9SJvWWbaWjYkxP-WGcOaidDS0lR210K-dwZ2GupO0HOsydtJ-_6ZJzEwm-zPa_YedKEKkKy91dI_ZBU_zuqLzVmmpbHjmlz5_Qlit7eXeykkmf7y4Ln4DkPBj1XXi5yidLPVydAbeBIrgUgbdRLyUUysMrMGPGfrTdI/w400-h300/IMG_20240218_151950.jpg" width="400" /></a></div><br />Fix時は下記の情報がF9Pから配信されました。<br /><pre>$GNRMC,055707.00,A,3610.56537,N,13917.57079,E,0.007,,180224,,,R,V*0A<br />$GNVTG,,T,,M,0.007,N,0.013,K,D*3D<br />$GNGGA,055707.00,3610.56537,N,13917.57079,E,4,12,0.78,57.6,M,38.5,M,5.0,0000*5D<br />$GNGSA,A,3,02,07,08,30,16,21,10,26,27,,,,1.32,0.78,1.07,1*02<br />$GNGSA,A,3,74,73,75,84,85,,,,,,,,1.32,0.78,1.07,2*0F<br />$GNGSA,A,3,13,21,26,27,15,,,,,,,,1.32,0.78,1.07,3*0E<br />$GNGSA,A,3,07,09,10,16,25,23,24,11,06,12,,,1.32,0.78,1.07,4*00<br />$GNGSA,A,3,07,02,03,,,,,,,,,,1.32,0.78,1.07,5*0A<br />$GPGSV,3,1,12,01,,,43,02,45,206,46,07,41,292,47,08,67,338,45,1*5E<br />$GPGSV,3,2,12,10,20,078,43,16,38,108,44,21,61,198,46,26,12,123,31,1*6B<br />$GPGSV,3,3,12,27,46,049,46,30,18,315,35,41,18,249,41,50,46,200,43,1*60<br />$GPGSV,2,1,06,07,41,292,43,08,67,338,47,10,20,078,43,26,12,123,31,6*66<br />$GPGSV,2,2,06,27,46,049,47,30,18,315,39,6*6B<br />$GPGSV,1,1,01,23,09,045,,0*5D<br />$GLGSV,2,1,06,73,27,144,48,74,74,132,40,75,45,330,47,84,59,019,37,1*79<br />$GLGSV,2,2,06,85,54,238,48,86,06,222,40,1*79<br />$GLGSV,2,1,05,73,27,144,50,75,45,330,47,84,59,019,43,85,54,238,47,3*70<br />$GLGSV,2,2,05,86,06,222,39,3*4F<br />$GLGSV,1,1,01,83,00,036,,0*46<br />$GAGSV,2,1,07,04,01,293,32,13,74,090,50,14,65,289,50,15,26,041,37,2*72<br />$GAGSV,2,2,07,21,76,001,50,26,40,200,49,27,40,112,50,2*4E<br />$GAGSV,2,1,06,13,74,090,45,14,65,289,46,15,26,041,33,21,76,001,44,7*7E<br />$GAGSV,2,2,06,26,40,200,46,27,40,112,46,7*74<br />$GAGSV,1,1,01,19,01,241,,0*4B<br />$GBGSV,2,1,08,07,51,292,43,09,48,250,45,10,38,286,42,12,51,039,47,1*7D<br />$GBGSV,2,2,08,16,41,223,46,23,30,314,45,24,37,153,46,25,75,257,47,1*79<br />$GBGSV,2,1,07,06,43,228,45,07,51,292,47,09,48,250,47,10,38,286,45,B*06<br />$GBGSV,2,2,07,11,67,255,50,12,51,039,51,16,41,223,44,B*3C<br />$GBGSV,4,1,14,01,46,171,,02,18,246,,03,37,222,,04,42,148,,0*72<br />$GBGSV,4,2,14,34,79,348,,38,05,182,,39,33,212,,40,56,308,,0*70<br />$GBGSV,4,3,14,43,42,245,,44,28,049,,59,46,179,,60,15,249,,0*7C<br />$GBGSV,4,4,14,61,38,223,,62,45,146,,0*7B<br />$GQGSV,1,1,04,02,85,104,43,03,69,177,43,04,09,185,30,07,46,200,40,1*67<br />$GQGSV,1,1,04,02,85,104,47,03,69,177,47,04,09,185,39,07,46,200,46,6*6F<br />$GNGLL,3610.56537,N,13917.57079,E,055707.00,A,D*75<br /></pre><br />GGAに注目すると、測位状態(Eの後)がRTK FIXを意味する4になっていました。<br /><pre>$GNGGA,055707.00,3610.56537,N,13917.57079,E,4,12,0.78,57.6,M,38.5,M,5.0,0000*5D<br /></pre><br />今回はRTKを使っていないのですが、L6を利用した高精度単独測位を意味する状態が無いためRTKのFIXを使っていると推測します。<br /><br /><h1 style="text-align: left;">L6を利用した単独測位はRTKに比べると不安定な印象</h1>会社にRTK装置(softbankのichimil)があるので今回のL6を利用するF9PとFIX具合を比較したところ、RTKの方が安定していました。<br /><br />L6を利用するF9Pは装置を持ち歩いて数m移動するとFixからFloat状態になることが多かったです。<br />一方、RTKは大体問題なく動きました。<br />移動者の胸元あたりにアンテナ部分を抱えて移動したので、頭にアンテナを固定する防止やヘルメットを作れば安定するのかもしれません。<br /><br />また、重要な衛星があるであろう方向は、2階建ての建物から5m以上離れないとL6を利用するF9PはFixしませんでした。<br />RTKは精度は不明ですが、空が見えていれば大体Fixしてくれます。<br /><br />精度や安定度を上げる設定などをご存知でしたら、コメントなどで教えていただけると嬉しいです。<br /><br /><h1 style="text-align: left;">おわり</h1>ZED-F9PとNEO-D9Cを組み合わせて、みちびきのL6電波を受信して単独測位を行えました。<br />RTKに比べるとFixの安定度は低かったですが、動かせて良かったです。<br /><br /><h1 style="text-align: left;">参考</h1>利用したF9PとD9Cの基板の説明書です。<br /><a href="https://www.geosense.co.jp/f9px1_manual/">F9PX1使用説明書</a><br /><a href="https://www.geosense.co.jp/d9cx1_manual/">D9CX1使用説明書</a><br /><br />以前手持ちのF9Pを2台使ってRTKを試したときの記事です。<br />pygpsclientを利用した設定値の書き換え方法も解説しています。<br /><a href="https://asukiaaa.blogspot.com/2024/01/build-ntrip-client-and-server-with-using-double-zed-f9p-and-pygpsclient.html"> ZED-F9P 2台とpygpslientを利用してntripのserverかつcasterとclientとして動かしてRTKで位置を推定 </a><br /><br />Asuki Konohttp://www.blogger.com/profile/07813182469285556500noreply@blogger.com0tag:blogger.com,1999:blog-9198372554518889060.post-703170717341774962024-02-12T21:57:00.004+09:002024-02-12T21:57:39.344+09:00SIM7600は3Gを無効にすると安定するものがある<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjR0LJYJGDqLpuocj_dAVwzDdMVx2QJb7YXoQzHIVg1K9aIbRoO9I0l4T1SwL6ck8sokC8jKB2D4V_GH29SQ2C1pfV_kPIvn_Qnt5y13Fy4a5bia5pwurVDp1XxFfgbCWeA_Hv8AJAbXCAUD6OAPHROK0Ng2NbYDxdv2DRsJJ9ZDRMCuKCTanDR8shLokw/s841/IMG_20231212_111242~3.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="560" data-original-width="841" height="266" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjR0LJYJGDqLpuocj_dAVwzDdMVx2QJb7YXoQzHIVg1K9aIbRoO9I0l4T1SwL6ck8sokC8jKB2D4V_GH29SQ2C1pfV_kPIvn_Qnt5y13Fy4a5bia5pwurVDp1XxFfgbCWeA_Hv8AJAbXCAUD6OAPHROK0Ng2NbYDxdv2DRsJJ9ZDRMCuKCTanDR8shLokw/w400-h266/IMG_20231212_111242~3.jpg" width="400" /></a></div><br /><h1 style="text-align: left;">背景</h1>SIM7600とは3Gや4G LTEの通信装置です。<br />PCならUSB通信で、マイコンならUART通信で設定を施して、soracomなどSIMを繋いでWAN(インターネット)に接続できます。<br /><br />SIM7600JC(SIM7600の日本仕様)をaliexpressで購入したところ、設定を施すと再起動を繰り返すものに複数遭遇しました。<br />試行錯誤したところ3Gの設定を有効にしなければ動くと分かったので、設定方法を備忘録として記事に残します。<br /><br /><h1 style="text-align: left;">使ったもの</h1><ul style="text-align: left;"><li>SIM7600JC-H</li><li>soracom plan-d のSIM</li><li>SIM7600JCにUSB接続する基板とPC</li></ul><br /><h1 style="text-align: left;">3Gを使わずWCDMA(4G)のみを有効化</h1>下記のように3Gを有効化しないATコマンドを設定すれば、自分が遭遇した不具合品?は安定して動作しました。<br /><pre>AT+CNBP=0x000700000FFF0380,0x000007FF3FDF3FFF,0x000000000000003F</pre><br /><a href="https://www.waveshare.com/w/upload/5/54/SIM7500_SIM7600_Series_AT_Command_Manual_V1.08.pdf">SIM7600のATコマンドマニュアル</a>の「AT+CNBP」に詳しい説明があり、下記のようにカンマ区切りでmode, lte_mode, tds_modeが指定可能で、modeを「0x000700000FFF0380」にすると、3G(GSM)は無効化したまま4G(WCDMA)だけを有効化できます。<br /><pre>AT+CNBP=<mode>[,<lte_mode>][,<tds_mode>]</pre><br />modeを全部使う設定「0xFFFFFFFF7FFFFFFF」にすると、再起動を繰り返す装置がありました。<br /><br /><h1 style="text-align: left;">3Gを有効にすると不具合が発生するものは、revisionに_ESC3が付く</h1>3Gを有効にすると不具合が発生するものとそうでないものは、自分が確認した範囲では外見では区別不能でした。<br />revisionを確認するための「AT+CGMR」コマンドで取得した情報に違いがあり、不具合が発生するものには「_ESC3」という文字列が末尾に付いていました。<br /><br />不具合が発生するもの<br /><pre>AT+CGMR<br />+CGMR: LE11B05SIM7600JC-H_ESC3</pre><br />不具合が発生しないもの<br /><pre>AT+CGMR<br />+CGMR: LE11B05SIM7600JC-H</pre><br /><h1 style="text-align: left;">再起動を繰り返す場合は、無線設定を初期値に戻せば良い</h1>再起動を繰り返してしまうため一旦安定させたい場合は、工場出荷と同様に通信のmodeを全て無効化すると、自分が遭遇した不具合が発生するSIM7600は安定しました。<br /><pre>AT+CNBP=0x0000000000000000,0x000007FF3FDF3FFF,0x000000000000003F</pre><br /><h1 style="text-align: left;">おわり</h1>revisionで_ESC3と末尾に付くSIM7600は、3G通信を避けるべき仕様なのか、3G(GSM)を有効にすると再起動を繰り返すものがありましたが、3Gを避けて4G(WCDMA)のみを有効にすれば期待通りに動きました。<br />非対応なら機能を有効化しても落ちずに使えないまま動いて欲しいですが、回避方法が分かって良かったです。<br /><br /><h1 style="text-align: left;">参考</h1><a href="https://electronics.stackexchange.com/questions/105533/atcnbp-command-for-sim5216e-cellular-module">AT+CNBP command for SIM5216E cellular module [closed]</a><br /><a href="https://www.waveshare.com/w/upload/5/54/SIM7500_SIM7600_Series_AT_Command_Manual_V1.08.pdf">SIM7600のATコマンドマニュアル</a><br /><br />Asuki Konohttp://www.blogger.com/profile/07813182469285556500noreply@blogger.com0tag:blogger.com,1999:blog-9198372554518889060.post-26356999582394509452024-02-04T23:35:00.000+09:002024-02-04T23:35:26.415+09:00pyubx2を利用してZED-F9Pの設定を変更するスクリプトを作った<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjTsp24sCtDZh2IEFVoz3iR8srjpk54Xc_VgcBQZQNrajcuIx1KUcQEoekYdCqCXc6RAokcpF8UlfDgrAUHA5IELwNcJs-YPxwQNRMCKBp0xJhT2iC2UYFGEPtyEIWrc6vHh5qLGEJyeG-Rvn4q5-D6c3mbnXHfUHuAg_JTcaOk3yt43nIRSmk7lB9xn8k/s1512/IMG_20240204_232954~2.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1171" data-original-width="1512" height="248" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjTsp24sCtDZh2IEFVoz3iR8srjpk54Xc_VgcBQZQNrajcuIx1KUcQEoekYdCqCXc6RAokcpF8UlfDgrAUHA5IELwNcJs-YPxwQNRMCKBp0xJhT2iC2UYFGEPtyEIWrc6vHh5qLGEJyeG-Rvn4q5-D6c3mbnXHfUHuAg_JTcaOk3yt43nIRSmk7lB9xn8k/s320/IMG_20240204_232954~2.jpg" width="320" /></a></div><br /><h1 style="text-align: left;">背景</h1><a href="https://asukiaaa.blogspot.com/2024/01/build-ntrip-client-and-server-with-using-double-zed-f9p-and-pygpsclient.html">前回pygpsclientというプログラムを利用して、ZED-F9Pを2台利用してRTKのためのntrip server + casterとntrip clientをubuntu上で動かし</a>ました。<br /><br />このpygpsclientはpyubx2などのpythonライブラリを利用して作られており、一部の機能はcliとして呼び出せるのですが、自分が利用したい設定値の書き込みや読み出し機能は自分が調べたり試したりした範囲ではcliとして提供されていません。<br />(ubxsetrateが近いのですが、設定値の読み書きは不能でした。)<br /><br />コマンドを通して設定変更や内容確認ができたら便利だと思うので、cliとして使えるpythonスクリプトを作りました。<br />備忘録としてgithubでも公開しつつ記事にも使い方を残します。<br /><br />スクリプトをまとめているリポジトリはこちらです。<br /><a href="https://github.com/asukiaaa/scripts-pyubx-config">https://github.com/asukiaaa/scripts-pyubx-config</a><br /><br /><h1 style="text-align: left;">使ったもの</h1><ul style="text-align: left;"><li>ubuntuをインストールしたPC</li><li>python3</li><li>ZED-F9P</li><li>USBケーブル</li></ul><br /><h1 style="text-align: left;">準備</h1><h2 style="text-align: left;">関連ライブラリをインストール</h2>pythonとgitを使うので、それらをインストールします。<pre>sudo apt update<br />sudo apt upgrade<br />sudo apt install -y python3-pip git</pre><br />主な処理にpyubx2を、cli化にclickを利用しているので、それらをpipでインストールします。<br /><pre>pip3 install pyubx2 click</pre><br /><h2 style="text-align: left;">スクリプトを含むリポジトリをダウンロード</h2>下記のリポジトリダウンロード(clone)して実行可能な状態にします。<br /><a href="https://github.com/asukiaaa/scripts-pyubx-config">https://github.com/asukiaaa/scripts-pyubx-config</a><br /><br />この記事では~/gitprojectsというディレクトリにリポジトリを配置して利用します。<br /><pre>mkdir -p ~/gitprojects<br />git clone https://github.com/asukiaaa/scripts-pyubx-config.git<br /></pre><br /><h1 style="text-align: left;">書き込み対象はpyubx2の定義を利用</h1>これから解説するコマンドでkeyとして指定する書き込み対象は、pyubx2で<a href="https://github.com/semuconsulting/pyubx2/blob/b55d97c5c4f7f0d4547b24074efd4caead090e60/src/pyubx2/ubxtypes_configdb.py#L69">UBX_CONFIG_DATABASE</a>として定義されているものを使います。<br />設定変更したい対象は、上記の定義から探してください。<br /><br />この記事ではUART1の通信速度設定である<a href="https://github.com/semuconsulting/pyubx2/blob/b55d97c5c4f7f0d4547b24074efd4caead090e60/src/pyubx2/ubxtypes_configdb.py#L1241">CFG_UART1_BAUDRATE</a>に対する書き込みを例として解説します。<br /><br /><h1 style="text-align: left;">設定書き込み</h1><a href="https://github.com/asukiaaa/scripts-pyubx-config/blob/main/pyubx-cfg-set.py">pyubx-cfg-set.py</a>で設定値を書き込みます。<br />--portでZED-F9Pのポートを、--keyで書き込み対象のキーを、--valueで書き込み値を渡して実行します。<br />通信速度を標準から変えている場合は--baudrateで指定してください。標準のbaudrateは38400bpsです。<br />このコマンドはUART1の通信速度設定である<a href="https://github.com/semuconsulting/pyubx2/blob/b55d97c5c4f7f0d4547b24074efd4caead090e60/src/pyubx2/ubxtypes_configdb.py#L1241">CFG_UART1_BAUDRATE</a>に対する書き込みを行います。<br /><pre>~/gitprojects/scripts-pyubx-config/pyubx-cfg-set.py --port /dev/ttyACM0 --key CFG_UART1_BAUDRATE --value 9600<br /></pre><br />コマンドの組み立てが成功すると下記のようなログが表示されます。<br /><pre><UBX(CFG-VALSET, version=0, ram=1, bbr=0, flash=0, action=0, reserved0=0, CFG_UART1_BAUDRATE=9600)><br /></pre><br />通信速度が合っていないとコマンドの書き込みが無視されるので、先程の説明の繰り返しになりますが、標準の38400bps以外にしている場合は--baudrateで指定してください。<br /><br /><h1 style="text-align: left;">設定読み込み</h1><a href="https://github.com/asukiaaa/scripts-pyubx-config/blob/main/pyubx-cfg-get.py">pyubx-cfg-get.py</a>で設定値を読み込めます。<br />--portでZED-F9Pのポートを、--keyで書き込み対象のキーを、--valueで書き込み値を渡して実行します。<br />(通信速度を標準から変えている場合は--baudrateで指定してください。標準のbaudrateは38400bpsです。)<br />このコマンドはUART1の通信速度設定である<a href="https://github.com/semuconsulting/pyubx2/blob/b55d97c5c4f7f0d4547b24074efd4caead090e60/src/pyubx2/ubxtypes_configdb.py#L1241">CFG_UART1_BAUDRATE</a>に対する読み込みを行います。<br /><pre>~/gitprojects/scripts-pyubx-config/pyubx-cfg-get.py --port /dev/ttyACM0 --key CFG_UART1_BAUDRATE</pre><br />コマンドが成功すると下記のようなログが表示されます。<br /><pre><UBX(CFG-VALGET, version=1, layer=0, position=0, CFG_UART1_BAUDRATE=9600)><br /></pre><br />先程のコマンドで設定した9600が設定されたのが分かります。<br /><br /><h1 style="text-align: left;">使いどころ</h1>ZED-F9Pを基地局モードにする際に便利です。<br />下記のコマンドは、位置固定モード(CFG-TMODE-MODEを2)にした上で、緯度経度高さを36.17609700, 139.29287333で,98.5に設定するコマンドです。<pre>cd ~/gitprojects/scripts-pyubx-config<br />PORT=/dev/ttyACM0<br />./pyubx-cfg-set.py --port $PORT --key CFG_TMODE_MODE --value 2<br />./pyubx-cfg-set.py --port $PORT --key CFG_TMODE_LAT --value 361760970<br />./pyubx-cfg-set.py --port $PORT --key CFG_TMODE_LON --value 1392928733<br />./pyubx-cfg-set.py --port $PORT --key CFG_TMODE_HEIGHT --value 9850<br /></pre><br />pyubx-cfg-get.pyで確認可能です。<br /><pre>cd ~/gitprojects/scripts-pyubx-config<br />PORT=/dev/ttyACM0<br />./pyubx-cfg-get.py --port $PORT --key CFG_TMODE_MODE<br />./pyubx-cfg-get.py --port $PORT --key CFG_TMODE_LAT<br />./pyubx-cfg-get.py --port $PORT --key CFG_TMODE_LON<br />./pyubx-cfg-get.py --port $PORT --key CFG_TMODE_HEIGHT<br /></pre><br />書き換えに成功していれば下記のログが表示されます。<br /><pre><UBX(CFG-VALGET, version=1, layer=0, position=0, CFG_TMODE_MODE=2)><br /><UBX(CFG-VALGET, version=1, layer=0, position=0, CFG_TMODE_LAT=361760970)><br /><UBX(CFG-VALGET, version=1, layer=0, position=0, CFG_TMODE_LON=1392928733)><br /><UBX(CFG-VALGET, version=1, layer=0, position=0, CFG_TMODE_HEIGHT=9850)><br /></pre><br /><h1 style="text-align: left;">おわり</h1>コマンドで設定して値を読み書きできるスクリプトを作って、ZED-F9Pに対する設定の書き込みと読み込みができました。<br /><br /><h1 style="text-align: left;">参考</h1><a href="https://github.com/asukiaaa/scripts-pyubx-config">scripts-pyubx-config</a><br /><a href="https://github.com/semuconsulting/pyubx2">pyubx2</a><br /><a href="https://asukiaaa.blogspot.com/2024/01/build-ntrip-client-and-server-with-using-double-zed-f9p-and-pygpsclient.html"> ZED-F9P 2台とpygpslientを利用してntripのserverかつcasterとclientとして動かしてRTKで位置を推定 </a><br /><br />Asuki Konohttp://www.blogger.com/profile/07813182469285556500noreply@blogger.com0tag:blogger.com,1999:blog-9198372554518889060.post-16397617122581332662024-01-29T00:24:00.008+09:002024-01-29T00:30:53.683+09:00ZED-F9P 2台とpygpslientを利用してntripのserverかつcasterとclientとして動かしてRTKで位置を推定<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEglkRTjl1ijpQKeYR6XoUcyYK9UPLOqsL_xRa7ody3Ci1M8r_qsMzByWuKYw0wwilpOt9yoDPOQve7j3K1K-Jyyr-oTiESqVBbTCnxh3mscscqfsoM0MZBTbwUpGQsnlqdUZ3PIM_0FDAJk6Xu-3tjfp01zKY4QfAk5tQtcu7hHDnlcqqg64dfCPRRxpzU/s1920/Screenshot%20from%202024-01-28%2014-52-22.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1080" data-original-width="1920" height="360" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEglkRTjl1ijpQKeYR6XoUcyYK9UPLOqsL_xRa7ody3Ci1M8r_qsMzByWuKYw0wwilpOt9yoDPOQve7j3K1K-Jyyr-oTiESqVBbTCnxh3mscscqfsoM0MZBTbwUpGQsnlqdUZ3PIM_0FDAJk6Xu-3tjfp01zKY4QfAk5tQtcu7hHDnlcqqg64dfCPRRxpzU/w640-h360/Screenshot%20from%202024-01-28%2014-52-22.png" width="640" /></a></div><br /><h1 style="text-align: left;">背景</h1>RTKとは基地局の情報を元に移動局の位置を補正して数cmの精度の位置情報を取得する仕組みです。<br />pygpsclientは有志が開発しているZED-F9PでRTKを実現するためのプログラムです。<br />ZED-F9Pという装置を利用すればRTKの基地局も移動局も作れるということで、取り組んでみました。<br />備忘録として取り組んだ内容を記事に残します。<br /><br /><h1 style="text-align: left;">使ったもの</h1><ul style="text-align: left;"><li><a href="https://www.switch-science.com/products/6319">ZED-F9Pピッチ変換基板</a> x2<br />ZED-F9Pを搭載した基板なら基本的にこの記事の内容で動かせると思います。<br />注意点として、型番が似ていて安いNEO-M9NモジュールはRTKに対応していないのでこの記事の内容を試せません。<br />ZED-F9Pが載ったものをご用意ください。<br /></li><li>L1 L2 対応アンテナ x2<br />ZED-F9PはL1とL2という種類の電波を受信できるので、それに対応したアンテナを利用します。<br /></li><li><a href="https://www.switch-science.com/products/1413">アンテナ変換コネクタ</a> x2<br />今回利用するZED-F9P基板には上記のアンテナを直接は付けられないので、変換コネクタ(SMA -> u.FL)を利用します。<br /></li><li>USB typeCケーブル x2<br />ZED-F9Pの基板をPCにUSB接続するのに使います。<br /></li><li>Ubuntu 22.04をインストールしたPC x1<br />今回はlinuxでも動くプログラムを利用してRTKを構築します。<br /></li></ul><br /><h1 style="text-align: left;">Windowsを持っている人向け: ファームウェア更新の勧め</h1>記事を書いている時点でZED-F9P向けの最新のファームウェアは2022年5月12日に公開された「HPG1.32」です。<br />この記事の内容は更新前の「HPG1.13」でも動きましたが、新しいファームウェアの方が性能向上や不具合改善を見込めるので、WindowsのPCを持っている方はu-centerを利用してファームウェアを更新をお勧めします。<br /><br />ファームウェア更新は下記のページが参考になります。<br /><br /><a href="https://www.geosense.co.jp/tech_firmware_verup/">ZED-F9Pファームウェアのバージョンアップ</a><br /><br /><h1 style="text-align: left;">PCにpygpsclientをインストール</h1>今回はubuntuで動かすため、windows専用のu-blox公式プログラムではなく、有志が作った<a href="https://github.com/semuconsulting/PyGPSClient">pygpsclient</a>というプログラムを使います。<br /><br />pipで動かすのでpythonをインストールしてからpygpsclientをインストールします。<br /><pre>sudo apt update<br />sudo apt upgrade<br />sudo apt install -y python3-pip<br />pyton3 -m pip install pygpsclient<br /></pre><br />インストールしたらpygpsclientをコマンドとして呼べるようになります。<br /><pre>pygpsclient -h</pre><br />インストールしたのにpygpsclientを呼べない場合はpython3の実行可能ファイルへのパスが通っていない可能性があるので、.bashrcに下記の行を追加すると多分実行可能になります。<br />
<div class="pre-box"><div class="pre-name">~/.bashrc</div>
<pre>export PATH=$PATH:$HOME/.local/bin</pre>
</div>
<br />bashrcを書き換えたら下記のコマンドで再読込できます。<br /><pre>source ~/.bashrc</pre><br /><br />インストールできたらコマンドを実行してpygpsclientを起動します。<br /><pre>pygpsclient</pre><br />起動するとこのような窓が表示されます。<br /><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhbjdc2nQOy9MgikmYpPbhiwrnjfmx4yxi9vMmR0W0NtuSy1jE_VS5ESUnMNRoKw34GmdWm6u0BK9KkK93AoNdkhERtJlWN_WSWMDYOpa9n3mwRcnxbpAxtNXbC0F6POlXKczlrfWK6pNC9-LLjCfjhkqvVY8gq02V5rtNaXNGLc_Ml2UAesJV8viaaA7Y/s1388/Screenshot%20from%202024-01-28%2019-23-37.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="974" data-original-width="1388" height="450" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhbjdc2nQOy9MgikmYpPbhiwrnjfmx4yxi9vMmR0W0NtuSy1jE_VS5ESUnMNRoKw34GmdWm6u0BK9KkK93AoNdkhERtJlWN_WSWMDYOpa9n3mwRcnxbpAxtNXbC0F6POlXKczlrfWK6pNC9-LLjCfjhkqvVY8gq02V5rtNaXNGLc_Ml2UAesJV8viaaA7Y/w640-h450/Screenshot%20from%202024-01-28%2019-23-37.png" width="640" /></a></div><br /><h1 style="text-align: left;">pygpsclientを利用したF9Pの設定値変更: CFG-NMEA-SVNUMBERINGを有効にしてみちびきを利用<br /></h1><h2 style="text-align: left;">F9Pに接続してUBX Configurationで設定値を参照</h2>公式のu-centerで行うような値の設定変更をpygpsclientでもできます。<br />ここではF9Pが観測対象の衛星でF9Pが利用中のNMEAで定義されてないの情報も利用する「CFG-NMEA-SVNUMBERING」を有効にする方法を例にして設定方法を解説します。<br /><br />F9Pが標準設定で利用するNMEA 4.10ではBeiDouやZQSS(みちびき)の情報が定義されてないので、これを有効にすると利用されます。<br /><a href="https://content.u-blox.com/sites/default/files/documents/u-blox-F9-HPG-1.32_InterfaceDescription_UBX-22008968.pdf">F9Pの説明書</a>の「2.2 NMEA protocol configuration」の「CFG-NMEA-SVNUMBERING」に説明があります。<br />(CFG-NMEA-PROTVを42にするとみちびきが定義済みのNMEA4.11を利用可能な装置もあるようなのですが、どうなったらみちびきが利用されている状態なのかデータの見方がまだ分からないので、一旦「CFG-NMEA-SVNUMBERING」で対応しています。)<br /><br />設定を変更するためにまずはF9Pと接続状態にします。<br />右上のSerial Portに注目し、対象のポートを選んでUSBマークを押します。<br />pygpsclientを起動後にF9Pを接続してシリアルポートに表示されてない時は、シリアルポートの右下の更新ボタンを押すと出てきます。<br /><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgjAYIgU8oJUONSx8JRrpBmXvfigt5kOXSMLunPEdeq7umKwlKwBxjDCJJTBgn9IQa0zozMfXewUn5izT_JBbSRMxfApDLL5vbnFSgMMBkY0SN5Oif18i0XJMDnIVfDgo1oclf8pIDlePHOD45_DzayONLQy2OJ0EmX_llfsQReF6m6DFdtZTyqg-C6Jng/s398/open_port.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="312" data-original-width="398" height="502" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgjAYIgU8oJUONSx8JRrpBmXvfigt5kOXSMLunPEdeq7umKwlKwBxjDCJJTBgn9IQa0zozMfXewUn5izT_JBbSRMxfApDLL5vbnFSgMMBkY0SN5Oif18i0XJMDnIVfDgo1oclf8pIDlePHOD45_DzayONLQy2OJ0EmX_llfsQReF6m6DFdtZTyqg-C6Jng/w640-h502/open_port.png" width="640" /></a></div><br />接続ボタンを押して何か情報が流れる状態になったら、右側下部のUBX Configボタンを押します。<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjbRgZuhbnobNHE5Oiy_fq1sFYxp4PFhFVAw7r_q2IIDazV_fm5qftREqjH59Uia-Nm1XTGbkDINBMzFwzBU9t9P5ZzlJCPKCGYo3XAcIn0AF4Hfq4def0nFEtL6nUP-i4JKk2gYgCk_TJyxw8DLRfAg9BYLnTQo5CydFmUSs8f0b2t7YhLurhzlviTJEo/s649/open_ubx_config.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="649" data-original-width="395" height="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjbRgZuhbnobNHE5Oiy_fq1sFYxp4PFhFVAw7r_q2IIDazV_fm5qftREqjH59Uia-Nm1XTGbkDINBMzFwzBU9t9P5ZzlJCPKCGYo3XAcIn0AF4Hfq4def0nFEtL6nUP-i4JKk2gYgCk_TJyxw8DLRfAg9BYLnTQo5CydFmUSs8f0b2t7YhLurhzlviTJEo/w244-h400/open_ubx_config.png" width="244" /></a></div><br />UBX Configuratonの窓の右上に注目します。<br />左下や中央でも一部の値を閲覧や設定できますが、同様のことを右上でも行えるのと、右上でしか確認できない値があるので、この記事では右上の操作のみ解説します。<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjrRolWRwdo0rHD2U7LbR0kpsu8bmfYUDwEA0c_mFj9DCWs9pAr537_L0B5KnmN12khWgT29aq4iq0WXdl6FpKXI3xmowEVAG0OHyM6B7Zot5-sGQbBI3D5tDVd-Mi-cvziZfVoH0vwKAIGmGXBLcfjhyphenhyphenrx9rAqY_F43jSXB-f-aFIe2s1BDpWISdLQrjQ/s1213/see_right_up.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="790" data-original-width="1213" height="416" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjrRolWRwdo0rHD2U7LbR0kpsu8bmfYUDwEA0c_mFj9DCWs9pAr537_L0B5KnmN12khWgT29aq4iq0WXdl6FpKXI3xmowEVAG0OHyM6B7Zot5-sGQbBI3D5tDVd-Mi-cvziZfVoH0vwKAIGmGXBLcfjhyphenhyphenrx9rAqY_F43jSXB-f-aFIe2s1BDpWISdLQrjQ/w640-h416/see_right_up.png" width="640" /></a></div><br />今回設定したいのは「CFG-NMEA-SVNUMBERING」なので、Categoryを「CFG-NMEA」にし、Keynameを「CFG-NMEA-SVNUMBERING」にします。<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiwn1_ygFU357sVyQSna_C1prMOPTV2u8x-ICLoVH4tR9jGnXbaOiove-gCN0oSJerXfVLc10-QSgo_YuY2HNImrJimeAyV7zuo9YI8UtekGi8dbmTj5Ch4z_g_QLtEqnadqHsRA1YbF50JgUTif1NCk6SOQpoH9CDYQZ5jNdsaALYP46jUjf6pL8JUdDM/s435/Screenshot%20from%202024-01-28%2021-51-39.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="202" data-original-width="435" height="298" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiwn1_ygFU357sVyQSna_C1prMOPTV2u8x-ICLoVH4tR9jGnXbaOiove-gCN0oSJerXfVLc10-QSgo_YuY2HNImrJimeAyV7zuo9YI8UtekGi8dbmTj5Ch4z_g_QLtEqnadqHsRA1YbF50JgUTif1NCk6SOQpoH9CDYQZ5jNdsaALYP46jUjf6pL8JUdDM/w640-h298/Screenshot%20from%202024-01-28%2021-51-39.png" width="640" /></a></div><br />Layerを「RAM」にして、トグルボタンを「CFG-VALGET」に合わせた状態で矢印ボタンを押すと、Valueに現在の値が表示されます。<br /><b>値が表示されない場合はpygnsclientが不具合を起こしている可能性があるので、pygnsclientを再起動してください。</b>(F9PのUSB抜き差しはしなくても直ることが多いです。)<br /><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjBF29IIZ88oD9Czw-V2glWp45ZMZUS61A7vqO9RqxVWhmcmAo8Hsx2Fe_7zvMSJHgpR6FnPzhwG9ys5QV0_YaXzTQc5e96FufXtGht8bvrx8H8_bCQJDKod8JcdT8HcP2szv9Rhl7ZdExBocVj50s_Qg0dde3RAbjwsoA7iycwjmHYiV4viSHPiWJqguo/s442/get_ram_value.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="367" data-original-width="442" height="532" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjBF29IIZ88oD9Czw-V2glWp45ZMZUS61A7vqO9RqxVWhmcmAo8Hsx2Fe_7zvMSJHgpR6FnPzhwG9ys5QV0_YaXzTQc5e96FufXtGht8bvrx8H8_bCQJDKod8JcdT8HcP2szv9Rhl7ZdExBocVj50s_Qg0dde3RAbjwsoA7iycwjmHYiV4viSHPiWJqguo/w640-h532/get_ram_value.png" width="640" /></a></div><br />現在の「CFG-NMEA-SVNUMBERING」が0だと分かりました。<br /><br /><h2 style="text-align: left;">一時的な設定変更はRAMを書き換える</h2>値を変えたい場合はトグルボタンを「CFG-VALSET」にして、Valueを書き換え、矢印ボタンを押すと変わります。<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgDeSc_wGXvVqYwkZZWmIg2CKvK7t4weg_XKo-BdvrM_jllm-eidBpU1-i59zhlMKN-ZIkgg0243bLI6C3F62KVtiVci2wyPIME-OrBLOteJjrlpfPHpjS3yIT1nqyeNQtfvZPJEvKkldYVIw1U1vt7Mdo78hVEGsaL64Ns29QaBYnqjsF9_OgaB7kTUj4/s442/set_ram_value.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="367" data-original-width="442" height="532" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgDeSc_wGXvVqYwkZZWmIg2CKvK7t4weg_XKo-BdvrM_jllm-eidBpU1-i59zhlMKN-ZIkgg0243bLI6C3F62KVtiVci2wyPIME-OrBLOteJjrlpfPHpjS3yIT1nqyeNQtfvZPJEvKkldYVIw1U1vt7Mdo78hVEGsaL64Ns29QaBYnqjsF9_OgaB7kTUj4/w640-h532/set_ram_value.png" width="640" /></a></div><br />書き換えた後にCFG-VALGETにして読み込むと、書き換え後の値を取得できます。<br />Layerが「RAM」の場合は、起動中のみ値が書き換わり、F9Pの電源を入れ直すと書き換え前の値に戻ります。<br /><br /><h2 style="text-align: left;">恒久的な設定変更はFLASHを書き換える(FLASHが無い設定もある)</h2>Layerとして「FLASH」を使える設定の場合はFLASHの値を書き換えると起動後のRAMの値がFLASHに書き込んだ値になります。<br />「CFG-NMEA-SVNUMBERING」は「FLASH」に対応しているため、Layerを「FLASH」にして、CFG-VALGETやCFG-VALSETが可能です。<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhg7iNBPEZAIFw5w6Jnxhw0ZrWojDhoondnSB01_4X2dxHPZJvFvOGUDzcmbu3w4dFCWd_0-mELdKLo7YlthMiYn66ICQ_L1Vf_vLOHGsBFQvBozJnPD9vNe7pDhO-MYM4G7WchAwbr-Z991CC3HyiOXEk-XDXjSSJ0JrJ-0SspWHMhnQIucFfU223p0x0/s442/get_flash_value.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="367" data-original-width="442" height="532" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhg7iNBPEZAIFw5w6Jnxhw0ZrWojDhoondnSB01_4X2dxHPZJvFvOGUDzcmbu3w4dFCWd_0-mELdKLo7YlthMiYn66ICQ_L1Vf_vLOHGsBFQvBozJnPD9vNe7pDhO-MYM4G7WchAwbr-Z991CC3HyiOXEk-XDXjSSJ0JrJ-0SspWHMhnQIucFfU223p0x0/w640-h532/get_flash_value.png" width="640" /></a></div><br />「CFG-NMEA-SVNUMBERING」の1つ上にある「CFG-NMEA-PORTVER」はFLASHに対応していないため、FLASHにしてCFG-VALGETを実施すると赤いびっくりマークが出て何も表示されません。<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjik90Zmw5ZR24T8xXOQ0oRyIFdthe6GDQ8PCLoBHHFBHdp9PDjo94lJSGoGcpNuUj8L9Yeuw4kZK6UHZMsjL0rX3Y4Xx4qTiPMLC6Zyyx_Jup0-VHBiPxxtihSSq3sJ_IgtfAHgAkE4wdGI2ocrY5cNhx1oI0ok0NKOLqso5GoWBGHxLIkUzLxETPkJUo/s442/Screenshot%20from%202024-01-28%2022-10-50.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="367" data-original-width="442" height="532" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjik90Zmw5ZR24T8xXOQ0oRyIFdthe6GDQ8PCLoBHHFBHdp9PDjo94lJSGoGcpNuUj8L9Yeuw4kZK6UHZMsjL0rX3Y4Xx4qTiPMLC6Zyyx_Jup0-VHBiPxxtihSSq3sJ_IgtfAHgAkE4wdGI2ocrY5cNhx1oI0ok0NKOLqso5GoWBGHxLIkUzLxETPkJUo/w640-h532/Screenshot%20from%202024-01-28%2022-10-50.png" width="640" /></a></div><br />CFG-NMEA-SVNUMBERINGを常時有効にしたいのでFLASHを1にします。<br />CFG-NMEA-SVNUMBERINGを選んだ状態で、Layerを「FLASH」にし、CFG-VALSETを選び、Valueを1にして矢印ボタンを押します。<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj5J_61kJwsZMKWVhlUiOi-w42EtR7nrjpFTWPatP_k8ExTSjNwT9JVZj4hIj8PD9c1KL1Sqp2AkhVR9YgDfJlFP-mAoBvaPAl_m_vb7eXuUVOkFKul2diVaQ-4HG-2120PSXYYVMIeRYisNTxM3g5UFEtcAnBNq1QafMXRxhyphenhyphen8TeQqJ_ts6fJNP7NuLS0/s442/set_flash_value.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="367" data-original-width="442" height="532" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj5J_61kJwsZMKWVhlUiOi-w42EtR7nrjpFTWPatP_k8ExTSjNwT9JVZj4hIj8PD9c1KL1Sqp2AkhVR9YgDfJlFP-mAoBvaPAl_m_vb7eXuUVOkFKul2diVaQ-4HG-2120PSXYYVMIeRYisNTxM3g5UFEtcAnBNq1QafMXRxhyphenhyphen8TeQqJ_ts6fJNP7NuLS0/w640-h532/set_flash_value.png" width="640" /></a></div><br />これによりCFG-NMEA-SVNUMBERINGが起動時から有効になり、みちびきの情報を利用可能になりました。<br /><br />CFG-NMEA-SVNUMBERINGのFLASHを1にする設定は、基地局用も移動局用もみちびきを利用するために、どちらのF9Pにも施すのが良いです。<br /><br /><h1 style="text-align: left;">ntripのserver + casterを起動</h1>ntripの基地局を起動します。<br />pygpsclientにはserverと同時にcasterを動かす仕組みがあるので、今回はそれを利用します。<br />どこかのcasterサーバーや、自分で立てたcasterサーバーを利用する場合は、Modeを「SOCKET SERVER」にして動かしてください。(しかしながら、SOCKET SERVERモードで Configure Base Stationを選べないのは不便なので、何かの手違いな気がします。)<br /><br />右下の表示のModeを「NTIRP CASTER」にします。<br />これを選ぶと表示情報が増えるので、スクロールバーを操作して下の方の情報を表示します。<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjanFt78-1sZoLaLsvgMKqvyRKq6rwAOT9uajTqNeYic1KJuaUrtKm1LJlXSSDtPoraqWVJBpOKKbsPXQJNuQypmnaLp0oUuSZ33v8W2ApLB-y5zLSPm9cfZW_6vKOGPeGwlIYsBp1mfTf57oM5Ku5LBQxPs2DLnpTTaoM8WhR3QyKsoiSEfEPC5BDAX2g/s384/select_ntrip_caster.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="209" data-original-width="384" height="348" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjanFt78-1sZoLaLsvgMKqvyRKq6rwAOT9uajTqNeYic1KJuaUrtKm1LJlXSSDtPoraqWVJBpOKKbsPXQJNuQypmnaLp0oUuSZ33v8W2ApLB-y5zLSPm9cfZW_6vKOGPeGwlIYsBp1mfTf57oM5Ku5LBQxPs2DLnpTTaoM8WhR3QyKsoiSEfEPC5BDAX2g/w640-h348/select_ntrip_caster.png" width="640" /></a></div><br />基地局の設定に合わせてF9Pの設定を書き換えてほしいので、Configure Base Station左側のチェックを有効にします。<br />また、手動で座標を指定したいので、Configure Base Stationを「FIXED」にします。<br />正確さが不要でとりあえずRTKを試したい場合はConfigure Base Stationを「SURVEY IN」にすればF9Pが単独で推測した位置情報が使われます。<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhZpHiZCasVDQLtSOPZyYOubEm4HU3oefwUhXaSyaVhzNwuzlar7Xpb8bXk23HegTpHUyKoWHYnpzusS2bRIXGtNaTPdybuufaJzJZESQY5jxpbfjdmHtMoSZ-iYXjm7nY8aJHCnh4jM-vjVNSzQ69jYZzE4R5XXIw-mSWcYC-SuJWMwMaGCqylbtnHiuI/s376/set_fixed.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="224" data-original-width="376" height="382" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhZpHiZCasVDQLtSOPZyYOubEm4HU3oefwUhXaSyaVhzNwuzlar7Xpb8bXk23HegTpHUyKoWHYnpzusS2bRIXGtNaTPdybuufaJzJZESQY5jxpbfjdmHtMoSZ-iYXjm7nY8aJHCnh4jM-vjVNSzQ69jYZzE4R5XXIw-mSWcYC-SuJWMwMaGCqylbtnHiuI/w640-h382/set_fixed.png" width="640" /></a></div><br />今回指定する座標は株式会社レグミンが入居している建物の駐車場の真ん中の車の上にします。<br />座標は大体<a href="https://www.google.com/maps/place/36%C2%B010'34.0%22N+139%C2%B017'34.3%22E/@36.1761024,139.2926526,21z/data=!4m4!3m3!8m2!3d36.1761111!4d139.2928611?entry=ttu">36.17609700, 139.29287333</a>です。<br />欲しい座標はgoogle mapで目星の場所を表示して右クリックすると出せます。<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgdsOv1AtGvyjQnLYn9bHbXai55yqKH6W57gB9DakEij8QtLkGZCap6iZssS7zahpy8F2sv4Ic3FJ5avJPYC3AoZmQv23AQCgDWzOlkRtB5WpM0Pax-3D24niPHzl0tvVPA-FWEazYC_i_bWsjcpVw6XdSyG9XOY8YptKerg1KgVEMABEmv9fwD3aRFHFQ/s387/Screenshot%20from%202024-01-28%2023-55-55.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="387" data-original-width="310" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgdsOv1AtGvyjQnLYn9bHbXai55yqKH6W57gB9DakEij8QtLkGZCap6iZssS7zahpy8F2sv4Ic3FJ5avJPYC3AoZmQv23AQCgDWzOlkRtB5WpM0Pax-3D24niPHzl0tvVPA-FWEazYC_i_bWsjcpVw6XdSyG9XOY8YptKerg1KgVEMABEmv9fwD3aRFHFQ/s320/Screenshot%20from%202024-01-28%2023-55-55.png" width="256" /></a></div><br />海抜は<a href="https://maps.gsi.go.jp/#5/36.104611/140.084556/&base=std&ls=std&disp=1&vs=c1g1j0h0k0l0u0t0z0r0s0m0f1">国土地理院の地図</a>情報からm単位で把握できます。<br />それによると、<a href="https://maps.gsi.go.jp/#18/36.176070/139.292808/&base=std&ls=std&disp=1&vs=c1g1j0h0k0l0u0t0z0r0s0m0f1">今回の場所の標高は約53m</a>と分かります。<br />車の上に基地局のアンテナを置くので、2m足してアンテナの位置は海抜55mとします。<br /><br />これはF9P内部処理の問題だと自分は思うのですが、設定したい高さを入力しても38mほど低い値になってしまいます。<br />これはNMEA GNGGAで示される「ジオイド高」という楕円体高から海抜高を引いた高さを扱う設定値(下記データのsep)があり、その値がF9Pの内部処理で固定した高さから引かれて結果の高さ(alt)になってしまいます。<br /><pre><NMEA(GNGGA, time=05:54:30, lat=36.176097, NS=N, lon=139.2928733333, EW=E, quality=2, numSV=12, HDOP=99.99, alt=55.0, altUnit=M, sep=38.5, sepUnit=M, diffAge=, diffStation=0)></pre>参考: <a href="https://ales-corp.co.jp/technical-information-nmea/">NMEAセンテンスについて</a><br /><br />これを補正するため、altの値分高くした値をアンテナの高さとして指定します。<br />今回の場合55mにしたいので、55+38.5 = 93.5 を固定の高さにします。<br />どなたか海抜高の適切な対応方法が分かる方がいらっしゃれば、コメント欄などで助言していただけると嬉しいです。<br /><br />ということで、上記の情報を入力します。<br />基準局が認識している座標を確認するため、最初は「Disable NMEA」は空欄にして動かすのが良いです。<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjKIVDoL0SH6EFKUvIVCsfH4DZCknh1iDyMYZVbd38JzYYLw1sqyfd0S6NZgPB3kt7EdjpQcSizdO2sYMG948yjYkmjdq0H29dC7m5i8f9U46Ud1CbiMUhzEomZgF6NwUHtN6HY206-l6Hgh2Hmi9zHqt-L4Q4emHFKZ2k7FMt9bpIt8Q4Q3C2JQ2IRyRg/s405/set_fixed_value.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="405" data-original-width="387" height="640" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjKIVDoL0SH6EFKUvIVCsfH4DZCknh1iDyMYZVbd38JzYYLw1sqyfd0S6NZgPB3kt7EdjpQcSizdO2sYMG948yjYkmjdq0H29dC7m5i8f9U46Ud1CbiMUhzEomZgF6NwUHtN6HY206-l6Hgh2Hmi9zHqt-L4Q4emHFKZ2k7FMt9bpIt8Q4Q3C2JQ2IRyRg/w612-h640/set_fixed_value.png" width="612" /></a></div><br />設定できたら「Socker Server / NTRIP Caster」を有効にするとserverとcasterが動きます。<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhOVm2bFIjDY6_KnmHvACH4qKyWqQLmajwK3nSo7I7-S5bql_5_h4D9BmJn1YDBTTVoUlNJQKfRR1ssNX74U9urwD6AOIJT4ofvQixwxvHXdQJyQzh_oSeW6hAhP-Z4pkENXNTtis_tafj9tCvx_RvI-JjgsU170y7u3aaUYzFuE0_P1XQsaK_OEJ2NUOU/s405/start_caster.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="405" data-original-width="387" height="640" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhOVm2bFIjDY6_KnmHvACH4qKyWqQLmajwK3nSo7I7-S5bql_5_h4D9BmJn1YDBTTVoUlNJQKfRR1ssNX74U9urwD6AOIJT4ofvQixwxvHXdQJyQzh_oSeW6hAhP-Z4pkENXNTtis_tafj9tCvx_RvI-JjgsU170y7u3aaUYzFuE0_P1XQsaK_OEJ2NUOU/w612-h640/start_caster.png" width="612" /></a></div><br />標準設定で動かしているので、接続情報はこうなります。<br />IP: PCのIP<br />Port: 2101<br />Mountpoint: pygnssutils<br />User: anon<br />Password: password<br /><br /><h1 style="text-align: left;">ntrip clientを起動</h1>今度はもう一台のF9Pをntripのclientとして動かし、RTKのFIXを狙います。<br />まず、コマンドを実行してpygpsclientをclient用に起動します。<br /><pre>pygpsclient</pre><br />ntrip serverとして使ってない方のF9Pに接続します。<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgJ_sZtA69BrATUq_igqUYRleAChEUiZn7l-yYOEsuG8EyQoHhEyFv3pDRHTEIDaBYmqu-Y2NHkDlvRrQVFocojStvTCqfluhnGbkPgZsfSxzO-32ZPUtIwaqHL8VrGZ0tY3Y7Lu6TyuyhB1kGIOf3pEMRkZ8Riw9g0oKVW8t6H_jpx2IkD4hrdYmr7sZg/s374/start_other_port.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="318" data-original-width="374" height="544" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgJ_sZtA69BrATUq_igqUYRleAChEUiZn7l-yYOEsuG8EyQoHhEyFv3pDRHTEIDaBYmqu-Y2NHkDlvRrQVFocojStvTCqfluhnGbkPgZsfSxzO-32ZPUtIwaqHL8VrGZ0tY3Y7Lu6TyuyhB1kGIOf3pEMRkZ8Riw9g0oKVW8t6H_jpx2IkD4hrdYmr7sZg/w640-h544/start_other_port.png" width="640" /></a></div><br />動かせたらntrip clientを選択してserverへの接続設定を行います。<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjYUt23sDJa5bxmhjg4NozCFy2jCErHaZ0JIvSAQHt45cGQjAobhQBQpvgmG9ictvNYyMO2xRC5w4pWFN69OLXeN97tpXwbDBBmZan-khKm9NefPAhZXIrmtGDkVhxw98TT4GCYa8Ux-oqGV1EuNq4smJBZ5HTllfaITtENnh21pYKU446f1I63YMH7osc/s627/select_ntrip_client.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="627" data-original-width="382" height="640" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjYUt23sDJa5bxmhjg4NozCFy2jCErHaZ0JIvSAQHt45cGQjAobhQBQpvgmG9ictvNYyMO2xRC5w4pWFN69OLXeN97tpXwbDBBmZan-khKm9NefPAhZXIrmtGDkVhxw98TT4GCYa8Ux-oqGV1EuNq4smJBZ5HTllfaITtENnh21pYKU446f1I63YMH7osc/w390-h640/select_ntrip_client.png" width="390" /></a></div><br />Server, Port, Mountpoint, User, Passwordを設定して接続ボタンを押します。<br />今回は同じPCでcasterを動かしているため、ServerのIPは0.0.0.0で良いです。<br />UserとPasswordはpygnssclientの標準値で既に入力済みです。<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgoGURmVAWQEZTz9RSRzTgeBlDqaJU3llFjLRRpRnR3ec81i1ArQjuU3AgpyI3yhQobe5OE6GkDrt1T6RhqW0ipHYoGl9G-H_YohfuQA_zfv2XejLprF8PRrkCXj-hBbDZYPIOaofx2rS5IejNfmHYflFhXPZEwFe0VmvgkDfqId0yi7w3HbHKqGFNmfNw/s596/start_ntrip_client.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="591" data-original-width="596" height="634" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgoGURmVAWQEZTz9RSRzTgeBlDqaJU3llFjLRRpRnR3ec81i1ArQjuU3AgpyI3yhQobe5OE6GkDrt1T6RhqW0ipHYoGl9G-H_YohfuQA_zfv2XejLprF8PRrkCXj-hBbDZYPIOaofx2rS5IejNfmHYflFhXPZEwFe0VmvgkDfqId0yi7w3HbHKqGFNmfNw/w640-h634/start_ntrip_client.png" width="640" /></a></div><br />接続するとConnectedとログが出ます。<br />右下のボタンや右上の閉じるを押しても、サーバーと切断することなく設定用の窓を閉じれます。<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiqA54cN9KvjLIE108S1qb60RKNgTRFMOA1lzShr9PJzv4a1CZc26vmtmzV-GW8MY_-4g_ZDWQ_MzoYGAnAOz7O9liWDAbgBNRt8zgiSstx8nFOGyyH0OQNaoMDLZ-vuSb0b_NUfrbb32dLWxACuHQGRHcel4NuNrJhvlLmCxbg1ErFEYh4f31L1HRK77M/s596/connected_to_ntrip_server.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="589" data-original-width="596" height="632" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiqA54cN9KvjLIE108S1qb60RKNgTRFMOA1lzShr9PJzv4a1CZc26vmtmzV-GW8MY_-4g_ZDWQ_MzoYGAnAOz7O9liWDAbgBNRt8zgiSstx8nFOGyyH0OQNaoMDLZ-vuSb0b_NUfrbb32dLWxACuHQGRHcel4NuNrJhvlLmCxbg1ErFEYh4f31L1HRK77M/w640-h632/connected_to_ntrip_server.png" width="640" /></a></div><br />pygpsclientの表示がRTK FIXEDになれば、RTKによる位置推定成功です。<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhJ9Hvy-Oo7U3OncJKWlLT7MyDmkNqXFpnYJDJKKSlRHx_VY4uzQ9ymVgaJDu9NSZ1XXfWGdSaJaDyNCx7px8YQOz-1Bq4HBlRKR_1dfBFkGogFEVOoudUl-SDiZzbsXXEIpd0-tuEuTlQaeN-AAM3JvqsHqh9rhwcut34KByDFhPH4JxdNmZd7vw_U7Gg/s816/Screenshot%20from%202024-01-28%2023-39-17.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="172" data-original-width="816" height="134" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhJ9Hvy-Oo7U3OncJKWlLT7MyDmkNqXFpnYJDJKKSlRHx_VY4uzQ9ymVgaJDu9NSZ1XXfWGdSaJaDyNCx7px8YQOz-1Bq4HBlRKR_1dfBFkGogFEVOoudUl-SDiZzbsXXEIpd0-tuEuTlQaeN-AAM3JvqsHqh9rhwcut34KByDFhPH4JxdNmZd7vw_U7Gg/w640-h134/Screenshot%20from%202024-01-28%2023-39-17.png" width="640" /></a></div><br /><h1 style="text-align: left;">位置推定できているか大まかに確認</h1>駐車場の車の上に基地局のアンテナを置き、車から数m離れたところに移動局のアンテナを置いてFIXEDの時の位置関係を見てみます。<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiNx9kAzU49xTkKjQ5EpG3647dgT6tEDJ6JBSVoPoblba-yXG7iWw24ikxBx9wthdrwPUgdv0gjY7AJ0JcyxZ9ddJiq0GX3GZ-1X19qWoEbHK4ev04oZtbO28nKKS8kKvBwC9rqaOUKhzzhaFMR98SRMNYQebU5LODd00gGe1bqbJAc0werHrHuADOq2zE/s3177/IMG_20240128_134148~3.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1666" data-original-width="3177" height="336" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiNx9kAzU49xTkKjQ5EpG3647dgT6tEDJ6JBSVoPoblba-yXG7iWw24ikxBx9wthdrwPUgdv0gjY7AJ0JcyxZ9ddJiq0GX3GZ-1X19qWoEbHK4ev04oZtbO28nKKS8kKvBwC9rqaOUKhzzhaFMR98SRMNYQebU5LODd00gGe1bqbJAc0werHrHuADOq2zE/w640-h336/IMG_20240128_134148~3.jpg" width="640" /></a></div><br />その時の結果がこちらです。<br /><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEglkRTjl1ijpQKeYR6XoUcyYK9UPLOqsL_xRa7ody3Ci1M8r_qsMzByWuKYw0wwilpOt9yoDPOQve7j3K1K-Jyyr-oTiESqVBbTCnxh3mscscqfsoM0MZBTbwUpGQsnlqdUZ3PIM_0FDAJk6Xu-3tjfp01zKY4QfAk5tQtcu7hHDnlcqqg64dfCPRRxpzU/s1920/Screenshot%20from%202024-01-28%2014-52-22.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1080" data-original-width="1920" height="360" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEglkRTjl1ijpQKeYR6XoUcyYK9UPLOqsL_xRa7ody3Ci1M8r_qsMzByWuKYw0wwilpOt9yoDPOQve7j3K1K-Jyyr-oTiESqVBbTCnxh3mscscqfsoM0MZBTbwUpGQsnlqdUZ3PIM_0FDAJk6Xu-3tjfp01zKY4QfAk5tQtcu7hHDnlcqqg64dfCPRRxpzU/w640-h360/Screenshot%20from%202024-01-28%2014-52-22.png" width="640" /></a></div><br />基地局<br />lat: 36.17609700<br />lon: 139.29287333<br />alt: 55.0<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhraW6rGdLK-DYTcQSvm4p9ciDC_JnU-FPnRiXIRDryJTpDhU-Ev_uMEvTwXvUqmcJ5tH8DCt8mg8LqAmSUdJ6WFU4sRbczf8zkTR_qxaOlJOZZWVTgsojMm73vVfS25BeItGEnrYNoXAoOaAdCHDKQcW_uaTaAbvpkT7GLZK0MSMqCWn59opZ7umeKZj4/s387/Screenshot%20from%202024-01-28%2023-53-04.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="387" data-original-width="310" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhraW6rGdLK-DYTcQSvm4p9ciDC_JnU-FPnRiXIRDryJTpDhU-Ev_uMEvTwXvUqmcJ5tH8DCt8mg8LqAmSUdJ6WFU4sRbczf8zkTR_qxaOlJOZZWVTgsojMm73vVfS25BeItGEnrYNoXAoOaAdCHDKQcW_uaTaAbvpkT7GLZK0MSMqCWn59opZ7umeKZj4/s320/Screenshot%20from%202024-01-28%2023-53-04.png" width="256" /></a></div><br />移動局<br />lat: 36.17613133<br />lon: 139.29287950<br />alt: 53.2<br /><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjKWUlmwkL0kg8D4VP_Ssi5Zbl8srmS5MPpyTCveFDl-J6XW4IWe1UNsb9_NIQBir5DEwEshh7MLkhiq3EkxZbgXza2xYnq0p38BDdhOYq2lo5YEUaMmfElkD-fT9VAMNjtIjgzbdiCdP304UfN5AFDzgOe1j3I_zSvudHgog0XxjuJo-mvGfaHwrBCpTo/s387/Screenshot%20from%202024-01-28%2023-53-02.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="387" data-original-width="310" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjKWUlmwkL0kg8D4VP_Ssi5Zbl8srmS5MPpyTCveFDl-J6XW4IWe1UNsb9_NIQBir5DEwEshh7MLkhiq3EkxZbgXza2xYnq0p38BDdhOYq2lo5YEUaMmfElkD-fT9VAMNjtIjgzbdiCdP304UfN5AFDzgOe1j3I_zSvudHgog0XxjuJo-mvGfaHwrBCpTo/s320/Screenshot%20from%202024-01-28%2023-53-02.png" width="256" /></a></div><br />移動局が建物側に数m近づき、高さは基地局に比べて1.8mほど低くなり、大体期待通りの位置を得られていました。<br /><br /><h1 style="text-align: left;">おわり</h1>ZED-F9P 2台とpygpsclientを利用してntripのserver(基準局)+caster(情報仲介サーバー)とclient(移動局)を起動し、clientでRTK FIXED状態の情報を取得して、それらしい位置情報を得られました。<br />pygpsclientは目下開発中なのか、serverをclient無しで動かそうとすると位置情報を固定する設定項目が消えたり、F9Pと通信できなくなるとプログラムの再起動が必要だったりと、不備や不具合らしき挙動を見かけましたが、ubuntuでRTKの仕組みをGUIを通して構築できて良かったです。<br /><br />この記事でGUIで行ったことをコマンド(CLI)で行う方法も解説しようと思いましたが、GUI専用で便利な処理が組まれていてコマンドで再現するには専用のpythonプログラムの作成が必要そうだったので、今回はGUIの操作方法の説明で終わります。<br /><br />ジオイド高によって固定した高さが下がってしまう問題の解決方法をご存知でしたら、コメント欄などでご助言いただけると嬉しいです。<br /><br /><h1 style="text-align: left;">参考</h1>pygpsclientのリポジトリです。<br /><a href="https://github.com/semuconsulting/PyGPSClient">pygpsclient</a><br /><br />参考にした農研機構のRTKの解説です。<br /><a href="https://www.pref.iwate.jp/agri/_res/projects/project_agri/_page_/002/006/815/01_rtk-gnss_manual.pdf">活用しよう! 農業で利用する 低コスト RTK-GNSS 導入マニュアル 2023年3月(Ver.1.00) 岩手県農業研究センター 生産基盤研究部生産システム研究室</a><br /><br />ZED-F9Pのファームウェアバージョン HPG 1.32の説明書です。<br /><a href="https://content.u-blox.com/sites/default/files/documents/u-blox-F9-HPG-1.32_InterfaceDescription_UBX-22008968.pdf">u-blox F9 HPG 1.32 u-blox F9 high precision GNSS receiver Interface Descriptio</a><br /><br />ファームウェア更新方法解説記事です。<br /><a href="https://www.geosense.co.jp/tech_firmware_verup/">ZED-F9Pファームウェアのバージョンアップ</a><br /><br />Asuki Konohttp://www.blogger.com/profile/07813182469285556500noreply@blogger.com0tag:blogger.com,1999:blog-9198372554518889060.post-65322819282018672472024-01-22T00:31:00.002+09:002024-01-27T11:55:35.852+09:00stm32マイコンの内蔵温度計を使う<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjR2i4rVk3YsPfc0oKJA-U8QKwH_zxha54sdCM9ZGPmeVCuYaDMOWUqhTu6G-VxESIZxFVbToAF3Qut-RWsf2fZKKrvD-UmUXFL2vdIj2ERLzgfRsqKxjo5YSkVAQHKcQMKlWW3sNNHW6hZ9OjhXNlyq5sGNRmynCOfGZ8xSsn3ypM1yj6kLkmIenX3rbs/s3071/IMG_20240121_234455.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="2616" data-original-width="3071" height="546" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjR2i4rVk3YsPfc0oKJA-U8QKwH_zxha54sdCM9ZGPmeVCuYaDMOWUqhTu6G-VxESIZxFVbToAF3Qut-RWsf2fZKKrvD-UmUXFL2vdIj2ERLzgfRsqKxjo5YSkVAQHKcQMKlWW3sNNHW6hZ9OjhXNlyq5sGNRmynCOfGZ8xSsn3ypM1yj6kLkmIenX3rbs/w640-h546/IMG_20240121_234455.jpg" width="640" /></a></div><br /><h1 style="text-align: left;">背景</h1>温度情報を取得したくてマイコンのADCを調べていたところ、STM32マイコンには温度計が内蔵されているものがあると把握しました。<br />備忘録として使い方を記事に残します。<br /><br /><h1 style="text-align: left;">使ったもの</h1><ul style="text-align: left;"><li>nucleo-l432kc<br />stm32l432kcが載ったnucleoという種類で展開されている開発ボードです。<br /></li><li>プログラムを書き込むPC<br />ubuntu22.04で動くPCを使いました。<br /></li><li>VSCode + platformio<br />プログラムを書いてビルドして書き込むプログラムです。<br /></li><li>USBケーブル<br />nucleo-l432kcのUSBポートはmicro Bなので、microB - AのUSBケーブルを利用しました。</li><li><a href="https://amzn.to/48FvHWl">気温計</a><br />マイコンが測定している温度との比較しました。<br /></li></ul><br /><h1 style="text-align: left;">stm32l432kcで温度を取得するプログラム全体像</h1>下記の処理でstm32l432kcの内部温度計を利用して温度を取得できます。<br />
<div class="pre-box"><div class="pre-name">platformio.ini</div>
<pre>[env:nucleo_l432kc]<br />platform = ststm32<br />framework = arduino<br />monitor_speed = 115200<br />board = nucleo_l432kc<br />upload_protocol = mbed<br />build_flags =<br /> -D ADC_SAMPLINGTIME=ADC_SAMPLETIME_640CYCLES_5<br /></pre>
</div>
<br /><div class="pre-box"><div class="pre-name">src/main.cpp</div>
<pre>#include <Arduino.h><br /><br />void setup() { Serial.begin(115200); }<br /><br />float voltToTemperature(float voltTemp, float voltAt30C) {<br /> return (voltTemp - voltAt30C) / 0.0025 + 30;<br />}<br /><br />float readVoltTempInternal() {<br /> auto adcTemp = analogRead(ATEMP);<br /> auto adcVref = analogRead(AVREF);<br /> const float voltVref = 1.2;<br /> return voltVref * adcTemp / adcVref;<br />}<br /><br />float getCal1VoltAt30C() {<br /> auto adcTempCal1 = *TEMPSENSOR_CAL1_ADDR;<br /> auto adcVrefCal = *VREFINT_CAL_ADDR;<br /> return 1.2 * adcTempCal1 / adcVrefCal;<br />}<br /><br />void loop() {<br /> auto voltTemp = readVoltTempInternal();<br /> auto voltAt30CDatasheet = 0.76;<br /> auto temperature = voltToTemperature(voltTemp, voltAt30CDatasheet);<br /> Serial.println("temperature without calibration " + String(temperature, 2) +<br /> " C");<br /> static const auto voltAt30CCal1 = getCal1VoltAt30C();<br /> auto temperatureWithCal1 = voltToTemperature(voltTemp, voltAt30CCal1);<br /> Serial.println(<br /> "temperature with calibration: " + String(temperatureWithCal1, 2) + " C");<br /> Serial.println("at " + String(millis()));<br /> delay(1000);<br />}<br /></pre>
</div>
<br />実行するとこのようなログを見れます。<pre>temperature without calibration 16.05 C<br />temperature with calibration: 21.61 C<br />at 19110</pre><br />プログラムの要所を解説します。<br /><br /><h1 style="text-align: left;">内蔵温度計の読み取りは5us必要なのでサンプリングサイクルを変更</h1><a href="https://www.st.com/resource/en/datasheet/stm32l432kc.pdf">マイコンstm32l432kcのデータシート</a>には内蔵温度計の読み取りには5us(マイクロ秒)が必要と記載されています。<br /><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh6-BKoojTSkAYzkxgoMtphvMCBRf5kdwGXL0evgaiKHjYUH-OaFSJrcaimVDyq4GItyqH77qXEJpybO1iTwZPqD2auBHM1Ebt1nrqR7Aux2y7qPbT7scI0wR-6nDcD2a0zAuM33QJi4OrWQc5OG8fFQDju0Mt506MEQetgibR_fnp7cT6vFRCbdKIb09I/s793/5us_is_needed_for_internal_temperature_sensor.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="327" data-original-width="793" height="264" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh6-BKoojTSkAYzkxgoMtphvMCBRf5kdwGXL0evgaiKHjYUH-OaFSJrcaimVDyq4GItyqH77qXEJpybO1iTwZPqD2auBHM1Ebt1nrqR7Aux2y7qPbT7scI0wR-6nDcD2a0zAuM33QJi4OrWQc5OG8fFQDju0Mt506MEQetgibR_fnp7cT6vFRCbdKIb09I/w640-h264/5us_is_needed_for_internal_temperature_sensor.png" width="640" /></a></div><br />また、本プログラムで利用する内部参照電圧も読み取りに4us必要と記載されています。<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhPgZbRh0jrKDYo6rwjI7sda7spiU0kTjlIX2EXCkqqSRMKOVciu8zK68zNmcHnBvM8bfClyT_Ju0KejFz-r0IWt4ojOS_RbNqNpoUh1VV2GMAO15ZDSrh7t0qSma2MT-vJhX2mU8jBKCVU2JKt8cJECU4Se5CJuTjfHhCQUZ3XEugPa6QrOMceRde96W0/s713/4us_is_needed_for_internal_voltage_reference.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="151" data-original-width="713" height="136" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhPgZbRh0jrKDYo6rwjI7sda7spiU0kTjlIX2EXCkqqSRMKOVciu8zK68zNmcHnBvM8bfClyT_Ju0KejFz-r0IWt4ojOS_RbNqNpoUh1VV2GMAO15ZDSrh7t0qSma2MT-vJhX2mU8jBKCVU2JKt8cJECU4Se5CJuTjfHhCQUZ3XEugPa6QrOMceRde96W0/w640-h136/4us_is_needed_for_internal_voltage_reference.png" width="640" /></a></div><br />ということで、80MHzの12bit読み取り環境で4us以上を確保できるのは、設定可能最大の640.5サイクル時の約8usなので、サンプリングサイクルをその640.5に設定します。<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhGOO7z0zPEaZG-6HnqVHWU3jaoKo234zy9mv6q8UTJHk-k8xvu6icrhfMjggnKqxOtn2zhRi0rG8fZQU-34fRm6E6wQmtKIfeb56Q0Ta8CVWyum3X53inpCtDZnPN2Qi-DjrsljlOqdF9IC16RKw_CaMcXFyWI0aqr8gYat700XvR_MfCDtFxmHmD3CUs/s712/640p5_for_8us.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="298" data-original-width="712" height="268" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhGOO7z0zPEaZG-6HnqVHWU3jaoKo234zy9mv6q8UTJHk-k8xvu6icrhfMjggnKqxOtn2zhRi0rG8fZQU-34fRm6E6wQmtKIfeb56Q0Ta8CVWyum3X53inpCtDZnPN2Qi-DjrsljlOqdF9IC16RKw_CaMcXFyWI0aqr8gYat700XvR_MfCDtFxmHmD3CUs/w640-h268/640p5_for_8us.png" width="640" /></a></div><br />Arduino Core STM32は<a href="https://asukiaaa.blogspot.com/2023/02/change-sampling-time-of-stm32arduino.html">ADC_SAMPLINGTIMEマクロをbuild_flagに指定してサンプリングサイクルを変えれます</a>。<br />
<div class="pre-box"><div class="pre-name">platformio.ini</div>
<pre>build_flags =<br /> -D ADC_SAMPLINGTIME=ADC_SAMPLETIME_640CYCLES_5<br /></pre>
</div>
<br />上記の設定で8usでアナログ読み取りを行えます。<br /><br /><h1 style="text-align: left;">温度センサと内部参照電圧の読み取り値を組み合わせて(補正していない)温度センサの電圧を取得</h1><a href="https://www.stmcu.jp/technical/hint/no-037/">stm32の内部参照電圧は1.2V</a>なので、その測定値を利用して下記の処理で温度センサの電圧を算出します。<br />これにより、動作電圧に関係なく内部温度を算出できます。<br /><pre>float readVoltTempInternal() {<br /> auto adcTemp = analogRead(ATEMP);<br /> auto adcVref = analogRead(AVREF);<br /> const float voltVref = 1.2;<br /> return voltVref * adcTemp / adcVref;<br />}<br /></pre><br /><h1 style="text-align: left;">補正情報から30℃のときの電圧を算出</h1><a href="https://www.st.com/resource/en/datasheet/stm32l432kc.pdf">stm32l432kc</a>には30℃のとき温度センサと内部参照電圧のadc読み取り値が補正情報としてマイコンに保存されています。<br /><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh8Fzt9hrIbhUcOaYzDof-pBxs6tod69bRHFXSaSo50I_8gdUXVv6EL9Tm0_vNb7GrEBLDA88ArVnUi0lTqCkpjMkyYMnrpDFnqQcsocmlUONeRyr5pNpA4kN6qEp7I6duydVEG5gE8EXaokktANRRO0nUvxnDxkIZ1MFHc06aI6QxPEnpocklpIMS-kSw/s628/Screenshot%20from%202024-01-21%2023-53-21.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="187" data-original-width="628" height="190" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh8Fzt9hrIbhUcOaYzDof-pBxs6tod69bRHFXSaSo50I_8gdUXVv6EL9Tm0_vNb7GrEBLDA88ArVnUi0lTqCkpjMkyYMnrpDFnqQcsocmlUONeRyr5pNpA4kN6qEp7I6duydVEG5gE8EXaokktANRRO0nUvxnDxkIZ1MFHc06aI6QxPEnpocklpIMS-kSw/w640-h190/Screenshot%20from%202024-01-21%2023-53-21.png" width="640" /></a></div><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiwSHFXOtHyoC8D084NQR0_vv8Ypiv5lVc9i-STcnTl6SuRZQXRZeinO1WGF5oPu2ecIgFUfw9JxnWu8eWYg3Uw79iQLxApFz_9fZWVyUfpCA4SV6HlcRa6igrByz9IE-jv0HbG2IMBlajB55Golpn1HZ89cmEidL4S2tF9Tdw7GeAEsggX8-fnqot9i08/s628/Screenshot%20from%202024-01-21%2023-53-30.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="126" data-original-width="628" height="128" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiwSHFXOtHyoC8D084NQR0_vv8Ypiv5lVc9i-STcnTl6SuRZQXRZeinO1WGF5oPu2ecIgFUfw9JxnWu8eWYg3Uw79iQLxApFz_9fZWVyUfpCA4SV6HlcRa6igrByz9IE-jv0HbG2IMBlajB55Golpn1HZ89cmEidL4S2tF9Tdw7GeAEsggX8-fnqot9i08/w640-h128/Screenshot%20from%202024-01-21%2023-53-30.png" width="640" /></a></div><br />Arduino Core STM32では「TEMPSENSOR_CAL1_ADDR」と「VREFINT_CAL_ADDR」でそれぞれ呼び出し可能なので、それから補正時の30℃のときの温度センサの電圧を算出します。<br /><pre>float getCal1VoltAt30C() {<br /> auto adcTempCal1 = *TEMPSENSOR_CAL1_ADDR;<br /> auto adcVrefCal = *VREFINT_CAL_ADDR;<br /> return 1.2 * adcTempCal1 / adcVrefCal;<br />}<br /></pre><br /><h1 style="text-align: left;">マイコンの仕様に合わせて電圧から温度を算出</h1><a href="https://www.st.com/resource/en/datasheet/stm32l432kc.pdf">stm32l432kc</a>のセンサ情報を見ると、温度センサの誤差は±5℃、2.7mVごとに1℃変化し、30℃のときに0.76Vと分かります。<br />この30℃のときの電圧は、先程算出した補正情報を利用可能です。<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhmAvDSWsBsD8kfED1h5CYbcLyGP3FvSBT-3mKNayivr2Ob9tEsE9ljAbrDu2iahmXt8De9e_jp_L7zygCNQdQaSSc6bzSHHeBKBdwkwTyVeqc-vlMfHCHSO4PABx8PqddI1QiaiffyB0QYCgLIB2cUg3kw7plM5r_cRmCXtqCZ8oPJO_y4wlfdfhnzqpY/s794/temperature_sensor_info.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="443" data-original-width="794" height="358" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhmAvDSWsBsD8kfED1h5CYbcLyGP3FvSBT-3mKNayivr2Ob9tEsE9ljAbrDu2iahmXt8De9e_jp_L7zygCNQdQaSSc6bzSHHeBKBdwkwTyVeqc-vlMfHCHSO4PABx8PqddI1QiaiffyB0QYCgLIB2cUg3kw7plM5r_cRmCXtqCZ8oPJO_y4wlfdfhnzqpY/w640-h358/temperature_sensor_info.png" width="640" /></a></div><br />比較として、データシートに示される30℃のときの電圧と、補正情報から算出した電圧それぞれを利用して温度センサの温度を算出しました。<br /><pre>float voltToTemperature(float voltTemp, float voltAt30C) {<br /> return (voltTemp - voltAt30C) / 0.0025 + 30;<br />}<br /><br />void loop() {<br /> auto voltTemp = readVoltTempInternal();<br /> auto voltAt30CDatasheet = 0.76;<br /> auto temperature = voltToTemperature(voltTemp, voltAt30CDatasheet);<br /> Serial.println("temperature without calibration " + String(temperature, 2) +<br /> " C");<br /> static const auto voltAt30CCal1 = getCal1VoltAt30C();<br /> auto temperatureWithCal1 = voltToTemperature(voltTemp, voltAt30CCal1);<br /> Serial.println(<br /> "temperature with calibration: " + String(temperatureWithCal1, 2) + " C");<br /> Serial.println("at " + String(millis()));<br /> delay(1000);<br />}<br /></pre><br /><h1 style="text-align: left;">余談: 精度±5℃のセンサの補正が5℃を超えていて良いだろうか</h1>ログを見ると、今回利用したマイコンは5.6℃増える補正がされていると分かります。<br /><pre>temperature without calibration 16.05 C<br />temperature with calibration: 21.61 C<br />at 19110</pre><br />温度センサの仕様に±5℃とあるものの、補正が5℃を超えていて良いのか疑問です。<br /><br /><h1 style="text-align: left;">余談: 起動後5分で約5℃温度が上がった</h1>プログラムを書き込んで10秒ほど観察する間は、補正後の温度は気温計と1℃未満の精度で期待通りの温度です。<br /><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjR2i4rVk3YsPfc0oKJA-U8QKwH_zxha54sdCM9ZGPmeVCuYaDMOWUqhTu6G-VxESIZxFVbToAF3Qut-RWsf2fZKKrvD-UmUXFL2vdIj2ERLzgfRsqKxjo5YSkVAQHKcQMKlWW3sNNHW6hZ9OjhXNlyq5sGNRmynCOfGZ8xSsn3ypM1yj6kLkmIenX3rbs/s3071/IMG_20240121_234455.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="2616" data-original-width="3071" height="546" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjR2i4rVk3YsPfc0oKJA-U8QKwH_zxha54sdCM9ZGPmeVCuYaDMOWUqhTu6G-VxESIZxFVbToAF3Qut-RWsf2fZKKrvD-UmUXFL2vdIj2ERLzgfRsqKxjo5YSkVAQHKcQMKlWW3sNNHW6hZ9OjhXNlyq5sGNRmynCOfGZ8xSsn3ypM1yj6kLkmIenX3rbs/w640-h546/IMG_20240121_234455.jpg" width="640" /></a></div><br />しかしながら、5分ほどプログラムを動かし続けると5℃以上温度が上昇し、補正前の測定値すら温度計の値を超えます。<br />10分経過しても同じような温度だったので、起動後約5分で発熱と放熱が均衡しました。<br /><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgGjksLMcowdJC1DpcPuIIsXUivKebTLsjFPfT4EsRawTR-80j6QiiKxQLh6MJNELQv_cXC4pAB6HNxhRS0eZkooKncRYJIcj6h89_g-vp5O-PR7tvbdSJXR3fyCWdfNFf0lyrtwlDp83aSwt0xNCuW8OysMhFB6CtaoFv_y3Xe18qDyxLlsD6vuTo6Zzc/s2727/IMG_20240121_235616.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="2487" data-original-width="2727" height="584" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgGjksLMcowdJC1DpcPuIIsXUivKebTLsjFPfT4EsRawTR-80j6QiiKxQLh6MJNELQv_cXC4pAB6HNxhRS0eZkooKncRYJIcj6h89_g-vp5O-PR7tvbdSJXR3fyCWdfNFf0lyrtwlDp83aSwt0xNCuW8OysMhFB6CtaoFv_y3Xe18qDyxLlsD6vuTo6Zzc/w640-h584/IMG_20240121_235616.jpg" width="640" /></a></div><br />起動後やdeep sleep復帰後は補正後の値を信用して良さそうですが、起動し続ける場合は5℃の変化を許容するか、サーミスタを外付けするなどして温度を扱うのが良さそうです。<br /><br /><h1 style="text-align: left;">おわり</h1>補正情報と内部参照電圧を利用して、stm32l432kcマイコンに内蔵されている温度計から温度情報を算出できました。<br />しかしながら、プログラムを動かし続けると5℃ほど測定値が上がったので、deep sleepを利用せず長時間マイコンを動かす用途では5℃の変化を許容するか外部にサーミスタなどの対応が必要そうでした。<br /><br /><h1 style="text-align: left;">参考</h1>今回利用したマイコンのデータシートです。<br /><a href="https://www.st.com/resource/en/datasheet/stm32l432kc.pdf">stm32l432kc</a><br /><br />st公式の開発のヒントページです。<br /><a href="https://www.stmcu.jp/technical/hint/no-039/">内蔵温度センサ</a><br /><a href="https://www.stmcu.jp/technical/hint/no-037/">VDDA(Vref+)の電圧値をADコンバータで測定する</a><br /><br />以前取り組んだサンプリングレート変更方法です。<br /><a href="https://asukiaaa.blogspot.com/2023/02/change-sampling-time-of-stm32arduino.html"> STM32Arduinoのアナログ読み取り間隔はADC_SAMPLINGTIMEマクロで変更可能 </a><br /><br />Asuki Konohttp://www.blogger.com/profile/07813182469285556500noreply@blogger.com2tag:blogger.com,1999:blog-9198372554518889060.post-39446331014955953102024-01-14T20:55:00.014+09:002024-01-16T10:25:14.556+09:00LovyanGFXでArduino環境向けに作った画面表示プログラムの動作確認をPC上で実施<div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgBQTLY_sfHbPf7IaV_fEqeX9q0RL8tSYCh1LkYkzGynfCPQJR1aNiVfLGzuJXIVP2wBXJUEwe66dGe9YjvxH_02SqV-rczPw93fgNCiU0mjiKgwtpy-BekSTYpXcTnVlmYLlQMloBZXpL6504y766Zo9YUq5nWQzEPi2MkaUz2oupWRwZauSAS_TLaECs/s3742/IMG_20240114_131224.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="2338" data-original-width="3742" height="200" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgBQTLY_sfHbPf7IaV_fEqeX9q0RL8tSYCh1LkYkzGynfCPQJR1aNiVfLGzuJXIVP2wBXJUEwe66dGe9YjvxH_02SqV-rczPw93fgNCiU0mjiKgwtpy-BekSTYpXcTnVlmYLlQMloBZXpL6504y766Zo9YUq5nWQzEPi2MkaUz2oupWRwZauSAS_TLaECs/s320/IMG_20240114_131224.jpg" width="320" /></a></div><br /><h1 style="text-align: left;">背景</h1>LovyanGFXとはlovyanさんが作っているLCD制御プログラムです。<br />それにはplatformioのnative環境で動かしてpc上で動作確認する仕組みがあるため使ってみました。<br /><br />
<blockquote class="twitter-tweet"><p dir="ltr" lang="ja">おお…Windows上でもVSCode+PlatformIOネイティブビルドでデバッガ動いた… <a href="https://t.co/v7OeAGXs1y">pic.twitter.com/v7OeAGXs1y</a></p>— らびやん (@lovyan03) <a href="https://twitter.com/lovyan03/status/1741623266345623899?ref_src=twsrc%5Etfw">January 1, 2024</a></blockquote> <script async="" charset="utf-8" src="https://platform.twitter.com/widgets.js"></script>
<br />いくつか詰まりどころがあったので、備忘録として記事を残します。<br /><br /><h1 style="text-align: left;">何が嬉しいか?: main.cpp書き換え後にビルドして動作するまでの時間がnativeの方が短い</h1>ライブラリがビルドされた状態でmainだけ書き換えて再実行する場合、実行されるまでの時間がnativeの方が短いため試行錯誤の速度を上げれます。<br />なお、Arduinoでもnativeでも初回はライブラリを含んだビルドが走るので自分の環境だとどちらも1分前後かかります。<br /><br />Arduino環境だと約23秒(ビルド約8秒、書き込み約15秒)<br />native環境だと約8秒(ビルド約8秒、書き込み1秒未満)<br /><br />デバッガも使えるようですが、この記事では表示内容の確認だけを解説します。<br /><br /><h1 style="text-align: left;">参考にした公式の情報</h1>LovyanGFX公式のSDLを利用するサンプルプロジェクトです。<br /><a href="https://github.com/lovyan03/LovyanGFX/tree/master/examples_for_PC/PlatformIO_SDL">https://github.com/lovyan03/LovyanGFX/tree/master/examples_for_PC/PlatformIO_SDL</a><br /><br />記事の末尾でも再度共有します。<br /><br /><h1 style="text-align: left;">使ったもの</h1><ul style="text-align: left;"><li>ubuntuをインストールしたPC<br />ubuntu22.04をインストールしたものを利用しました。</li><li>LovyanGFXやM5GFXを利用するplatformioのArduino向けプロジェクト<br />今回はAtomDisplayとfull HDモニタを組み合わせて動かすプログラムを使いました。</li><li>上記プログラム動作確認用実機<br /><a href="https://www.switch-science.com/products/7592?_pos=1&_sid=ea8f9e627&_ss=r">AtomDisplay</a>と<a href="https://amzn.to/48No3sK">13.3インチのfull HDモニタ</a>を使いました。<br />(モニタによってはAtomDisplayのfull HDモードのリフレッシュレートが不十分で動かない場合があります。)<br /></li></ul><br /><h1 style="text-align: left;">ubuntuで動かすためのライブラリをインストール</h1><a href="https://github.com/lovyan03/LovyanGFX/tree/master/examples_for_PC/PlatformIO_SDL">サンプルプログラムのREADME</a>で解説されている通り、platformioのnative環境ビルド用のライブラリと、LovyanGFXを利用したPC上での画像描画ライブラリをインストールします。<br /><pre>sudo apt update<br />sudo apt install -y build-essential libsdl2 libsdl2-dev</pre><br />macやwindowsを利用される方はREADMEのそれ向けの箇所を参照してください。<br /><a href="https://github.com/lovyan03/LovyanGFX/tree/master/examples_for_PC/PlatformIO_SDL"> LovyanGFX/examples_for_PC/PlatformIO_SDL</a><br /><br /><h1 style="text-align: left;">プロジェクト全体</h1>全体を共有してから要所を解説します。<br />このプロジェクトはgithubに上げています。<br /><a href="https://github.com/asukiaaa/pio-lovyangfx-sdl-on-pc-practice">https://github.com/asukiaaa/pio-lovyangfx-sdl-on-pc-practice</a><br /><br />
<div class="pre-box"><div class="pre-name">platformio.ini</div>
<pre>[platformio]<br />default_envs = native<br />; default_envs = m5stack-atom<br /><br />[env:native]<br />platform = native<br />lib_deps =<br /> LovyanGFX<br /> ArduinoFake<br /> string_asukiaaa<br />lib_compat_mode = off<br />build_flags =<br /> -DUSE_NATIVE<br /> -O0 -xc++ -std=c++14<br /> -lSDL2<br /> -I"/usr/local/include/SDL2" ; for intel mac homebrew SDL2<br /> -L"/usr/local/lib" ; for intel mac homebrew SDL2<br /> -I"${sysenv.HOMEBREW_PREFIX}/include/SDL2" ; for arm mac homebrew SDL2<br /> -L"${sysenv.HOMEBREW_PREFIX}/lib" ; for arm mac homebrew SDL2<br /><br />[env:m5stack-atom]<br />platform = espressif32<br />board = m5stack-atom<br />framework = arduino<br />monitor_speed = 115200<br />lib_deps =<br /> M5GFX<br /> string_asukiaaa<br />board_build.partitions = no_ota.csv<br /></pre>
</div>
<br />
<div class="pre-box"><div class="pre-name">src/main.cpp</div>
<pre>#ifdef USE_NATIVE<br />#define LGFX_AUTODETECT<br />#include <LovyanGFX.h><br /><br />#include <LGFX_AUTODETECT.hpp><br />#else<br />#include <M5AtomDisplay.h><br />#endif<br /><br />#include <Arduino.h><br />#include <string_asukiaaa.h><br />#include <unistd.h><br /><br />#include <iostream><br /><br />#if defined(USE_NATIVE)<br />static LGFX lcd(1080, 1920, 2);<br />#else<br />M5AtomDisplay lcd(1920, 1080);<br />#endif<br /><br />void setup() {<br /> lcd.init();<br />#ifndef USE_NATIVE<br /> lcd.setRotation(0);<br />#endif<br /> lcd.setTextSize(8);<br /> lcd.setTextColor(TFT_WHITE, TFT_BLACK);<br />}<br /><br />void loop() {<br />#ifdef USE_NATIVE<br /> auto seconds = time(NULL);<br />#else<br /> auto seconds = millis() / 1000;<br />#endif<br /> lcd.setCursor(0, 0);<br /> lcd.println("top left");<br /> lcd.print("string test ");<br /> lcd.println(string_asukiaaa::padStart("abcd", 10, '-').c_str());<br /> lcd.println(("at " + String(seconds)).c_str());<br /> lcd.drawRightString("bottom right", lcd.width(),<br /> lcd.height() - lcd.fontHeight());<br />#ifdef USE_NATIVE<br /> sleep(1);<br />#else<br /> delay(1000);<br />#endif<br />}<br /><br />#if defined(USE_NATIVE)<br />int user_func(bool* running) {<br /> setup();<br /> do {<br /> loop();<br /> } while (*running);<br /> return 0;<br />}<br /><br />int main(int, char**) { return lgfx::Panel_sdl::main(user_func); }<br />#endif<br /></pre></div><br />上記のプログラムを実機で動かした様子はこちらです。<br /><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgIGjQWgH84Ee2bXIlLfEx2-83fF4UfZjtXf9LTTtGUMpmijMoWrRKOsqSEApRnT39xcGJ4aN4CxkXlZbI9ilBfW5coym0akG0wf__7Fla8Do2UX8xYP_cpZLU-eswSJDO1UeFJMXSbg8EyEqImh21XW5rzqFlAOKUcjPHIhRSmsLLnRMC_KQ8UXCzjZT8/s2705/IMG_20240114_194302.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="2705" data-original-width="1833" height="640" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgIGjQWgH84Ee2bXIlLfEx2-83fF4UfZjtXf9LTTtGUMpmijMoWrRKOsqSEApRnT39xcGJ4aN4CxkXlZbI9ilBfW5coym0akG0wf__7Fla8Do2UX8xYP_cpZLU-eswSJDO1UeFJMXSbg8EyEqImh21XW5rzqFlAOKUcjPHIhRSmsLLnRMC_KQ8UXCzjZT8/w434-h640/IMG_20240114_194302.jpg" width="434" /></a></div><br />native環境で動かした様子はこちらです。<br />何故か横広全画面で描画されてしまうので、全画面を解いて大きさの調整が必要です。<br /><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjpgPTB6SRP0LuqUOtuFgomS0icdSaQgaPSmR0FmiCqLKUUlbmz_1yf77DyzegBVCRHgi2QF59gUpHknYUrQs9wMAW2JnIqnIQDBFtIoo6r5mg47D00gbUyNmB7VW_NiHbg_4eNzVzWkTjkOWOdRoDdc5oK24wE2sSIU4Na76cxnpeH21ASFKaoAdUi6qA/s1920/Screenshot%20from%202024-01-14%2019-44-28.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1080" data-original-width="1920" height="360" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjpgPTB6SRP0LuqUOtuFgomS0icdSaQgaPSmR0FmiCqLKUUlbmz_1yf77DyzegBVCRHgi2QF59gUpHknYUrQs9wMAW2JnIqnIQDBFtIoo6r5mg47D00gbUyNmB7VW_NiHbg_4eNzVzWkTjkOWOdRoDdc5oK24wE2sSIU4Na76cxnpeH21ASFKaoAdUi6qA/w640-h360/Screenshot%20from%202024-01-14%2019-44-28.png" width="640" /></a></div><br />全画面を解いて大きさを調整した後の様子です。<br /><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiw-z5oAIuhjSR6cEFy3hrP9UR2v_cyKzY9XO9_tM1bbDt8uQhiZFc9GUXwgxsd93Xxk8AraW3anljyitQ7_5bpws5LoKC-xAuW7YDtJn8MPQle2fCO_VkrCv5kysxJyWBcu3MVwGrqWQZ1MQCYyL5rrGN1VZvXUuxND1iOzv2-okNRMrPu8GhkHYhPvk8/s800/Screenshot%20from%202024-01-14%2019-45-15.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="800" data-original-width="511" height="640" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiw-z5oAIuhjSR6cEFy3hrP9UR2v_cyKzY9XO9_tM1bbDt8uQhiZFc9GUXwgxsd93Xxk8AraW3anljyitQ7_5bpws5LoKC-xAuW7YDtJn8MPQle2fCO_VkrCv5kysxJyWBcu3MVwGrqWQZ1MQCYyL5rrGN1VZvXUuxND1iOzv2-okNRMrPu8GhkHYhPvk8/w408-h640/Screenshot%20from%202024-01-14%2019-45-15.png" width="408" /></a></div><br /><h1 style="text-align: left;">pc上での描画ライブラリ SDL2を有効化</h1>関連ライブラリの解説でインストールしたSDL2をplatformio.iniのbuild flagsとして-lで利用を宣言します。<br />macの場合はパスの指定が必要なようですが、ubuntuの場合は-lオプションだけでSDL2が利用可能になります。<br /><pre>[env:native]<br />build_flags =<br /> -lSDL2<br /></pre><br /><h1 style="text-align: left;">lcdの定義をLovyanGFX向けに置き換え</h1>AtomDisplayはLGFX_AUTODETECTで判別できないようなので、USE_NATIVEというnative環境のときだけ有効になるマクロを定義し、ライブラリの読み込みや変数の定義を切り替えています。<br /><pre>[env:native]<br />lib_deps =<br /> LovyanGFX<br />build_flags =<br /> -DUSE_NATIVE<br /><br />[env:m5stack-atom]<br />lib_deps =<br /> M5GFX</pre><br /><pre>#ifdef USE_NATIVE<br />#define LGFX_AUTODETECT<br />#include <LovyanGFX.h><br /><br />#include <LGFX_AUTODETECT.hpp><br />#else<br />#include <M5AtomDisplay.h><br />#endif<br /></pre><br /><pre>#if defined(USE_NATIVE)<br />static LGFX lcd(1080, 1920, 2);<br />#else<br />M5AtomDisplay lcd(1920, 1080);<br />#endif<br /></pre><br /></div><h1 style="text-align: left;">native環境LovyanGFXx向けのmain関数を準備</h1>native環境はsetupとloop関数ではなくPC上で動くcppプログラムと同様にmain関数で動きます。<br />関数をLovyanGFXのPanel_sdl::mainに渡すと画面描画処理を継続してくれる仕組みになっているので、必要な処理で関数を組み立ててmain関数内で渡します。<br /><pre>#if defined(USE_NATIVE)<br />int user_func(bool* running) {<br /> setup();<br /> do {<br /> loop();<br /> } while (*running);<br /> return 0;<br />}<br /><br />int main(int, char**) { return lgfx::Panel_sdl::main(user_func); }<br />#endif<br /></pre><br />今回のプロジェクトではsetupもloopもnativeでほぼ動く内容なのでそれらの関数を使っていますが、arduino向けに作り込んでいてそのままの利用が困難な場合はsetupとloopは使わず画面の描画関係の処理だけで関数を組み立ててPanel_sdl::mainに渡すのが良いです。<br /><br /><div><h1 style="text-align: left;">Stringクラスなどを利用したい場合はArduinoFakeを関連ライブラリに設定</h1>lib_depsに<a href="https://github.com/FabioBatSilva/ArduinoFake">ArduinoFake</a>を設定するとStringやWireを呼び出せる状態になります。<br /><pre>[env:native]<br />platform = native<br />lib_deps =<br /> ArduinoFake<br /></pre><br />注意点としてLovyanGFXをincludeした後にArduino.hのincludeが必要です。<br />Arduino.hを先にincludeするとLovyanGFXが大量のエラーを出してビルドできません。<br /><pre>#ifdef USE_NATIVE<br />#include <LovyanGFX.h><br />#endif<br /><br />#include <Arduino.h><br /></pre><br />LovyanGFXはStringを利用しないnative状態で読み込まれるため、Stringを利用している呼び出しは「.c_str()」を付けてcharの配列を引数として渡す必要があります。<br /><pre> lcd.println(("at " + String(seconds)).c_str());<br /></pre><br /><h1 style="text-align: left;">native環境向けでないライブラリを使う場合は、lib_compat_modeを無効化</h1>ArduinoFakeを利用することでArduinoの基本機能は呼び出せる状態にできましたが、platformio向けの設定ファイルlibraries.jsonをライブラリに含みつつnative環境に対応していると明記しているライブラリでないとlib_depsで指定してもファイルが見つからずビルドが失敗します。<br /><br />その場合はlib_compat_modeを無効化すると、nativeに対応しているか否かに関わらずライブラリを取り込んでビルドしてくれます。<br /><pre>[env:native]<br />lib_deps =<br /> ArduinoFake<br /> string_asukiaaa<br />lib_compat_mode = off<br /></pre><br />上記の設定で取り込んでいる<a href="https://github.com/asukiaaa/arduino-string">string_asukiaaa</a>というライブラリは記事を書いている時点で最新版の1.0.4はlibraries.jsonが無いためplatformioがnative環境に対応していないと判断しますが、lib_compat_modeを無効化することで使えました。<br /><br />参考<br /><a href="https://community.platformio.org/t/unrecognized-library-in-native-environment/30717"> Unrecognized library in native environment </a><br /><a href="https://docs.platformio.org/en/latest/projectconf/sections/env/options/library/lib_compat_mode.html">lib_compat_mode</a><br /><br /><h1 style="text-align: left;">実機で画面を回転する場合、nativeは回転後の画面の大きさを使う</h1>native環境でsetRotationを1以外にすると表示が回転して見づらくなるので、回転を含めてnativeと実機で切り替えるのが自分は都合が良かったです。<br /><pre>#if defined(USE_NATIVE)<br />static LGFX lcd(1080, 1920, 2);<br />#else<br />M5AtomDisplay lcd(1920, 1080);<br />#endif<br /></pre><pre> lcd.init();<br />#ifndef USE_NATIVE<br /> lcd.setRotation(0);<br />#endif<br /></pre><br /><h1 style="text-align: left;">色はTFT_*で指定</h1>M5GFXではBLACKやWHITEなどで色を指定できましたが、LovyanGFXでは名前が競合するのを避けるためかTFT_が頭についたTFT_BLACKやTFT_WHITEで定義されています。<br />TFT_付きのマクロはM5FGXでも定義されているので、実機でもnative環境でも動かすコードを書く時はTFT_付きを使うのが良いです。<br /><pre> lcd.setTextColor(TFT_WHITE, TFT_BLACK);<br /></pre><br /><h1 style="text-align: left;">native環境ではmillisが使えない</h1>ArduinoFakeではmillisが定義されていないためビルドエラーになります。<br />経過秒数を扱いたいならtime関数が使えます。<br /><pre>#ifdef USE_NATIVE<br /> auto seconds = time(NULL);<br />#else<br /> auto seconds = millis() / 1000;<br />#endif<br /></pre><br /><h1 style="text-align: left;">native環境ではdelayが使えない</h1>マクロでコメントアウトするか、unistdのsleepを使います。<br /><pre>#include <unistd.h><br /></pre><pre>#ifdef USE_NATIVE<br /> sleep(1);<br />#else<br /> delay(1000);<br />#endif<br /></pre><br /><h1 style="text-align: left;">気になること: 表示画面の領域を超える画面設定は、縦横比が崩れた状態で全画面表示される</h1>1080x1920の画像を表示しているはずが、横長の全画面表示になってしまいます。<br /><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjpgPTB6SRP0LuqUOtuFgomS0icdSaQgaPSmR0FmiCqLKUUlbmz_1yf77DyzegBVCRHgi2QF59gUpHknYUrQs9wMAW2JnIqnIQDBFtIoo6r5mg47D00gbUyNmB7VW_NiHbg_4eNzVzWkTjkOWOdRoDdc5oK24wE2sSIU4Na76cxnpeH21ASFKaoAdUi6qA/s1920/Screenshot%20from%202024-01-14%2019-44-28.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1080" data-original-width="1920" height="360" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjpgPTB6SRP0LuqUOtuFgomS0icdSaQgaPSmR0FmiCqLKUUlbmz_1yf77DyzegBVCRHgi2QF59gUpHknYUrQs9wMAW2JnIqnIQDBFtIoo6r5mg47D00gbUyNmB7VW_NiHbg_4eNzVzWkTjkOWOdRoDdc5oK24wE2sSIU4Na76cxnpeH21ASFKaoAdUi6qA/w640-h360/Screenshot%20from%202024-01-14%2019-44-28.png" width="640" /></a></div><br /><h1 style="text-align: left;">LovyanGFXのscaleは整数なので1より小さくできないが、コードを直接書き換えれば最初から小さく表示できる</h1>下記のように書き換えれば指定した大きさの1/4で表示されます。<br /><br />
<div class="pre-box"><div class="pre-name">LovyanGFX/src/lgfx/v1/platforms/sdl/Panel_sdl.cpp の Panel_sdl::sdl_create<br /></div>
<pre> // m->window = SDL_CreateWindow(_window_title,<br /> // SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,<br /> // _cfg.panel_width * m->scaling_x, _cfg.panel_height * m->scaling_y, flag); /*last param. SDL_WINDOW_BORDERLESS to hide borders*/<br /> m->window = SDL_CreateWindow(_window_title,<br /> SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,<br /> _cfg.panel_width * 0.25, _cfg.panel_height * 0.25, flag); /*last param. SDL_WINDOW_BORDERLESS to hide borders*/</pre></div><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi17Sr8-swBrPTCB0DmMW-3zVn6ovOy3-bIK2gRhQ7LKfr17NahlU3G7MBuYlVulpIzM45TYjEDgQGrHmA7nJ-2RIBjpOt9IWw9FYEHF9Y9INogWlUBGBGVxEZZSlaFucrJLPYbJwr3cDTwssd5MSZzCFUNC4tuhpn5m_Q5QzwTcJQk9k-fp2erv5WvL-s/s535/Screenshot%20from%202024-01-14%2020-40-28.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="535" data-original-width="290" height="640" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi17Sr8-swBrPTCB0DmMW-3zVn6ovOy3-bIK2gRhQ7LKfr17NahlU3G7MBuYlVulpIzM45TYjEDgQGrHmA7nJ-2RIBjpOt9IWw9FYEHF9Y9INogWlUBGBGVxEZZSlaFucrJLPYbJwr3cDTwssd5MSZzCFUNC4tuhpn5m_Q5QzwTcJQk9k-fp2erv5WvL-s/w346-h640/Screenshot%20from%202024-01-14%2020-40-28.png" width="346" /></a></div><br /><h1 style="text-align: left;">おわり</h1>nativeで動作確認可能な環境を作れたため、表示内容の調整やプレビューの取得が容易になって嬉しいです。<br /><br /><h1 style="text-align: left;">参考</h1>LovyanGFX公式のSDLを利用するサンプルプロジェクトです。<br /><a href="https://github.com/lovyan03/LovyanGFX/tree/master/examples_for_PC/PlatformIO_SDL">https://github.com/lovyan03/LovyanGFX/tree/master/examples_for_PC/PlatformIO_SDL</a><br /><br />この記事で作成したプロジェクトです。<br /><a href="https://github.com/asukiaaa/pio-lovyangfx-sdl-on-pc-practice">https://github.com/asukiaaa/pio-lovyangfx-sdl-on-pc-practice</a><br /><br />native環境でArduinoの関数(StringやWire)を利用するためのライブラリです。<br /><a href="https://github.com/FabioBatSilva/ArduinoFake">ArduinoFake</a><br /><br />native環境でArduino向けのライブラリを取り込むためにはlib_compat_modeをoffにすれば良いと把握したフォーラムと、それの公式解説ページです。<br /><a href="https://community.platformio.org/t/unrecognized-library-in-native-environment/30717">Unrecognized library in native environment </a><br /><a href="https://docs.platformio.org/en/latest/projectconf/sections/env/options/library/lib_compat_mode.html">lib_compat_mode</a><br /><br /></div>Asuki Konohttp://www.blogger.com/profile/07813182469285556500noreply@blogger.com0tag:blogger.com,1999:blog-9198372554518889060.post-86338335212275552262024-01-07T16:49:00.023+09:002024-01-07T17:34:59.468+09:00pedestalでsessionやcookieを使う<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEisxOG2OZSbg5wOZFma6Zt-yVhDofVolyg5cB2meJdcMqRlsEsYNx26PdPrUKBOTi5hXIl1nMleqfL8BND2bByZMngc1WvY7mxoMSWz5mVT9dKj-ZFeqP_h3Qu00KFJFWeRuCa0uJtSt6IDbMU0WxPJCMvyYy5R46fXtZ60LD8S1xnAqQi-zjl5ntt46Uw/s840/Screenshot%20from%202024-01-07%2014-19-16.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="633" data-original-width="840" height="482" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEisxOG2OZSbg5wOZFma6Zt-yVhDofVolyg5cB2meJdcMqRlsEsYNx26PdPrUKBOTi5hXIl1nMleqfL8BND2bByZMngc1WvY7mxoMSWz5mVT9dKj-ZFeqP_h3Qu00KFJFWeRuCa0uJtSt6IDbMU0WxPJCMvyYy5R46fXtZ60LD8S1xnAqQi-zjl5ntt46Uw/w640-h482/Screenshot%20from%202024-01-07%2014-19-16.png" width="640" /></a></div><br /><h1 style="text-align: left;">背景</h1><a href="http://pedestal.io/pedestal/0.6/index.html">pedestal</a>とはclojureというプログラミング言語のライブラリの1つであり、これを利用してwebサーバーのapiを管理できます。<br /><br />このpedestalは<a href="https://github.com/ring-clojure/ring?tab=readme-ov-file">ring</a>というapi管理ライブラリを利用して作られており、sessionの機能はringに頼っています。<br />設定方法、値の書き換え方、関連資料を備忘録として記事に残します。<br /><br /><h1 style="text-align: left;">使ったもの</h1><ul style="text-align: left;"><li><a href="https://clojure.org/guides/install_clojure">clojure cli環境</a><br />cljコマンドでサーバーを起動します。<br />この記事のプログラムはdbを使わないのでclojure cli環境だけで動きます。</li><li>webブラウザ<br />作ったページを閲覧します。<br /></li></ul><br /><h1 style="text-align: left;">全体像</h1>200行弱ありますが全体が見れると分かりやすいと思うので、deps.ednとmain関数があるファイルの全体を共有してから要所を解説します。<br />このファイルを含み実行可能なプロジェクトは下記のリポジトリに上げています。<br /><br /><a href="https://github.com/asukiaaa/clj-pedestal-session-practice">clj-pedestal-session-practice</a><br /><br />
<div class="pre-box">
<div class="pre-name">deps.edn</div>
<pre>{:paths ["src" "resources"]<br /> :deps {org.clojure/clojure {:mvn/version "1.11.1"}<br /> io.pedestal/pedestal.service {:mvn/version "0.6.2"}<br /> io.pedestal/pedestal.jetty {:mvn/version "0.6.2"}<br /> hiccup/hiccup {:mvn/version "1.0.5"}<br /> ns-tracker/ns-tracker {:mvn/version "0.4.0"}}<br /> :aliases<br /> {:run-m {:main-opts ["-m" "clj-pedestal-session-practice.server"]}<br /> :run-dev {:ns-default clj-pedestal-session-practice.server<br /> :exec-fn -run-dev<br /> :exec-args {:name "Clojure"}}<br /> :build {:deps {io.github.clojure/tools.build {:mvn/version "0.9.4"}}<br /> :ns-default build}<br /> :test {:extra-paths ["test"]<br /> :extra-deps {org.clojure/test.check {:mvn/version "1.1.1"}<br /> io.github.cognitect-labs/test-runner<br /> {:git/tag "v0.5.1" :git/sha "dfb30dd"}}}}}<br /></pre>
</div><br />
<div class="pre-box">
<div class="pre-name">src/clj_pedestal_practice/server.clj</div>
<pre>(ns clj-pedestal-session-practice.server<br /> (:gen-class)<br /> (:require [io.pedestal.http :as http :refer [html-body]]<br /> [io.pedestal.http.route :as route :refer [url-for]]<br /> [io.pedestal.http.body-params :refer [body-params]]<br /> [ring.middleware.session.cookie :as cookie]<br /> [ring.util.response :refer [redirect]]<br /> [io.pedestal.http.ring-middlewares :as middlewares]<br /> [hiccup.page :refer [html5]]<br /> [ns-tracker.core :refer [ns-tracker]]))<br /><br />(def watched-namespaces (ns-tracker "src"))<br /><br />(defn handler-redirect-with-injecting-data<br /> [_request]<br /> (-> (redirect (url-for :home-page-with-interceptors))<br /> (assoc :cookies {:some {:value "data-in-cookie" :http-only true}})<br /> (assoc-in [:session :some] {:value "data-in-session"})))<br /><br />(defn handler-page-inject-without-redirect [_request]<br /> {:status 200<br /> :cookies {:some {:value "data-in-cookie-without-redirect" :http-only true}}<br /> :session {:some "data-in-session-without-redirect"}<br /> :body (html5<br /> [:p "injected"]<br /> [:a {:href (url-for :home-page-with-interceptors)} "home"])})<br /><br />(defn handler-page-check<br /> [request]<br /> {:status 200<br /> :body (html5<br /> [:a {:href (url-for :home-page-with-interceptors)} "home"] [:br]<br /> [:a {:href (url-for :home-page-without-interceptor)} "home-without-interceptor"] [:br]<br /> [:a {:href (url-for :inject)} "inject"] [:br]<br /> [:a {:href (url-for :inject-without-redirect)} "inject-without-redirect"] [:br]<br /> [:a {:href (url-for :clear)} "clear"] [:br]<br /> [:a {:href (url-for :clear-without-redirect)} "clear-withtout-redirect"] [:br]<br /> [:p "check page"]<br /> [:p "request"]<br /> [:p (str request)]<br /> [:p "cookies"]<br /> [:p (str (:cookies request))]<br /> [:p "session"]<br /> [:p (str (:session request))])})<br /><br />(defn handler-redirect-with-clear [_request]<br /> (-> (redirect (url-for :home-page-with-interceptors))<br /> (assoc :cookies {:some {:max-age 0}})<br /> (assoc :session nil)))<br /><br />(defn handler-page-clear-without-redirect [_request]<br /> {:status 200<br /> :session nil<br /> :cookies {:some {:max-age 0}}<br /> :body (html5<br /> [:p "clear-without-redirect"]<br /> [:a {:href (url-for :home-page-with-interceptors)} "home"])})<br /><br />(def interceptor-session (middlewares/session {:store (cookie/cookie-store)}))<br />(def interceptors-common [(body-params)<br /> html-body<br /> interceptor-session])<br /><br />(def routes<br /> #{["/"<br /> :get (conj interceptors-common handler-page-check)<br /> :route-name :home-page-with-interceptors]<br /> ["/home-without-interceptor"<br /> :get [html-body handler-page-check]<br /> :route-name :home-page-without-interceptor]<br /> ["/inject"<br /> :get (conj interceptors-common handler-redirect-with-injecting-data)<br /> :route-name :inject]<br /> ["/inject-without-redirect"<br /> :get (conj interceptors-common handler-page-inject-without-redirect)<br /> :route-name :inject-without-redirect]<br /> ["/clear"<br /> :get (conj interceptors-common handler-redirect-with-clear)<br /> :route-name :clear]<br /> ["/clear-without-redirect"<br /> :get (conj interceptors-common handler-page-clear-without-redirect)<br /> :route-name :clear-without-redirect]})<br /><br />(defn routes-watched []<br /> (doseq [ns-sym (watched-namespaces)]<br /> (require ns-sym :reload))<br /> (route/expand-routes routes))<br /><br />(def service {:env :prod<br /> ::http/routes routes<br /> ::http/resource-path "/public"<br /> ::http/type :jetty<br /> ::http/port 8080})<br /><br />(defonce runnable-service (http/create-server service))<br /><br />(defn -run-dev<br /> [& _args]<br /> (println "\nCreating your [DEV] server...")<br /> (-> service ;; start with production configuration<br /> (merge {:env :dev<br /> ::http/routes routes-watched<br /> ;; do not block thread that starts web server<br /> ::http/join? false<br /> ;; Routes can be a function that resolve routes,<br /> ;; we can use this to set the routes to be reloadable<br /> ;; ::http/routes #(deref #'routes)<br /> ;; all origins are allowed in dev mode<br /> ::http/allowed-origins {:creds true :allowed-origins (constantly true)}})<br /> ;; Wire up interceptor chains<br /> http/default-interceptors<br /> http/dev-interceptors<br /> http/create-server<br /> http/start))<br /><br />(defn -main<br /> [& _args]<br /> (println "\nCreating your server...")<br /> (http/start runnable-service))</pre></div><br />下記のコマンドで開発版(deps.ednで指定した-run-dev関数の呼び出し)を実行できます。<br /><pre>clj -X:run-dev</pre><br />実行すると http://localhost:8080 でサーバーが起動するのでブラウザで確認します。<br /><br /><h1 style="text-align: left;">ring.middleware.session.cookieでinterceptorを作って埋め込む</h1>ringのcookieを下記のように記述してinterceptorとして埋め込んだパスでsessionやcookieが利用可能になります。<br /><pre> (:require [ring.middleware.session.cookie :as cookie]<br /> [io.pedestal.http.ring-middlewares :as middlewares])</pre><pre>(def interceptor-session (middlewares/session {:store (cookie/cookie-store)}))<br />(def interceptors-common [(body-params)<br /> html-body<br /> interceptor-session])<br /></pre><pre> ["/"<br /> :get (conj interceptors-common handler-page-check)<br /> :route-name :home-page-with-interceptors]<br /> ["/home-without-interceptor"<br /> :get [html-body handler-page-check]<br /> :route-name :home-page-without-interceptor]<br /></pre><br />interceptorを適用した「/」ではsessionとcookieを見れますが、適用していない「/home-without-interceptor」では見れません。<br />sessionのinterceptorを適用していないと、値の代入や削除もできません。<br /><br /><span>/と/home-without-interceptorでは、下記のhandlerでrequestに含まれるcookiesとsessionを表示しています。</span><br /><pre>(defn handler-page-check<br /> [request]<br /> {:status 200<br /> :body (html5<br /> [:a {:href (url-for :home-page-with-interceptors)} "home"] [:br]<br /> [:a {:href (url-for :home-page-without-interceptor)} "home-without-interceptor"] [:br]<br /> [:a {:href (url-for :inject)} "inject"] [:br]<br /> [:a {:href (url-for :inject-without-redirect)} "inject-without-redirect"] [:br]<br /> [:a {:href (url-for :clear)} "clear"] [:br]<br /> [:a {:href (url-for :clear-without-redirect)} "clear-withtout-redirect"] [:br]<br /> [:p "check page"]<br /> [:p "request"]<br /> [:p (str request)]<br /> [:p "cookies"]<br /> [:p (str (:cookies request))]<br /> [:p "session"]<br /> [:p (str (:session request))])})<br /></pre><br />interceptorを適用している/だと値を見れます。<br /><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEidK-BPnlHoaO7rdciAqaC1IO3Hr3qwXygl_aRAtQl1opfX9i9J2t-LR-9DUa3OjBvW7i168jWhOs0mzhA4YKlO0-T4caEn1UIIPHkBFN8nx_SOWQHLLKVqFG6c-8SFPCcqQ_zgAKnmSPOv2-yNLy1ONPtkIDLRsDsF3qsemjR11Lh61XJP2zC6NxdiNOs/s637/Screenshot%20from%202024-01-07%2013-59-43.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="449" data-original-width="637" height="452" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEidK-BPnlHoaO7rdciAqaC1IO3Hr3qwXygl_aRAtQl1opfX9i9J2t-LR-9DUa3OjBvW7i168jWhOs0mzhA4YKlO0-T4caEn1UIIPHkBFN8nx_SOWQHLLKVqFG6c-8SFPCcqQ_zgAKnmSPOv2-yNLy1ONPtkIDLRsDsF3qsemjR11Lh61XJP2zC6NxdiNOs/w640-h452/Screenshot%20from%202024-01-07%2013-59-43.png" width="640" /></a></div><br />interceptorを適用していない/home-without-interceptorでは値を見れません。<br /><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjWMKp2H_lAFoJAnW9lMroNTWF1lmjfgDpf5Zp2YUVSSXJ-Z2IB0W_qCU4eR387nSRAv6mYDjDNRHfakuCi9SjFw0DKYopmjPffA-lTTCxiXOONQopLHmWkdBI_p78nt-g23lFeT0SgFaCWEsCqoBUa9kpymmhwMFA8dM3Bsy2a-c099KY_z_EOMJRL0RE/s638/Screenshot%20from%202024-01-07%2013-59-59.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="352" data-original-width="638" height="354" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjWMKp2H_lAFoJAnW9lMroNTWF1lmjfgDpf5Zp2YUVSSXJ-Z2IB0W_qCU4eR387nSRAv6mYDjDNRHfakuCi9SjFw0DKYopmjPffA-lTTCxiXOONQopLHmWkdBI_p78nt-g23lFeT0SgFaCWEsCqoBUa9kpymmhwMFA8dM3Bsy2a-c099KY_z_EOMJRL0RE/w640-h354/Screenshot%20from%202024-01-07%2013-59-59.png" width="640" /></a></div><br />参考<br />pedestalのサンプルコードを参考にしました。(これに合わせてcookie-storeを設定していますが、cookie-storeを渡さなくてもsessionとcookieが両方使えるのが謎です。)<br /><a href="https://github.com/pedestal/pedestal/blob/master/samples/ring-middleware/src/ring_middleware/service.clj"> pedestal/samples/ring-middleware/src/ring_middleware/service.clj</a><br /><br />pedestalのmiddleware/sessionの説明ページです。<br /><a href="http://pedestal.io/pedestal/0.7/reference/ring.html#_session">Ring Middleware</a><br /><br /><h1 style="text-align: left;">redirect時はassocで、ページ表示時はresponseのmapに記述して値を配置</h1>sessionのinterceptorを埋め込んでいるhandlerのrequestのmapに対して、:cookies でcookieを、:session でsessionを操作可能です。<br /><pre>(defn handler-redirect-with-injecting-data<br /> [_request]<br /> (-> (redirect (url-for :home-page-with-interceptors))<br /> (assoc :cookies {:some {:value "data-in-cookie" :http-only true}})<br /> (assoc-in [:session :some] {:value "data-in-session"})))<br /><br />(defn handler-page-inject-without-redirect [_request]<br /> {:status 200<br /> :cookies {:some {:value "data-in-cookie-without-redirect" :http-only true}}<br /> :session {:some "data-in-session-without-redirect"}<br /> :body (html5<br /> [:p "injected"]<br /> [:a {:href (url-for :home-page-with-interceptors)} "home"])})<br /></pre><pre> ["/inject"<br /> :get (conj interceptors-common handler-redirect-with-injecting-data)<br /> :route-name :inject]<br /> ["/inject-without-redirect"<br /> :get (conj interceptors-common handler-page-inject-without-redirect)<br /> :route-name :inject-without-redirect]<br /></pre><br />cookieはringの機能を通して一般的なcookie関連の設定が可能です。<br />下記のringの説明ページのwrap-cookiesに詳しい設定が書かれています。<br /><br /><a href="https://ring-clojure.github.io/ring/ring.middleware.cookies.html">ring.middleware.cookies</a><br /><br />このコードではhttp-onlyを有効にしてjsからは値を参照できなくしています。<br />認証情報などはhttpOnlyやsecureを有効にして保持するのが悪用を防げて良いです。<br /><pre> :cookies {:some {:value "data-in-cookie-without-redirect" :http-only true}}<br /></pre><br />http://localhost:8080/inject にアクセス後に表示される情報がこちらです。<br />http-onlyを有効にしているので、handlerのrequestでは値を見れますが、jsでdocument.cookieを参照しても空です。<br /><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEisxOG2OZSbg5wOZFma6Zt-yVhDofVolyg5cB2meJdcMqRlsEsYNx26PdPrUKBOTi5hXIl1nMleqfL8BND2bByZMngc1WvY7mxoMSWz5mVT9dKj-ZFeqP_h3Qu00KFJFWeRuCa0uJtSt6IDbMU0WxPJCMvyYy5R46fXtZ60LD8S1xnAqQi-zjl5ntt46Uw/s840/Screenshot%20from%202024-01-07%2014-19-16.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="633" data-original-width="840" height="482" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEisxOG2OZSbg5wOZFma6Zt-yVhDofVolyg5cB2meJdcMqRlsEsYNx26PdPrUKBOTi5hXIl1nMleqfL8BND2bByZMngc1WvY7mxoMSWz5mVT9dKj-ZFeqP_h3Qu00KFJFWeRuCa0uJtSt6IDbMU0WxPJCMvyYy5R46fXtZ60LD8S1xnAqQi-zjl5ntt46Uw/w640-h482/Screenshot%20from%202024-01-07%2014-19-16.png" width="640" /></a></div><br />参考<br />ringのcookieに関する説明ページです。<br /><a href="https://ring-clojure.github.io/ring/ring.middleware.cookies.html">ring.middleware.cookies</a><br /><br />pedestalのresponse mapの説明ページです。<br /><a href="http://pedestal.io/pedestal/0.7/reference/response-map.html">Response Map</a><br /><br /><h1 style="text-align: left;">sessionは全体を削除可能だが、cookieの削除はキーとmax-ageの指定が必要</h1>sessionはnilや{}を代入すると全体を削除可能です。<br />session部分的に削除したい場合は、削除を施したmapを渡します。<br />しかし、cookieは全体の削除は対応しておらず、キーにnilを代入しても空文字を持つキーができるので、消したいキーにmax-ageを0設定して消します。<br /><pre>(defn handler-redirect-with-clear [_request]<br /> (-> (redirect (url-for :home-page-with-interceptors))<br /> (assoc :cookies {:some {:max-age 0}})<br /> (assoc :session nil)))<br /><br />(defn handler-page-clear-without-redirect [_request]<br /> {:status 200<br /> :session nil<br /> :cookies {:some {:max-age 0}}<br /> :body (html5<br /> [:p "clear-without-redirect"]<br /> [:a {:href (url-for :home-page-with-interceptors)} "home"])})<br /></pre><pre> ["/clear"<br /> :get (conj interceptors-common handler-redirect-with-clear)<br /> :route-name :clear]<br /> ["/clear-without-redirect"<br /> :get (conj interceptors-common handler-page-clear-without-redirect)<br /> :route-name :clear-without-redirect]</pre><br />max-ageに小さい数を指定するのがcookieの消し方です。<pre> :cookies {:some {:max-age 0}}<br /></pre><br />参考<br /><a href="https://stackoverflow.com/questions/14258856/in-clojure-ring-how-do-i-delete-a-cookie">In clojure/ring, how do I delete a cookie?</a><br /><br /><h1 style="text-align: left;">サーバーを再起動するとsessionは消えるがcookieは残る</h1>sessionはclojure cliのメモリで管理されているため再起動で消えます。<br />cookieはブラウザが保有しているので、サーバーを再起動しても残ります。<br /><br /><h1 style="text-align: left;">余談: コードの自動更新</h1>変更の反映にサーバーを起動しなおすのは時間がかかって嬉しくないので、以前取り組んだns-reloadを利用した自動更新の仕組みを適用しています。<br /><pre>(def watched-namespaces (ns-tracker "src"))<br /></pre><pre>(defn routes-watched []<br /> (doseq [ns-sym (watched-namespaces)]<br /> (require ns-sym :reload))<br /> (route/expand-routes routes))<br /></pre><pre>(defn -run-dev<br /> [& _args]<br /> (-> service<br /> (merge {:env :dev<br /> ::http/routes routes-watched<br /></pre><br />参考<br /><a href="https://asukiaaa.blogspot.com/2022/04/pedestal-with-auto-reloading.html">pedestalでコード変更時に自動更新</a><br /><br /><h1 style="text-align: left;">おわり</h1>pedestalでsessionやcookieを扱う方法を大まかに把握できました。<br /><br /><h1 style="text-align: left;">参考</h1>今回紹介したコードを管理しているリポジトリです。<br /><a href="https://github.com/asukiaaa/clj-pedestal-session-practice">clj-pedestal-session-practice</a><br /><br />pedestalのsessionに関するサンプルコードです。<br /><a href="https://github.com/pedestal/pedestal/blob/master/samples/ring-middleware/src/ring_middleware/service.clj"> pedestal/samples/ring-middleware/src/ring_middleware/service.clj</a><br /><br />pedestalのmiddleware/sessionの説明ページです。<br /><a href="http://pedestal.io/pedestal/0.7/reference/ring.html#_session">Ring Middleware</a><br /><br />ringのcookieの扱い方説明ページです。<br /><a href="https://ring-clojure.github.io/ring/ring.middleware.cookies.html">ring.middleware.cookies</a><br /><br />pedestalのresponse mapの説明ページです。<br /><a href="http://pedestal.io/pedestal/0.7/reference/response-map.html">Response Map</a><br /><br />ringでのcookieの消し方を質問しているページです。<br /><a href="https://stackoverflow.com/questions/14258856/in-clojure-ring-how-do-i-delete-a-cookie">In clojure/ring, how do I delete a cookie?</a><br /><br />サーバーの自動更新解説ページです。<br /><a href="https://asukiaaa.blogspot.com/2022/04/pedestal-with-auto-reloading.html">pedestalでコード変更時に自動更新</a><br /><br />Asuki Konohttp://www.blogger.com/profile/07813182469285556500noreply@blogger.com0tag:blogger.com,1999:blog-9198372554518889060.post-90119399217245862942023-12-31T23:32:00.002+09:002023-12-31T23:32:14.397+09:00cppでclassの配列を定義する場合、{}を二重で使う<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhnIYV1zZAGrgJyLjNWQn6D0SNCgfD3WL_HDrNQ-fF5Nl5fD_ftJHAKX9y52FP-hclh_P-REJlJ4DpPFmDprHKOMRe2EvkpcxJD4JidYiJd1IxIOOtdM0JvjE1nE_3JMdEEV8nArZtz1r5sX8Ixp4NoMBT4sINI-vnkksRJcTaDLiNkmkSzLZ6cQVijviM/s394/Screenshot%20from%202023-12-31%2023-02-06.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="140" data-original-width="394" height="228" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhnIYV1zZAGrgJyLjNWQn6D0SNCgfD3WL_HDrNQ-fF5Nl5fD_ftJHAKX9y52FP-hclh_P-REJlJ4DpPFmDprHKOMRe2EvkpcxJD4JidYiJd1IxIOOtdM0JvjE1nE_3JMdEEV8nArZtz1r5sX8Ixp4NoMBT4sINI-vnkksRJcTaDLiNkmkSzLZ6cQVijviM/w640-h228/Screenshot%20from%202023-12-31%2023-02-06.png" width="640" /></a></div><br />cppでconstructorに引数が必要なclassの配列(array)を作る場合、[]と()の組み合わせではなく、{}を二重に使って定義します。<br />具体的には下記のように書きます。<br /><pre>class Book {<br /> public:<br /> std::string title;<br /> Book(std::string title) : title(title) {}<br />};<br /><br />Book books[]{{"hoi"}, {"fue"}};<br /></pre><br />[]と{}の間に=があっても同じです。<br /><pre>Book books[] = {{"hoi"}, {"fue"}};<br /></pre><br />配列の長さは定義後にsizeofを使って取得できます。<br /><pre>const size_t lenBooks = sizeof(books) / sizeof(Book);<br /></pre><br />{}を二重にする書き方が分からず戸惑う場面があるので記事に残します。<br /><br /><a href="https://stackoverflow.com/a/8579748/3774895">How do I declare an array with a custom class?</a><br /><a href="https://en.cppreference.com/w/cpp/language/array">Array declaration</a><br /><br />Asuki Konohttp://www.blogger.com/profile/07813182469285556500noreply@blogger.com0tag:blogger.com,1999:blog-9198372554518889060.post-47164927093170134992023-12-25T00:54:00.004+09:002024-01-29T09:29:30.942+09:00cppのクラスメンバ関数をbindを通してstd::functionとして扱う<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEic2b0-AWBAgWarkZJIZEYzlrNU1ujA8MN1Po2rdiqb_LLEvOPCVsJGHUe8baSIKnTlWZzeoObx0AKyalG9t2unF-XIyrv84wmoTzlM1U-tNLVofTpP_wdLKbGsc7PdPP3OfSrSVSCki1lXG1_At0Ls-CpNUIiiB2h9ZxQAlqQDwW15_KcTZ2RGhVnRgak/s565/Screenshot%20from%202023-12-25%2000-47-05.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="102" data-original-width="565" height="116" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEic2b0-AWBAgWarkZJIZEYzlrNU1ujA8MN1Po2rdiqb_LLEvOPCVsJGHUe8baSIKnTlWZzeoObx0AKyalG9t2unF-XIyrv84wmoTzlM1U-tNLVofTpP_wdLKbGsc7PdPP3OfSrSVSCki1lXG1_At0Ls-CpNUIiiB2h9ZxQAlqQDwW15_KcTZ2RGhVnRgak/w640-h116/Screenshot%20from%202023-12-25%2000-47-05.png" width="640" /></a></div><br /><h1 style="text-align: left;">背景</h1>以前クラスメンバ関数をコールバック関数として渡したいとgithubで要望したところbindを使えば可能と助言をいただきました。<br /><br /><a href="https://github.com/h2zero/NimBLE-Arduino/issues/342#issuecomment-1024878938">Request of setting notify_callback as class instance. #342</a><br /><br />この手法は時々使いたくなる場面があって活用しているものの、その度に上記のissueを開き直したり既存の実装を調べ直したり書き方を検索したりして書き方を思い出しているので、記事としてまとめて見返しやすくします。<br /><br /><h1 style="text-align: left;">bindでクラスメンバ関数を括る</h1>bindを利用して下記のようにまとめれます。<br /><pre>std::bind(対象のクラス::クラスメンバ変数, クラスのインスタンス);<br /></pre><br />引数がある場合は、placeholdersを引数の数分bindに渡します。<br />下記の例は引数が2個ある場合のbindです。<pre>std::bind(対象のクラス::クラスメンバ変数のポインタ, クラスのインスタンスのポインタ, std::placeholders::_1, std::placeholders::_2);<br /></pre><br /><h1 style="text-align: left;">具体例</h1>具体例も共有します。<br /><pre>#include <stdlib.h><br /><br />#include <functional><br />#include <iostream><br /><br />void runPoyo(std::function<void()> callbackPoyo) { callbackPoyo(); }<br />void runNani(std::function<void(int, int)> callbackNani) { callbackNani(0, 1); }<br /><br />class Hoge {<br /> public:<br /> void poyo() { printf("poyo\n"); }<br /> void nani(int x, int y) { printf("nani %d %d\n", x, y); }<br /> void run() {<br /> std::function<void(void)> callbackPoyo = std::bind(&Hoge::poyo, this);<br /> std::function<void(int, int)> callbackNani = std::bind(<br /> &Hoge::nani, this, std::placeholders::_1, std::placeholders::_2);<br /> runPoyo(callbackPoyo);<br /> runNani(callbackNani);<br /> }<br />};<br /><br />int main(int argc, char** argv) {<br /> Hoge instanceHoge;<br /> instanceHoge.run();<br /> std::function<void(void)> callbackPoyo =<br /> std::bind(&Hoge::poyo, &instanceHoge);<br /> std::function<void(int, int)> callbackNani = std::bind(<br /> &Hoge::nani, &instanceHoge, std::placeholders::_1, std::placeholders::_2);<br /> callbackPoyo();<br /> callbackNani(2, 3);<br /> std::function<void(int, int)> callbackNaniChangeValueOrder = std::bind(<br /> &Hoge::nani, &instanceHoge, std::placeholders::_2, std::placeholders::_1);<br /> callbackNaniChangeValueOrder(2, 3);<br /> std::function<void(int)> callbackNaniAssignedVal55 =<br /> std::bind(&Hoge::nani, &instanceHoge, 55, std::placeholders::_1);<br /> callbackNaniAssignedVal55(4); // result: nani 55 4<br /> std::function<void(int)> callbackNaniAssignedVal66 =<br /> std::bind(&Hoge::nani, &instanceHoge, std::placeholders::_1, 66);<br /> callbackNaniAssignedVal66(5); // result: nani 5 66<br /> return 0;<br />}<br /></pre><br />上記のプログラムをg++でビルドして実行すると下記の実行結果が出ます。<br /><pre>poyo<br />nani 0 1<br />poyo<br />nani 2 3<br />nani 3 2<br />nani 55 4<br />nani 5 66</pre><br />Hogeクラスのpoyoをbindでまとめる場合はこう書きます。<br /><pre> std::function<void(void)> callbackPoyo =<br /> std::bind(&Hoge::poyo, &instanceHoge);<br /> callbackPoyo();<br /></pre><br />クラスメンバ関数の中でまとめる場合はインスタンスにthisを渡せば良いです。<br /><pre>class Hoge {<br /> public:<br /> void poyo() { printf("poyo\n"); }<br /> void run() {<br /> std::function<void(void)> callbackPoyo = std::bind(&Hoge::poyo, this);<br /> runPoyo(callbackPoyo);<br /> }<br />};</pre><br />引数が必要なHogeクラスのnaniをbindでまとめる場合はこう書きます。<br /><pre> std::function<void(int, int)> callbackNani = std::bind(<br /> &Hoge::nani, &instanceHoge, std::placeholders::_1, std::placeholders::_2);<br /></pre><br />引数がある関数は、bind時にplaceholderを渡さず値の代入が可能です。<br /><pre> std::function<void(int)> callbackNaniAssignedVal55 =<br /> std::bind(&Hoge::nani, &instanceHoge, 55, std::placeholders::_1);<br /> callbackNaniAssignedVal55(4); // result: nani 55 4<br /></pre><pre> std::function<void(int)> callbackNaniAssignedVal66 =<br /> std::bind(&Hoge::nani, &instanceHoge, std::placeholders::_1, 66);<br /> callbackNaniAssignedVal66(5); // result: nani 5 66</pre><br /><h1 style="text-align: left;">おわり</h1>bindを利用するとクラスメンバ関数をstd::function型に変換できるので、std::function型のコールバックを受け取る関数に渡せて便利です。<br />この記事によって、書きたくなったときの調べ直す時間が短くなるのを願います。<br /><br /><h1 style="text-align: left;">参考</h1><a href="https://github.com/h2zero/NimBLE-Arduino/issues/342#issuecomment-1024878938">Request of setting notify_callback as class instance. #342</a><br /><a href="https://en.cppreference.com/w/cpp/utility/functional/bind">std::bind cppreference</a><br /><br />Asuki Konohttp://www.blogger.com/profile/07813182469285556500noreply@blogger.com0tag:blogger.com,1999:blog-9198372554518889060.post-6819175628257234722023-12-18T00:01:00.005+09:002023-12-18T09:52:30.380+09:00clojureのマクロを利用する定義の静的解析で変数未定義エラーになる場合の対応<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiHLl7yvypk8cMw6KO9gTmmGoIBZQBhPG02xcn0bfexZeQ5KgNIrQ2rp-r4TKNwtSL0ruP1b9tFbYpsvODKoVZQDACC7MmxA-BsSZ4U7Te5gEubsgtjm4-E91Ze25t9Xn0q1VJaSqMAIjlogldBWwV6__tKdjcIeI4TZIb5vsPpbsE0b9MlP5tmBUUObIY/s582/Screenshot%20from%202023-12-17%2023-04-19.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="260" data-original-width="582" height="286" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiHLl7yvypk8cMw6KO9gTmmGoIBZQBhPG02xcn0bfexZeQ5KgNIrQ2rp-r4TKNwtSL0ruP1b9tFbYpsvODKoVZQDACC7MmxA-BsSZ4U7Te5gEubsgtjm4-E91Ze25t9Xn0q1VJaSqMAIjlogldBWwV6__tKdjcIeI4TZIb5vsPpbsE0b9MlP5tmBUUObIY/w640-h286/Screenshot%20from%202023-12-17%2023-04-19.png" width="640" /></a></div><br /><h1 style="text-align: left;">マクロ内の変数が未定義エラーになる</h1>VSCodeでclojureのマクロ(記事冒頭の図は<a href="https://github.com/pedestal/pedestal/blob/e6ddf2b535d13919648dbdfce405f5a142327023/samples/buddy-auth/src/buddy_auth/service.clj#L61-L72">pedestalのbuddyののinterceptor</a>)を記述すると、error-dispatchマクロを利用する記述で下記の未定義エラーが発生しました。<br /><pre>Unresolved symbol: ctx clj-kondo(unresolved-symbol)<br /></pre><br /><h1 style="text-align: left;">対応: declareで定義する</h1>記述前にdeclareで定義しておけば、静的解析の意味付けはできませんがエラーは回避できます。<br /><pre>(declare ctx)<br />(declare ex)<br /></pre><br />変数にマウスカーソルを重ねると表示される定義は、declareで定義した情報が表示され、マクロで扱われる役割とは異なります。<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEicaR6pSKvB0Cs8wL0uzZbJ4eIJ-pbM121kQlhyVY9jmxp7ORZrB0KFEcA14f0f2UJ-v205W4DvLX59bVXv9uZub0BXOH7TWC90FuIxFT4VU-9Cb6Tp_WME3mnWhSgx4cE4rIjH8aOljrMQgmV6N7sIz27ZUOcplz0H0mP2xEJ2su_EscZKR6EhgtzyETE/s627/Screenshot%20from%202023-12-17%2023-43-39.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="152" data-original-width="627" height="156" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEicaR6pSKvB0Cs8wL0uzZbJ4eIJ-pbM121kQlhyVY9jmxp7ORZrB0KFEcA14f0f2UJ-v205W4DvLX59bVXv9uZub0BXOH7TWC90FuIxFT4VU-9Cb6Tp_WME3mnWhSgx4cE4rIjH8aOljrMQgmV6N7sIz27ZUOcplz0H0mP2xEJ2su_EscZKR6EhgtzyETE/w640-h156/Screenshot%20from%202023-12-17%2023-43-39.png" width="640" /></a></div><br />参考: <a href="https://stackoverflow.com/a/61728066/3774895">How to avoid unresolved symbol with clj-kond when using hugSQL def-db-fns macro?</a><br /><br /><h1 style="text-align: left;">おわり</h1>解析で赤線が出るものの動きはするコードが出てきて戸惑いましたが、とりあえずエラーの赤線は消せて良かったです。<br />他に良い解決方法があれば、コメントなどで教えていただけると嬉しいです。<br /><br />この記事は <a href="https://qiita.com/advent-calendar/2023/clojure">Clojure Advent Calendar 2023</a> 18日目の記事です。<br /><br />Asuki Konohttp://www.blogger.com/profile/07813182469285556500noreply@blogger.com0tag:blogger.com,1999:blog-9198372554518889060.post-34095831637647642352023-12-10T23:20:00.004+09:002023-12-10T23:31:56.984+09:00スイッチは光らないけど通電すると光るコンセントケーブルを光らなくした<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiMWkAfVB8hqjL1jwAKagU1pb6RcW0wfW6S9dwz5hBe_A0XenZICa5YT3niuvYqYb36n2Jhb-ZDiQmx563HLkK3v1_gXdaUZ43imZ-oFHSaxCYvYnIv1YymaHOiOjTqrVPsgpwMqm-FDHyW0gC_THpwcQp-skp-pq6tRJvP37uz5RDBsScdhqcDj7cIl5E/s2430/IMG_20231209_122214.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="2430" data-original-width="1880" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiMWkAfVB8hqjL1jwAKagU1pb6RcW0wfW6S9dwz5hBe_A0XenZICa5YT3niuvYqYb36n2Jhb-ZDiQmx563HLkK3v1_gXdaUZ43imZ-oFHSaxCYvYnIv1YymaHOiOjTqrVPsgpwMqm-FDHyW0gC_THpwcQp-skp-pq6tRJvP37uz5RDBsScdhqcDj7cIl5E/s320/IMG_20231209_122214.jpg" width="248" /></a></div><br /><h1 style="text-align: left;">背景</h1>ビックカメラでon offスイッチが光らないコンセント延長ケーブルを買ったところ、通電させると光る箇所があったので光らなくしました。<br />道具や手順を共有します。<br /><br /><h1 style="text-align: left;">改造対象</h1>ビックカメラで購入しました。<br /><a href="https://www.biccamera.com/bc/item/6128502/">電源タップ multiple outlet ホワイト AT-MOSK515 [1.5m /5個口 /スイッチ付き(個別)]</a><br /><br />スイッチが光らなくて主張が控えめなのを期待して買いましたが、通電すると根本が光って通電を主張してきました。<br />どうして…<br /><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgb38dxpu7fWSaB0BsdibB1cXLeDV9TLAEdw45axiIiCQ6tQySig7cmqnI_XaPchR9wbjuNASo9R34E72A9NplKBWXrmXBFcOnBVC_3_BZwJqZZbKR52oq1CoqhogP6uUJuG98kEdCGWsZjMosGtOINFJk-JeF9qVjNDp6pK2fOpSmy866IVrKe3pRG-mE/s2946/IMG_20231130_175545.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1815" data-original-width="2946" height="394" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgb38dxpu7fWSaB0BsdibB1cXLeDV9TLAEdw45axiIiCQ6tQySig7cmqnI_XaPchR9wbjuNASo9R34E72A9NplKBWXrmXBFcOnBVC_3_BZwJqZZbKR52oq1CoqhogP6uUJuG98kEdCGWsZjMosGtOINFJk-JeF9qVjNDp6pK2fOpSmy866IVrKe3pRG-mE/w640-h394/IMG_20231130_175545.jpg" width="640" /></a></div><br />分解しようにもY型の特殊ネジが使われていて、通常のプラスやマイナスのドライバーでは開けません。<br /><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhZIBz9huqndSUGXZG1BPva9AMI0cMfytQfwWoZmWuvG73l0ZFgOloXddLImFUDnPhQ38VI5XcyOy727YYgWttEmFdxTMBn6qadtZ6KW1OZAU3cqoak_EpubYXrUOTine8dxTIzF4iXnEsda1YXgH9upKh_5mzzATAGVLnvc-nWmF96zqUwqBVyN3ZiBNo/s1868/IMG_20231130_180611.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1868" data-original-width="1795" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhZIBz9huqndSUGXZG1BPva9AMI0cMfytQfwWoZmWuvG73l0ZFgOloXddLImFUDnPhQ38VI5XcyOy727YYgWttEmFdxTMBn6qadtZ6KW1OZAU3cqoak_EpubYXrUOTine8dxTIzF4iXnEsda1YXgH9upKh_5mzzATAGVLnvc-nWmF96zqUwqBVyN3ZiBNo/s320/IMG_20231130_180611.jpg" width="307" /></a></div><br />ちなみに、「TAGlabel by amadana」(タグレーベル バイ アマダナ)という聞いたこと無いブランドですが、この製品は株式会社オーム電気が管理しているようです。<br /><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh2OvswmBUOlZ-NGbWVZtP4Ul_E2msdqVcIJxdONyfXXVQoHfHZiKwHm0s4IhOsNHL80sucg5FmO6kEDrVuKNgYrDlisHIW_WO2GwtJNcoG53Yc_BPdeZuzX7VGGSf2gS2iHPMr-R_us18sRkTD21q2WkGXgBWfP9CcVuAG4skq8Ueyk4LG68wAAiFjEQI/s2379/IMG_20231210_232357.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="2013" data-original-width="2379" height="271" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh2OvswmBUOlZ-NGbWVZtP4Ul_E2msdqVcIJxdONyfXXVQoHfHZiKwHm0s4IhOsNHL80sucg5FmO6kEDrVuKNgYrDlisHIW_WO2GwtJNcoG53Yc_BPdeZuzX7VGGSf2gS2iHPMr-R_us18sRkTD21q2WkGXgBWfP9CcVuAG4skq8Ueyk4LG68wAAiFjEQI/s320/IMG_20231210_232357.jpg" width="320" /></a></div><br /><h1 style="text-align: left;">使ったもの</h1><ul style="text-align: left;"><li>特殊ビット<br />aliexpressで購入しました。<br />最も種類が多く含まれているものを送料込で1000円弱で購入し、1週間ほどで届きました。<br /><a href="https://ja.aliexpress.com/item/1005005815220573.html?spm=a2g0o.order_list.order_list_main.5.64e1585ayl15fY&gatewayAdapt=glo2jpn">精密されたu字型トライアングルドライバー磁気ビット1/4インチクロス3ポイントスクリュードライバーパワードリル用セキュリティチップ</a><br /><br />上記ページのビットは接続部の窪みから端までがVESSELのビットに比べて短いので、力を加えるとドライバーの固定具から外れて奥に押し込まれることがあります。<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjz16bZsiH56TLkHa6cIK-H3QdZYBYecFLNLk_0nktr71snloLXv5EQz_rvwRktPk_kkzNA7xlDFkJmUfR2iT2HELqT3D45C4BVhaqMkA-kpw4lYtKHCUDQleZo3FtVDdJmJmlumul0-MnhHERAoncSTQrXachOlX470sDWpLlbgDjNzxBUA2ppQDgUsUg/s2229/IMG_20231210_230942~2.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="2229" data-original-width="1512" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjz16bZsiH56TLkHa6cIK-H3QdZYBYecFLNLk_0nktr71snloLXv5EQz_rvwRktPk_kkzNA7xlDFkJmUfR2iT2HELqT3D45C4BVhaqMkA-kpw4lYtKHCUDQleZo3FtVDdJmJmlumul0-MnhHERAoncSTQrXachOlX470sDWpLlbgDjNzxBUA2ppQDgUsUg/s320/IMG_20231210_230942~2.jpg" width="217" /></a></div>そのような挙動を避けたい方は、次に紹介するamazonで売られているビットをお試しください。<br />そして、良ければ期待通りにネジを回せたかコメントなどで教えていただけると嬉しいです。<br /><br />未検証ですが、amazonで買うならY型ネジ用の下記商品が合うと思います。<br /><iframe frameborder="0" marginheight="0" marginwidth="0" sandbox="allow-popups allow-scripts allow-modals allow-forms allow-same-origin" scrolling="no" src="//rcm-fe.amazon-adsystem.com/e/cm?lt1=_blank&bc1=000000&IS2=1&bg1=FFFFFF&fc1=000000&lc1=0000FF&t=asukiaaa-22&language=ja_JP&o=9&p=8&l=as4&m=amazon&f=ifr&ref=as_ss_li_til&asins=B001YH87GC&linkId=aaf4fc68e7d42f3236966d44229e9a7f" style="height: 240px; width: 120px;"></iframe><br /><br />上記の単品で買えるのを後から知り、下記のセットの価格だけ見て怯んでaliexpressに頼りました。<br /><iframe frameborder="0" marginheight="0" marginwidth="0" sandbox="allow-popups allow-scripts allow-modals allow-forms allow-same-origin" scrolling="no" src="//rcm-fe.amazon-adsystem.com/e/cm?lt1=_blank&bc1=000000&IS2=1&bg1=FFFFFF&fc1=000000&lc1=0000FF&t=asukiaaa-22&language=ja_JP&o=9&p=8&l=as4&m=amazon&f=ifr&ref=as_ss_li_til&asins=B001YH85V4&linkId=e4a9679502175ef67f9bdc8c027a6acf" style="height: 240px; width: 120px;"></iframe></li><li>電ドラボール<br />ビットを取り付けてねじを回せるなら何でも良いです。<br /><iframe frameborder="0" marginheight="0" marginwidth="0" sandbox="allow-popups allow-scripts allow-modals allow-forms allow-same-origin" scrolling="no" src="//rcm-fe.amazon-adsystem.com/e/cm?lt1=_blank&bc1=000000&IS2=1&bg1=FFFFFF&fc1=000000&lc1=0000FF&t=asukiaaa-22&language=ja_JP&o=9&p=8&l=as4&m=amazon&f=ifr&ref=as_ss_li_til&asins=B09V218NSD&linkId=927b46a33c2a52f7f3aeee4569d758ce" style="height: 240px; width: 120px;"></iframe><br /></li><li>「はんだごてとペンチかピンセット」もしくは「 ニッパー」<br />元に戻せる改造をするなら、はんだごてと熱いものを掴むためのペンチかピンセットを用意します。<br />元に戻せなくて良いならニッパーだけで良いです。<br /><iframe frameborder="0" marginheight="0" marginwidth="0" sandbox="allow-popups allow-scripts allow-modals allow-forms allow-same-origin" scrolling="no" src="//rcm-fe.amazon-adsystem.com/e/cm?lt1=_blank&bc1=000000&IS2=1&bg1=FFFFFF&fc1=000000&lc1=0000FF&t=asukiaaa-22&language=ja_JP&o=9&p=8&l=as4&m=amazon&f=ifr&ref=as_ss_li_til&asins=B006MQD7M4&linkId=966a3c5700b7148d553081e31eda7fff" style="height: 240px; width: 120px;"></iframe> <iframe frameborder="0" marginheight="0" marginwidth="0" sandbox="allow-popups allow-scripts allow-modals allow-forms allow-same-origin" scrolling="no" src="//rcm-fe.amazon-adsystem.com/e/cm?lt1=_blank&bc1=000000&IS2=1&bg1=FFFFFF&fc1=000000&lc1=0000FF&t=asukiaaa-22&language=ja_JP&o=9&p=8&l=as4&m=amazon&f=ifr&ref=as_ss_li_til&asins=B09ZHWCXGR&linkId=f844f38bb0c95f27407cef284787763e" style="height: 240px; width: 120px;"></iframe></li></ul><br /><h1 style="text-align: left;">開ける</h1>Y型の特殊ネジが付いているので、対応する特殊ビットで開けます。<br /><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhDjHVyjTIhAOP8BxWTAy1NvwzzfFjPacA09F9jxxUsprxtb-TnoG5jIDbyk2DED5jQGATJbC51393S_s1TBF21C0MiNHmPVITh9AflmJ7UwEAWyA-OYzr-ce-eeKoxjksTYqt2dzPMyUMo7MCiWCn5jgJvwqfRDn46XEVtPrIgUB9UI6bGjYA0SPiNPHw/s2777/IMG_20231209_113905.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="2345" data-original-width="2777" height="270" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhDjHVyjTIhAOP8BxWTAy1NvwzzfFjPacA09F9jxxUsprxtb-TnoG5jIDbyk2DED5jQGATJbC51393S_s1TBF21C0MiNHmPVITh9AflmJ7UwEAWyA-OYzr-ce-eeKoxjksTYqt2dzPMyUMo7MCiWCn5jgJvwqfRDn46XEVtPrIgUB9UI6bGjYA0SPiNPHw/s320/IMG_20231209_113905.jpg" width="320" /></a></div><br />開きました。<br />改造を思い立ってからここまでに2週間かかりました。<br /><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgQywmIwyc1k_qCvPb8VGCRmSKASaxtsHP_exsPv4s840qEeAifZteiKoNqg8zSxGpdCNAbxdyBFrT0R_s7EI06jgYNxgyNjRDuyas8Jda5nV2CJo0LMWMO2wE1C-Wyr0SjFxu4IxVXKiMmFMLImRvBOSW00cDQd9t1yKVCyeA5D9EbamXE_pkc5zNsb7g/s3946/IMG_20231209_114055.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1825" data-original-width="3946" height="296" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgQywmIwyc1k_qCvPb8VGCRmSKASaxtsHP_exsPv4s840qEeAifZteiKoNqg8zSxGpdCNAbxdyBFrT0R_s7EI06jgYNxgyNjRDuyas8Jda5nV2CJo0LMWMO2wE1C-Wyr0SjFxu4IxVXKiMmFMLImRvBOSW00cDQd9t1yKVCyeA5D9EbamXE_pkc5zNsb7g/w640-h296/IMG_20231209_114055.jpg" width="640" /></a></div><br /><h1 style="text-align: left;">改造対象を確認</h1>光る部分はダイオードと抵抗とLEDで回路が構成され、それが基板に載っていました。<br /><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj40VdSq8PezNiOCxGnqHS5qXrCf-TtJDNHRqRqAhZTssB8-BKzdrfsbUQnySu7GBICaqGwrT0r4m1zLgFRkMHyD_Q-ZgB9EjKZVl4c2Nuds_xI07w9TKJsMbz4KZPuPGdfGQiH8ZLvrO2xXJww80QwT0BDMea3xLMLMEnBoN07r-9iQeRHx4qeqtX45PQ/s1546/IMG_20231209_114257.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1305" data-original-width="1546" height="270" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj40VdSq8PezNiOCxGnqHS5qXrCf-TtJDNHRqRqAhZTssB8-BKzdrfsbUQnySu7GBICaqGwrT0r4m1zLgFRkMHyD_Q-ZgB9EjKZVl4c2Nuds_xI07w9TKJsMbz4KZPuPGdfGQiH8ZLvrO2xXJww80QwT0BDMea3xLMLMEnBoN07r-9iQeRHx4qeqtX45PQ/s320/IMG_20231209_114257.jpg" width="320" /></a></div><br />抵抗は赤黒黄金なので200kΩが使われていました。<br /><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEixUDst0wsM4JE5JW0lUebXhzY_OpLbQe7CXpUp3g7tVUuFqJmp6EjdDueGTo_gDdd_L55UZ1wgZFTyVop3fSsurCI0sDFJ8kwxZZF-7P8OAacRDvkXUoOK5e59LHktzFwE2R5xYFxENeH4l5DMFRr9CTCLnl7dVlWjmDyCt3jUW-cbnMXeMXxbmqKm4YQ/s1260/IMG_20231209_114323.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1260" data-original-width="1068" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEixUDst0wsM4JE5JW0lUebXhzY_OpLbQe7CXpUp3g7tVUuFqJmp6EjdDueGTo_gDdd_L55UZ1wgZFTyVop3fSsurCI0sDFJ8kwxZZF-7P8OAacRDvkXUoOK5e59LHktzFwE2R5xYFxENeH4l5DMFRr9CTCLnl7dVlWjmDyCt3jUW-cbnMXeMXxbmqKm4YQ/s320/IMG_20231209_114323.jpg" width="271" /></a></div><br />雷サージ対応として<a href="https://www.anglia-live.com/product/142120001/GNR14D391K/CERAMATE">GNR14D391K</a>という型のバリスタ(EMI除去フィルター)が載っていました。<br />データシートによると実効値250V以下のAC電源に対応しているので、バリスタは200Vの電源でも耐えてくれます。<br /><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjAUQoCG6UXsoKsk8R2avArIIDoDUPiXsjVQcl4sLkmF5peF_bJOyntaMdHFCQIPyrUdHe2WAYA9V0peR0stYj001dMYNhegN-3kPCu8TmdMVshojtosAaEvNuDJi-5egNTpB3l-mKf40H1-3nZY6wxPBzjSw9tMIJQbEvy-O66i2rlV8tS_TpGZS4EltI/s1294/original_e2c35f42-8923-4dfb-8f97-b129500fc454_IMG_20231209_114511.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1294" data-original-width="1242" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjAUQoCG6UXsoKsk8R2avArIIDoDUPiXsjVQcl4sLkmF5peF_bJOyntaMdHFCQIPyrUdHe2WAYA9V0peR0stYj001dMYNhegN-3kPCu8TmdMVshojtosAaEvNuDJi-5egNTpB3l-mKf40H1-3nZY6wxPBzjSw9tMIJQbEvy-O66i2rlV8tS_TpGZS4EltI/s320/original_e2c35f42-8923-4dfb-8f97-b129500fc454_IMG_20231209_114511.jpg" width="307" /></a></div><br />製品仕様は125Vなのので、間違えて200V電源に接続しても耐えられる部品が選ばれたようです。<br /><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgDm3X-2RIVRt1P7Q_rxUoke4STNfeYFs1H0VCZG8OMYcAZ3ZF1q3ucKKw0JxrBxawmfLUcKXAPYoBBO-JP3El1Ch8I3OhwETfqQLaUEgzbfGUqAGeZijmduWkcjDW2Kjn2zSYMhantYbB_R1de7fqqDsqiZtyNjbfHnnVdlKuLuUEuIWg_8W9v6auiZvA/s3657/IMG_20231210_223123~2.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="3657" data-original-width="2399" height="640" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgDm3X-2RIVRt1P7Q_rxUoke4STNfeYFs1H0VCZG8OMYcAZ3ZF1q3ucKKw0JxrBxawmfLUcKXAPYoBBO-JP3El1Ch8I3OhwETfqQLaUEgzbfGUqAGeZijmduWkcjDW2Kjn2zSYMhantYbB_R1de7fqqDsqiZtyNjbfHnnVdlKuLuUEuIWg_8W9v6auiZvA/w420-h640/IMG_20231210_223123~2.jpg" width="420" /></a></div><br />LEDとバリスタの部分を回路図に起こすとこうなります。<br /><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi4hWkyzVsVG3S-hDwwJN2zf5Rv9wDV9dpc0mTgU0V8sS6NEX8wRAJp3WZ9scXguij_1O_7TSwcBqB9TyMHg7IiGvL3c5MyL7ausWIzmpPO_7u3fAv7Im02pEHbkSQ5foxXRIcg7fjJsf0OHpekIdFvhZB3zHxX9iyXETYXE3MmQaPJd414u5BgXHYDddw/s405/Screenshot%20from%202023-12-10%2022-45-14.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="392" data-original-width="405" height="310" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi4hWkyzVsVG3S-hDwwJN2zf5Rv9wDV9dpc0mTgU0V8sS6NEX8wRAJp3WZ9scXguij_1O_7TSwcBqB9TyMHg7IiGvL3c5MyL7ausWIzmpPO_7u3fAv7Im02pEHbkSQ5foxXRIcg7fjJsf0OHpekIdFvhZB3zHxX9iyXETYXE3MmQaPJd414u5BgXHYDddw/s320/Screenshot%20from%202023-12-10%2022-45-14.png" width="320" /></a></div><br /><h1 style="text-align: left;">ダイオードを外してLEDへの通電を停止</h1>LEDが繋がっている回路を切断すれば光らなくなるので、今回は外しやすいダイオードを抜いて切断します。<br /><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjK_YUWx88HaAVihQFrr2yWhZ-UO8RPSBYGg2Ukd6kcru4YYkEBzJRNAnjbTi0r2TL-OSC2XSujGuaz2hL9d3WbC1fY1W2zEO4gyTgpBfzDrIQfhTt2lNYVg-UgkLygpmPawXpStqQdLrhHfX-zmh_8u2sA86SGjiNKwQg5rVgJbsm5xIm3pLkwS6MnRlw/s405/cut_diode_line.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="392" data-original-width="405" height="310" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjK_YUWx88HaAVihQFrr2yWhZ-UO8RPSBYGg2Ukd6kcru4YYkEBzJRNAnjbTi0r2TL-OSC2XSujGuaz2hL9d3WbC1fY1W2zEO4gyTgpBfzDrIQfhTt2lNYVg-UgkLygpmPawXpStqQdLrhHfX-zmh_8u2sA86SGjiNKwQg5rVgJbsm5xIm3pLkwS6MnRlw/s320/cut_diode_line.png" width="320" /></a></div><br />はんだごてでダイオードが繋がっているハンダを加熱し、ピンセットで抜きました。<br /><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjVvxcnlcUW1HOk3y2FVrq9dr4n98Bs3C87YeSLCL994SB2U0tYFTyTBO91MzABErLUrMaEqTJaDiAFG5MpFn_vtGQCoZsAIRxwL1V7LFzPf4aVf8psEj05fw6Y30cQC7HYTxKrY5kCLGmrJzCjCMP2IuEsJMoIfzlR7wEtLIQnECsLH8YY1-9RVqCRQ8k/s980/IMG_20231209_115350.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="980" data-original-width="897" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjVvxcnlcUW1HOk3y2FVrq9dr4n98Bs3C87YeSLCL994SB2U0tYFTyTBO91MzABErLUrMaEqTJaDiAFG5MpFn_vtGQCoZsAIRxwL1V7LFzPf4aVf8psEj05fw6Y30cQC7HYTxKrY5kCLGmrJzCjCMP2IuEsJMoIfzlR7wEtLIQnECsLH8YY1-9RVqCRQ8k/s320/IMG_20231209_115350.jpg" width="293" /></a></div><br />抜いた後は切断状態を維持しつつも箱に戻す際に干渉しないように足を横に曲げました。<br /><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEioTurEpQrFdLvTb7jk57bbyzJMQw2SRUqHB-OyGGhh9yGa4tAeXrxkgRyNbTv75qmioJGkJ0WvxsRRHH_slqnq2KV8DfZtB5XlgsSzPw_DzPh_o2fkXHKxkQfoWbebjJteNGK49OaBCMfzySYPMLY1LUFLlwxhNXo0pN2wKwQ3AQ1Zm5A3av33oc2iN48/s1178/IMG_20231209_115751.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1178" data-original-width="901" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEioTurEpQrFdLvTb7jk57bbyzJMQw2SRUqHB-OyGGhh9yGa4tAeXrxkgRyNbTv75qmioJGkJ0WvxsRRHH_slqnq2KV8DfZtB5XlgsSzPw_DzPh_o2fkXHKxkQfoWbebjJteNGK49OaBCMfzySYPMLY1LUFLlwxhNXo0pN2wKwQ3AQ1Zm5A3av33oc2iN48/s320/IMG_20231209_115751.jpg" width="245" /></a></div><br /><h1 style="text-align: left;">基板を元に戻して閉じる</h1>元の位置に戻して蓋をしてネジ止めしたら改造終了です。<br /><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjgnsVj3U_eiqvuiSOdiqbtwU3wMQbQeX7vpcwiENtCWhR1Sr3JVez1PTJu-p3Wc01UmwfHMP3NXdHN1d3l1EWLBUZuSA9LO1PIfK82XEc6p8wCkHGvqui4uLYn7LaXQrTvk_qUuW233bZxmAIp5ei6HkqbHELJ2yStlH-XMMq6O6CUQLgej29npq2vkC8/s1864/IMG_20231209_115836.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1436" data-original-width="1864" height="247" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjgnsVj3U_eiqvuiSOdiqbtwU3wMQbQeX7vpcwiENtCWhR1Sr3JVez1PTJu-p3Wc01UmwfHMP3NXdHN1d3l1EWLBUZuSA9LO1PIfK82XEc6p8wCkHGvqui4uLYn7LaXQrTvk_qUuW233bZxmAIp5ei6HkqbHELJ2yStlH-XMMq6O6CUQLgej29npq2vkC8/s320/IMG_20231209_115836.jpg" width="320" /></a></div><br /><h1 style="text-align: left;">動作確認</h1>LEDの回路を切断したことにより、通電しても光らないスイッチ付きのコンセント延長ケーブルになりました。<br /><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiMWkAfVB8hqjL1jwAKagU1pb6RcW0wfW6S9dwz5hBe_A0XenZICa5YT3niuvYqYb36n2Jhb-ZDiQmx563HLkK3v1_gXdaUZ43imZ-oFHSaxCYvYnIv1YymaHOiOjTqrVPsgpwMqm-FDHyW0gC_THpwcQp-skp-pq6tRJvP37uz5RDBsScdhqcDj7cIl5E/s2430/IMG_20231209_122214.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="2430" data-original-width="1880" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiMWkAfVB8hqjL1jwAKagU1pb6RcW0wfW6S9dwz5hBe_A0XenZICa5YT3niuvYqYb36n2Jhb-ZDiQmx563HLkK3v1_gXdaUZ43imZ-oFHSaxCYvYnIv1YymaHOiOjTqrVPsgpwMqm-FDHyW0gC_THpwcQp-skp-pq6tRJvP37uz5RDBsScdhqcDj7cIl5E/s320/IMG_20231209_122214.jpg" width="248" /></a></div><br /><h1 style="text-align: left;">終わり</h1>光らないのを期待して買って帰ったケーブルが光ったときは落胆し、改造しようと裏側を見たら特殊なYネジですぐには開けれず再び落胆しましたが、道具を揃えて期待通り光らない改造ができて良かったです。<br /><br />Asuki Konohttp://www.blogger.com/profile/07813182469285556500noreply@blogger.com0tag:blogger.com,1999:blog-9198372554518889060.post-22936082254042200432023-12-03T23:47:00.001+09:002023-12-03T23:47:22.006+09:00stm32に対してポートを指定してplatformioでプログラムを書き込むlinux向けのスクリプトを書いた<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiA6LgSbX8PGQbfzQciGgy0hZXVOG0Qedg9nYiyLNPD1ZjQrjb46sdVijQEUpAJWLq0ZSMNBahkHrFvV2fZfI_Ruxn6fIDkd3-Ms1AYMCwbngB-W0eJAeuThyhPpbxQYEtqc9AMRAqROhmL2eI19b5LCXhN3Yq9KWXWU7hguZpiuklyixOtIFyD0ASpur8/s2394/IMG_20231203_234424~2.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="2276" data-original-width="2394" height="304" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiA6LgSbX8PGQbfzQciGgy0hZXVOG0Qedg9nYiyLNPD1ZjQrjb46sdVijQEUpAJWLq0ZSMNBahkHrFvV2fZfI_Ruxn6fIDkd3-Ms1AYMCwbngB-W0eJAeuThyhPpbxQYEtqc9AMRAqROhmL2eI19b5LCXhN3Yq9KWXWU7hguZpiuklyixOtIFyD0ASpur8/s320/IMG_20231203_234424~2.jpg" width="320" /></a></div><br /><h1 style="text-align: left;">背景</h1>前回<a href="https://asukiaaa.blogspot.com/2023/11/specify-stm32-on-multiple-connectoins.html">stm32を複数台繋げた状態で、それぞれを識別してプログラムを書き込む方法</a>を把握しました。<br />方法が分かったのは良いのですが、都度stlinkのid serialを調べるのが手間なので、ポートを渡したらplatformioで書き込んでくれるスクリプトを書きました。<br />使い方を共有します。<br /><br /><h1 style="text-align: left;">コードをclone(ダウンロード)</h1>便利スクリプトをまとめているgithubのリポジトリに上げています。<br /><a href="https://github.com/asukiaaa/useful-scripts/blob/master/platformio/upload-to-stm32-port">https://github.com/asukiaaa/useful-scripts/blob/master/platformio/upload-to-stm32-port</a><br /><br /><a href="https://asukiaaa.blogspot.com/2023/11/specify-stm32-on-multiple-connectoins.html">前回の記事</a>で把握したstlinkのserial idをポートから調べてアップロードコマンドに渡すスクリプトです。<br />記事を書いている時点での内容はこちらです。<br /><pre>#!/bin/bash<br /><br />if [ "$1" = "" ]; then<br /> echo "Please execute with path of stm32 serial port.<br />$0 port<br /><br />Example:<br />$0 /dev/ttyACM0"<br /> exit 1<br />fi<br /><br />PORT=$1<br />SERIAL_RAW=$(udevadm info $PORT | grep SERIAL_SHORT=)<br />SERIAL=${SERIAL_RAW#*=}<br />PLATFORMIO_UPLOAD_FLAGS="-cadapter serial $SERIAL" pio run -t upload ${@: 2}<br /></pre><br />適当な場所にcloneしてください。<br />下記のコマンドはホームディレクトリにgitprojectsというディレクトリを作り、その中にリポジトリをcloneしています。<br /><pre>mkdir -p ~/gitprojects<br />cd ~/gitprojects<br />git clone https://github.com/asukiaaa/useful-scripts.git<br /></pre><br />上記の場所にリポジトリを置くと下記のコマンドで呼び出せます。<br /><pre>~/gitprojects/useful-scripts/platformio/upload-to-stm32-port</pre><br /><h1 style="text-align: left;">ポートを指定して実行</h1>先程cloneしたコマンドをplatformioのプロジェクトの中で対象のポート名と共に呼び出せば、ポートを指定してプログラムを書き込めます。<br /><pre>cd [stm32のplatformioのプロジェクト]<br />~/gitprojects/useful-scripts/platformio/upload-to-stm32-port /dev/ttyACM0<br /></pre><br />第2引数以後はplatformioのコマンドに渡しているので、-vオプションでplatformioのコマンドの確認も可能です。<br /><pre>~/gitprojects/useful-scripts/platformio/upload-to-stm32-port /dev/ttyACM0 -v<br /></pre><br /><h1 style="text-align: left;">おわり</h1>細かいことを考えずstm32に対してポートを指定してプログラムを書き込めるようになり嬉しいです。<br /><br /><h1 style="text-align: left;">参考</h1><a href="https://asukiaaa.blogspot.com/2023/11/specify-stm32-on-multiple-connectoins.html">PCに複数繋げたstm32を判別してplatformioでプログラムを書き込む</a><br /><br />Asuki Konohttp://www.blogger.com/profile/07813182469285556500noreply@blogger.com0tag:blogger.com,1999:blog-9198372554518889060.post-20198123238413338912023-11-26T21:45:00.002+09:002023-12-03T23:51:12.462+09:00PCに複数繋げたstm32を判別してplatformioでプログラムを書き込む<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhpAn5vUmAu4xietGUcBAJNiliuC2avPf-oiTNcvvBqv7uYhR0yfsVe3x7JZDWNIAFLKiN_MK42DreXGC0Eu8XbkcC7CUQzV-7wbF7dfNHTiwvoht97kdUXEPfS_tbnZa9RtfYTH25fW2xG0GiZcgMI6zzHVGppGfUbPE5s-688jGV5pL29C49VywzjdDk/s2540/IMG_20231126_153900~2.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="2540" data-original-width="2207" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhpAn5vUmAu4xietGUcBAJNiliuC2avPf-oiTNcvvBqv7uYhR0yfsVe3x7JZDWNIAFLKiN_MK42DreXGC0Eu8XbkcC7CUQzV-7wbF7dfNHTiwvoht97kdUXEPfS_tbnZa9RtfYTH25fW2xG0GiZcgMI6zzHVGppGfUbPE5s-688jGV5pL29C49VywzjdDk/s320/IMG_20231126_153900~2.jpg" width="278" /></a></div><br /><h1 style="text-align: left;">背景</h1>複数のstm32を同時にPCに繋げてplatformioを利用していたところ、uploat-portの指定が効かず片方にしかプログラムを書き込めない場面に出くわしました。<br />調べたところopenocdかmbedの設定に従えば判別できると分かりました。<br />備忘録として対応内容を記事に残します。<br /><br /><h1 style="text-align: left;">使ったもの</h1><ul style="text-align: left;"><li>ubuntu22.04をインストールしたPC</li><li>VSCode + platformioプラグイン</li><li>nucleo-f429zi</li><li>nucleo-l432kc</li><li>usbハブ</li></ul><br /><h1 style="text-align: left;">upload_protocol = stlink (標準)の場合</h1>stlinkはopenocdを使っているため、それのオプションで対象を指定できます。<br />調査と試行の結果2種類の指定方法を把握したので、それぞれ解説します。<br /><br /><h2 style="text-align: left;">adapter serial(旧hla_serial)でserialのidを指定</h2>stlinkのserialのidは認識されているシリアルポートに対してudevadmコマンドを実行して確認できます。<br /><pre>udevadm info /dev/ttyACM0 | grep SERIAL</pre><pre>E: ID_SERIAL=STMicroelectronics_STM32_STLink_066BFF494877514867174753<br />E: ID_SERIAL_SHORT=066BFF494877514867174753<br /></pre><br />調べたserialのidをupload flagsで<a href="https://openocd.org/doc/html/Debug-Adapter-Configuration.html">adapter serial</a>として指定します。<br />
<div class="pre-box">
<div class="pre-name">platformio.ini</div>
<pre>upload_flags =<br /> -c<br /> adapter serial 066BFF494877514867174753<br /></pre>
</div>
<br />1行で書く場合は、1行書きで-cとadapterの間にスペースがあると正しく解釈されず動かない場合があるので、スペース無しで記述するのが良いです。<br />問題に取り組んでいるときはその不具合が発生したのですが、記事を書いているときはスペースがあっても動いたので、何が悪いのか不明です。<br />参考: <a href="https://community.platformio.org/t/unnecessary-double-quotes-with-upload-flags/23876">Unnecessary double quotes with upload_flags</a><br />
<div class="pre-box">
<div class="pre-name">platformio.ini</div>
<pre>upload_flags =<br /> -cadapter serial 066BFF494877514867174753<br /></pre>
</div>
<br />上記の設定で書き込めば、指定した装置に対して書き込めます。<br /><br /><a href="https://docs.platformio.org/en/latest/envvars.html#envvar-PLATFORMIO_UPLOAD_FLAGS">環境変数PLATFORMIO_BUILD_FLAGS</a>を使えば設定ファイルに書き込まずコマンドで指定できます。<br /><pre>PLATFORMIO_UPLOAD_FLAGS="-cadapter serial 066BFF494877514867174753" pio run -t upload</pre><br /><h2 style="text-align: left;">adapter usb locationでstlinkが繋がっているusbポートを指定</h2>usbポートを指定して書き込みます。<br />「IDは指定しなくて良いが、この目的のこの種類のマイコンはこのUSBポートに繋ぐ」ような場面で便利です。<br /><br />シリアルポートからusbポートの場所を探る場合、udevadmで表示されるパスから読み取れます。<br /><pre>udevadm info /dev/ttyACM0 | grep P:</pre><pre>P: /devices/pci0000:00/0000:00:14.0/usb2/2-1/2-1.1/2-1.1:1.2/tty/ttyACM0<br /></pre><br />上記の表示の場合、下記の2-1.1がusbポートの場所情報です。<br /><pre>P: /devices/pci0000:00/0000:00:14.0/usb2/2-1/2-1.1/2-1.1:1.2/tty/ttyACM0<br /> ^^^^^<br /></pre><br />usbポートの全体像は下記コマンドで確認できます。<br /><pre>lsusb -t</pre><pre>/: Bus 03.Port 1: Dev 1, Class=root_hub, Driver=xhci_hcd/4p, 5000M<br /> |__ Port 1: Dev 6, If 0, Class=Hub, Driver=hub/4p, 5000M<br />/: Bus 02.Port 1: Dev 1, Class=root_hub, Driver=xhci_hcd/9p, 480M<br /> |__ Port 1: Dev 75, If 0, Class=Hub, Driver=hub/4p, 480M<br /> |__ Port 1: Dev 84, If 3, Class=CDC Data, Driver=cdc_acm, 12M << ここ<br /> |__ Port 1: Dev 84, If 1, Class=Mass Storage, Driver=usb-storage, 12M << ここ<br /> |__ Port 1: Dev 84, If 2, Class=Communications, Driver=cdc_acm, 12M << ここ<br /> |__ Port 1: Dev 84, If 0, Class=Vendor Specific Class, Driver=, 12M << ここ<br /> |__ Port 2: Dev 77, If 0, Class=Vendor Specific Class, Driver=, 12M<br /> |__ Port 2: Dev 77, If 1, Class=Mass Storage, Driver=usb-storage, 12M<br /> |__ Port 2: Dev 77, If 2, Class=Communications, Driver=cdc_acm, 12M<br /> |__ Port 2: Dev 77, If 3, Class=CDC Data, Driver=cdc_acm, 12M<br /> |__ Port 4: Dev 2, If 0, Class=Wireless, Driver=btusb, 12M<br /> |__ Port 4: Dev 2, If 1, Class=Wireless, Driver=btusb, 12M<br /> |__ Port 5: Dev 3, If 0, Class=Human Interface Device, Driver=usbhid, 12M<br /> |__ Port 6: Dev 4, If 0, Class=Video, Driver=uvcvideo, 480M<br /> |__ Port 6: Dev 4, If 1, Class=Video, Driver=uvcvideo, 480M<br />/: Bus 01.Port 1: Dev 1, Class=root_hub, Driver=ehci-pci/3p, 480M<br /> |__ Port 1: Dev 2, If 0, Class=Hub, Driver=hub/8p, 480M<br /> |__ Port 7: Dev 3, If 0, Class=Human Interface Device, Driver=usbhid, 12M<br /> |__ Port 8: Dev 6, If 0, Class=Human Interface Device, Driver=usbhid, 12M<br /></pre>「<<ここ」と示しているのが今回の書き込み先です。<br />Bus 02 の Port 1 のPort 1 であり、udevadmで読み取った2-1.1と合っているのが分かります。<br /><br />これを<a href="https://openocd.org/doc/html/Debug-Adapter-Configuration.html">adapter usb location</a>として指定します。<br />
<div class="pre-box">
<div class="pre-name">platformio.ini</div>
<pre>upload_flags =<br /> -c<br /> adapter usb location 2-1.1<br /></pre>
</div>
<br />上記の設定で書き込めば、指定した装置に対して書き込めます。<br /><br /><a href="https://docs.platformio.org/en/latest/envvars.html#envvar-PLATFORMIO_UPLOAD_FLAGS">環境変数PLATFORMIO_BUILD_FLAGS</a>を使えば設定ファイルに書き込まずコマンドで指定できます。<br /><pre>PLATFORMIO_UPLOAD_FLAGS="-c adapter usb location 2-1.1" pio run -t upload</pre><br /><h1 style="text-align: left;">upload_protocol = mbedの場合</h1>mbedモードの場合は、stlinkがマウントされているメディアのパスを指定します。<br />ubuntuの場合は「/media/${USER}/」にマイコンの名前を含んだメディアとしてマウントされます。<br /><pre>pio run -t upload --upload-port /media/asuki/NODE_L432KC/</pre><br />mbedモードでシリアルポートを--upload-portとして指定していると、それはディレクトリではないというエラーが出ます。<br /><pre>*** [upload] /dev/ttyACM0/firmware.bin: Not a directory</pre><br /><h1 style="text-align: left;">おわり</h1>stlinkの場合はserialのidを、mbedの場合はマウントされたメディアを指定することで、優先的に書き込まれる装置のUSBを外して書き込み後につなぎ直してシリアルモニタを繋ぎ直すという手間なことをしなくても複数同時にstm32をstlinkで開発できるようになりました。<br /><br />記事にまとめた方法の他に便利な指定方法がありましたら、コメントなどで共有していただけると嬉しいです。<br /><br /><h1 style="text-align: left;">続編情報</h1>ポートを指定したらstlinkでプログラムを書き込める便利スクリプトを書きました。<br />よかったらご利用ください。<br /><br /><a href="https://asukiaaa.blogspot.com/2023/12/upload-to-port-of-stm32-with-using-useful-script.html">stm32に対してポートを指定してplatformioでプログラムを書き込むlinux向けのスクリプトを書いた</a><br /><a href="https://github.com/asukiaaa/useful-scripts/blob/master/platformio/upload-to-stm32-port">https://github.com/asukiaaa/useful-scripts/blob/master/platformio/upload-to-stm32-port</a><br /><br /><h1 style="text-align: left;">参考</h1>stlink利用時の指定方法を把握したページです。<br /><a href="https://www.bergzand.net/programming-with-multiple-st-link-programmers.html">Programming with multiple ST-Link programmers</a><br /><a href="https://community.platformio.org/t/more-than-one-st-link-for-upload-several-devices-are-connected-to-pc/12727/3">More than one ST-Link for upload (several devices are connected to PC_</a><br /><a href="https://community.platformio.org/t/stlink-upload-port/19170/3"> STLink upload_port</a><br /><br />upload_flagsの指定で改行の位置が解釈不具合の原因と把握したページです。<br /><a href="https://community.platformio.org/t/unnecessary-double-quotes-with-upload-flags/23876">Unnecessary double quotes with upload_flags</a><br /><br />openocdのadapterコマンドの解説ページです。<br /><a href="https://openocd.org/doc/html/Debug-Adapter-Configuration.html">8 Debug Adapter Configuration</a><br /><br />usbポートの位置把握の参考にしたページです。<br /><a href="https://stackoverflow.com/questions/58072009/how-to-interpret-tcl-command-in-openocd-manual">How to interpret tcl command in openOCD manual</a><br /><a href="https://askubuntu.com/questions/184526/how-to-get-bus-and-device-relationship-for-a-dev-ttyusb">How to get Bus and Device relationship for a /dev/ttyUSB</a><br /><br />mbed利用時の指定方法を把握したページです。<br /><a href="https://community.platformio.org/t/error-upload-port-for-environment-or-use-global-upload-port-option/24126">Error `upload_port` for environment or use global `–upload-port` option</a><br /><br /><h1 style="text-align: left;">変更履歴</h1>2023.12.03 続編情報として便利スクリプトと紹介ページへのリンクを追加しました。<br /><br />Asuki Konohttp://www.blogger.com/profile/07813182469285556500noreply@blogger.com0tag:blogger.com,1999:blog-9198372554518889060.post-23485138664979284712023-11-20T08:31:00.002+09:002023-11-21T13:46:15.854+09:00ubuntu22.04にstm32f429zi向けのrustでの開発環境を作りプログラムを実行<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEioDrRhSP0ZmHikfqvETHRVo9rAvKh6d3jIPRyYlpP_vjy_hhLN5xG9ZEKsUmA_0cKEqrpmHYkK9EN8cAb7ZRBxT6GRxY6V_A6hCsVbkaavNUXfVzNQ1morLhANx3Ww9pDXoHm3JqjIVX_1_mgUb-YYjRpoCt-esSLQzPlwhoSxS1ioYHsSQ650sBrhikU/s1827/IMG_20231120_011959.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1784" data-original-width="1827" height="312" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEioDrRhSP0ZmHikfqvETHRVo9rAvKh6d3jIPRyYlpP_vjy_hhLN5xG9ZEKsUmA_0cKEqrpmHYkK9EN8cAb7ZRBxT6GRxY6V_A6hCsVbkaavNUXfVzNQ1morLhANx3Ww9pDXoHm3JqjIVX_1_mgUb-YYjRpoCt-esSLQzPlwhoSxS1ioYHsSQ650sBrhikU/s320/IMG_20231120_011959.jpg" width="320" /></a></div><br /><h1 style="text-align: left;">背景</h1>stm32マイコンには有志によって作られたrustのプログラム環境と関連機能呼び出しライブラリがあります。<br /><br /><a href="https://github.com/stm32-rs">stm32-rs</a><br /><br />気になっていたのでubuntuに環境を構築してボタン認識とLED点灯をさせてみました。<br />備忘録として取り組んだ内容を記事に残します。<br /><br /><h1 style="text-align: left;">使ったもの</h1><ul style="text-align: left;"><li>ubuntu22.04をインストールしたPC</li><li><a href="https://www.st.com/en/evaluation-tools/nucleo-f429zi.html">nucleo-stm32f429zi</a></li><li>micro USBケーブル</li></ul><br /><h1 style="text-align: left;">関連プログラムをインストール</h1>開発環境に必要なプログラムとそれのインストール手順を紹介します。<br /><br /><h2 style="text-align: left;">VSCode</h2>プログラム開発に便利な機能を備えたテキストエディタ(文章編集プログラム)です。<br /><br />ubuntu22.04だと<a href="https://code.visualstudio.com/docs/setup/linux#_snap">snap経由でインストール</a>できます。<br /><pre>sudo snap install --classic code</pre><br />インストール後はVSCodeを開いて「Ctrl + Shift + p」を押してコマンド入力欄を出し、下記のコマンドで「<a href="https://marketplace.visualstudio.com/items?itemName=MS-CEINTL.vscode-language-pack-ja">Japanese Language Pack for Visual Studio Code</a>」をインストールすれば、表示が日本語になります。<br />(自分が試したときは入力後に言語を手動で選択する画面が開いたので、コマンド実行後に選択操作が必要なのかもしれません。)<br /><pre>ext install MS-CEINTL.vscode-language-pack-ja</pre><br />2022年頃まではsnap版のVSCodeは日本語を入力できない不具合がありましたが、2023/11/20に自分が試したときは日本語を入力可能になっていました。<br />何らかの制限でsnap板ではなくdeb版を使いたいという方は、<a href="https://code.visualstudio.com/docs/setup/linux#_debian-and-ubuntu-based-distributions">debian系OS向けのインストール手順</a>に従ってインストールしてください。<br /><br /><h2 style="text-align: left;">VSCode プラグイン cortex-debug rust-analyzer</h2>今回の開発に便利な下記2つのプラグインをVSCodeのプラグイン一覧から検索してインストールしてください。<br /><br />cortex-debug: デバッグ時にブレークポイントを置いて動作確認するため<br /><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgz1fTLrzHlv52C999SWQzXxPujdidluAilo3euazve6NHqrQemOAT4gOxXb9Gd7-9GD7e0-yHFCs1KbwOC1FzniQKP6aYfdGgjTDAJ0Z0SBxFfO-61f3DoBPdBK5c5MOh0a0HD8gjxLflvr2pV28sN_qvu5kMa6y-9eNoM5u-rVRDQpTvAPMEFP1xVLGo/s216/Screenshot%20from%202023-11-20%2001-25-56.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="126" data-original-width="216" height="126" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgz1fTLrzHlv52C999SWQzXxPujdidluAilo3euazve6NHqrQemOAT4gOxXb9Gd7-9GD7e0-yHFCs1KbwOC1FzniQKP6aYfdGgjTDAJ0Z0SBxFfO-61f3DoBPdBK5c5MOh0a0HD8gjxLflvr2pV28sN_qvu5kMa6y-9eNoM5u-rVRDQpTvAPMEFP1xVLGo/s1600/Screenshot%20from%202023-11-20%2001-25-56.png" width="216" /></a></div><br />rust-analyzer: rust編集時の構文解析<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhimrC9vP51Gm_TLo1YrAZ49qEF67JNosXW8ZaAGrXMFkvFcGrZbvi_rr5HhVnEr6i6sv1cGx0lk4XfPun1NdIU-mkJjvTPBPADd5acSBz04DkEPZRViI6ZhUq7WCbMHQtwa0WyOryXcQ48TlXBlF6e00riGtHc7oL-6xXLqup5c5HYsdMyoRomxWp-dWQ/s216/Screenshot%20from%202023-11-20%2001-27-27.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="126" data-original-width="216" height="126" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhimrC9vP51Gm_TLo1YrAZ49qEF67JNosXW8ZaAGrXMFkvFcGrZbvi_rr5HhVnEr6i6sv1cGx0lk4XfPun1NdIU-mkJjvTPBPADd5acSBz04DkEPZRViI6ZhUq7WCbMHQtwa0WyOryXcQ48TlXBlF6e00riGtHc7oL-6xXLqup5c5HYsdMyoRomxWp-dWQ/s1600/Screenshot%20from%202023-11-20%2001-27-27.png" width="216" /></a></div><br /><h2 style="text-align: left;">rust lang<br /></h2>プログラミング言語rustです。<br /><a href="https://www.rust-lang.org/ja/tools/install">公式のインストール手順</a>に従ってインストールしてください。<br /><br />PCをインターネットに繋げてインストール手順に示されているコマンドを実行して待機すれば済むはずです。<br /><pre>curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh</pre><br />rustをインストール済みならrustupコマンドで更新できます。<pre>rustup upgrade</pre><br />今回は1.74.0を利用しました<br /><pre>rustc --version</pre><pre>rustc 1.74.0 (79e9716c9 2023-11-13)<br /></pre><br /><h2 style="text-align: left;">rustのクロスコンパイラ</h2>今回利用するstm32f429ziはデータシートによると「Arm® 32-bit Cortex®-M4 CPU with FPU」です。<br /><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEigbf2nDwm1gUS94lIOvv0t3gIO2-e71OApMHT7yK3xa5avmHsVLXQZ4xsVXlhn7R8Fa43wXYU1lNEnWiKX2iaK8jgvEcL3URrhZ4GLW1SQqbk7N-9wGeK8W9bKEVj2nEyfMd_mencNY53uwhTJK9Jw_94Dg7n3dzd4oOl2p4z9AIdUSszXe_DWGYGwTKI/s983/Screenshot%20from%202023-11-19%2023-30-59.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="202" data-original-width="983" height="132" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEigbf2nDwm1gUS94lIOvv0t3gIO2-e71OApMHT7yK3xa5avmHsVLXQZ4xsVXlhn7R8Fa43wXYU1lNEnWiKX2iaK8jgvEcL3URrhZ4GLW1SQqbk7N-9wGeK8W9bKEVj2nEyfMd_mencNY53uwhTJK9Jw_94Dg7n3dzd4oOl2p4z9AIdUSszXe_DWGYGwTKI/w640-h132/Screenshot%20from%202023-11-19%2023-30-59.png" width="640" /></a></div><br /><a href="https://developer.arm.com/Processors/Cortex-M4">Cortex-M4</a>はarm v7mなので、FPU(Floating point unit: 浮動小数点ユニット)付きのv7m向けクロスコンパイラthumbv7em-none-eabihfをインストールします。<br /><pre>rustup target add thumbv7em-none-eabihf</pre><br />無いとビルドやデバッグ実行時に下記のようなエラーが出ます。<br /><pre>error[E0463]: can't find crate for `core`<br /> |<br /> = note: the `thumbv7em-none-eabihf` target may not be installed<br /> = help: consider downloading the target with `rustup target add thumbv7em-none-eabihf`<br /></pre><br />エラーが長くて最初のエラーを確認しづらいときは、VSCodeでターミナルを立ち上げて下記のコマンドするとless(文章表示プログラム)で先頭から表示できます。<br /><pre>cargo test --color always 2>&1 | less -r</pre><br /><h2 style="text-align: left;">gdb-multiarch(旧: arm-node-eabi-gdb)</h2>stm32f429ziとデバッガの連携に必要なプログラムです。<br />v10までは「arm-node-eabi-gdb」だったプログラムがv11あたりから複数のICに対応して「gdb-multiarch」に変わったようです。<br /><pre>sudo apt install -y gdb-multiarch<br /></pre><br />これが無いと下記のようなエラーが発生します。<br /><pre>GDB executable "arm-none-eabi-gdb" was not found.<br />Please configure "cortex-debug.armToolchainPath" or "cortex-debug.gdbPath" correctly.</pre><br />参考:<br /><a href="https://askubuntu.com/a/1299843/655102">How can I install "gdb-arm-none-eabi" on Ubuntu 18.04 (Bionic Beaver)?</a><br /><br /><h2 style="text-align: left;">openocd</h2>基板に実装済みのICをデバッグするためのプログラムです。<br />下記のコマンドでインストールできます。<br /><pre>sudo apt install openocd<br /></pre><br />これが無いとデバッガ実行時に下記のようなエラーが出ます。<br /><pre>Launching gdb-server: openocd -c "gdb_port 50000" -c "tcl_port 50001" -c "telnet_port 50002" -s /home/asuki/rustprojects/stm32f429zi-test -f /home/asuki/.vscode/extensions/marus25.cortex-debug-1.12.1/support/openocd-helpers.tcl -f interface/stlink.cfg -f target/stm32f4x.cfg<br /> Please check TERMINAL tab (gdb-server) for output from openocd<br />Finished reading symbols from objdump: Time: 32 ms<br />Finished reading symbols from nm: Time: 27 ms<br />Failed to launch OpenOCD GDB Server: Error: spawn openocd ENOENT</pre><br /><h1 style="text-align: left;">プロジェクトを作成してstm32f429zi向けに設定変更</h1>今回は「rust-stm32f429zi-test」というプロジェクトを作り、それをstm32f429zi向けに変更します。<br /><br />解説するプロジェクトはgithubに上げています。<br /><a href="https://github.com/asukiaaa/rust-stm32f429zi-test">https://github.com/asukiaaa/rust-stm32f429zi-test</a><br /><br />下記コミットの変更内容を解説します。<br /><a href="https://github.com/asukiaaa/rust-stm32f429zi-test/commit/dabf44b0af966e7bc8e5875f7f4edb87226e1fc9"> Succeeded in controlling a led with a button </a><br /><br /><h2 style="text-align: left;">テンプレートからプロジェクトを作成</h2>プロジェクトのディレクトリを置きたいディレクトリで下記のコマンドを実行します。<br /><pre>cargo generate --git https://github.com/rust-embedded/cortex-m-quickstart.git<br /></pre><br />プロジェクト名を入力するとその名前のディレクトリが作成され、その中に関連ファイルが置かれます。<br />今回は「rust-stm32f429zi-test」というプロジェクトを作成しました。<br /><br />プロジェクトができたらVSCodeでそのディレクトリを開き、次の手順からファイルの編集などを行います。<br /><br /><h2 style="text-align: left;">.cargo/config.tomlの変更</h2><h3 style="text-align: left;">プロジェクトのアーキテクチャ変更</h3>stm32f429ziのthumbv7em-none-eabihfに変えます。<br />
<div class="pre-box">
<div class="pre-name">変更前</div>
<pre>[target.thumbv7m-none-eabi]</pre>
</div>
<div class="pre-box">
<div class="pre-name">変更後</div>
<pre>[target.thumbv7em-none-eabihf]</pre>
</div>
<br /><h3 style="text-align: left;">runner有効化</h3>gdb-multiarchを利用するrunner設定のコメントを有効化します。
<div class="pre-box">
<div class="pre-name">変更前</div>
<pre># runner = "gdb-multiarch -q -x openocd.gdb"</pre>
</div>
<div class="pre-box">
<div class="pre-name">変更後</div>
<pre>runner = "gdb-multiarch -q -x openocd.gdb"</pre>
</div>
<br /><h3 style="text-align: left;">古いbuild target無効化</h3>元々書かれている利用しないtargetを無効化します。<div class="pre-box">
<div class="pre-name">変更前</div>
<pre>target = "thumbv7m-none-eabi"</pre>
</div>
<div class="pre-box">
<div class="pre-name">変更後</div>
<pre># target = "thumbv7m-none-eabi"</pre>
</div>
<br /><h3 style="text-align: left;">thumbv7em-none-eabihfのbuild target有効化</h3>stm32f429ziのアーキテクチャthumbv7em-none-eabihfをbuild targetとして指定します。
<div class="pre-box">
<div class="pre-name">変更前</div>
<pre># target = "thumbv7em-none-eabihf"</pre>
</div>
<div class="pre-box">
<div class="pre-name">変更後</div>
<pre>target = "thumbv7em-none-eabihf"</pre>
</div>
<br /><h2 style="text-align: left;">.vscodeに開発対象のマイコンのSVDファイルをダウンロード</h2><a href="https://wiki.st.com/stm32mpu/wiki/CMSIS-SVD_environment_and_scripts">SVDファイルとはSystem View Descriptionの略</a>で、Crotex-Mマイコンが備える機能へのメモリ一覧などが含まれるファイルです。<br />VSCodeのデバッガがそれを参照するので、実行対象のマイコンのSVDファイルをダウンロードして.vscodeディレクトリに配置します。<br /><br />stm32向けのSVDファイルは下記のページにあります。<br /><a href="https://github.com/cmsis-svd/cmsis-svd/blob/main/data/STMicro">https://github.com/cmsis-svd/cmsis-svd/blob/main/data/STMicro</a><br /><br />今回はstm32f429zi向けなので、下記のファイルをダウンロードしました。<br /><a href="https://github.com/cmsis-svd/cmsis-svd/blob/main/data/STMicro/STM32F429.svd">https://github.com/cmsis-svd/cmsis-svd/blob/main/data/STMicro/STM32F429.svd</a><br /><br />githubページの右側のボタンを押すとダウンロードできます。<br /><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh8bXni-7VM5v-MsisjteXr0TufvqY82l7Nf1NpjpuD7HG4gFS94DR0DZe_fSeVfzECusDOW2xFQa6yEAZF-ipN1GuKQ6E1UgUOn-ZwzJGSQiAnRezz8WdgUTgb7IGWvUPGmKfQRXMnuSl9OecsrlQaRECFNZ86v6GMhJcAZVhcDIq1t4GP64EmYWBMMJ8/s710/github_download_button.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="185" data-original-width="710" height="166" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh8bXni-7VM5v-MsisjteXr0TufvqY82l7Nf1NpjpuD7HG4gFS94DR0DZe_fSeVfzECusDOW2xFQa6yEAZF-ipN1GuKQ6E1UgUOn-ZwzJGSQiAnRezz8WdgUTgb7IGWvUPGmKfQRXMnuSl9OecsrlQaRECFNZ86v6GMhJcAZVhcDIq1t4GP64EmYWBMMJ8/w640-h166/github_download_button.png" width="640" /></a></div><br />ダウンロードしたら.vscodeディレクトリ内に置きます。<br /><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgu3Nj-Mmj9izyaJumjNVx3NwwBihY8a_fbkxkP0o010tZwrTTZj3WBW89kPL-sVndGPFWl3XqVOru75JaRrlqoXsw1ihupT15ppKMAyFpGXaltKB3EN3r8ikgs34bVvw-UAnorPeOHfVDuqZ4bAdKlUfVbheCY2iym3_xaOIxqBsWKLyhcEU8k-KDghNc/s222/Screenshot%20from%202023-11-19%2023-18-43.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="176" data-original-width="222" height="176" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgu3Nj-Mmj9izyaJumjNVx3NwwBihY8a_fbkxkP0o010tZwrTTZj3WBW89kPL-sVndGPFWl3XqVOru75JaRrlqoXsw1ihupT15ppKMAyFpGXaltKB3EN3r8ikgs34bVvw-UAnorPeOHfVDuqZ4bAdKlUfVbheCY2iym3_xaOIxqBsWKLyhcEU8k-KDghNc/s1600/Screenshot%20from%202023-11-19%2023-18-43.png" width="222" /></a></div><br /><h2 style="text-align: left;">.vscode/launch.jsonの変更</h2><h3 style="text-align: left;">device config svdFileを利用するマイコン向けに変更</h3>stm32f429zi向けにマイコンの設定を変えます。<br />stlinkのconfigは「stlink-v2-1.cfg」だと廃止予定警告が出たので「stlink.cfg」に変えました。<br />SVDファイルは先程配置したものを使うパスにします。<br />
<div class="pre-box">
<div class="pre-name">変更前</div>
<pre> "device": "STM32F303VCT6",<br /> "configFiles": [<br /> "interface/stlink-v2-1.cfg",<br /> "target/stm32f3x.cfg"<br /> ],<br /> "svdFile": "${workspaceRoot}/.vscode/STM32F303.svd",</pre>
</div>
<div class="pre-box">
<div class="pre-name">変更後</div>
<pre> "device": "STM32F429ZI",<br /> "configFiles": [<br /> "interface/stlink.cfg",<br /> "target/stm32f4x.cfg"<br /> ],<br /> "svdFile": "${workspaceRoot}/.vscode/STM32F429.svd",</pre>
</div>
<br /><h3 style="text-align: left;">周波数を利用するマイコンに合わせて変更</h3>stm32f429ziのデータシートによると工場出荷状態だと16MHzの内蔵発振子を利用して動作するので、設定を16MHzにします。<br /><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjqoTVK5LDcuM6KaGKf0rvu3bMpQ9kxx99gv64dSLqwdSN5Co0BO51eoUfV2t12g2DMzS9F_MoQT8RI9eWIpmRecbh2Jeu-71DTk6DaK6r9rotzeNR2trVLQhYlRmmqSxFfdfRjj1jFYGpvM78e8QJEjMy9kKQfap-xF1uKzRpyYUHr_Ogz5IApE9oXoSo/s463/Screenshot%20from%202023-11-19%2023-33-14.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="195" data-original-width="463" height="270" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjqoTVK5LDcuM6KaGKf0rvu3bMpQ9kxx99gv64dSLqwdSN5Co0BO51eoUfV2t12g2DMzS9F_MoQT8RI9eWIpmRecbh2Jeu-71DTk6DaK6r9rotzeNR2trVLQhYlRmmqSxFfdfRjj1jFYGpvM78e8QJEjMy9kKQfap-xF1uKzRpyYUHr_Ogz5IApE9oXoSo/w640-h270/Screenshot%20from%202023-11-19%2023-33-14.png" width="640" /></a></div><br /><div class="pre-box">
<div class="pre-name">変更前</div>
<pre> "cpuFrequency": 8000000,</pre>
</div>
<div class="pre-box">
<div class="pre-name">変更後</div>
<pre> "cpuFrequency": 16000000,</pre>
</div>
<br /><h2 style="text-align: left;">Cargo.tomlの変更</h2><h3 style="text-align: left;">関連ライブラリを最新版に変更</h3><a href="https://crates.io/search?q=cortex-m">crate.ioで確認</a>しつつ各ライブラリを最新版にします。<br />
<div class="pre-box">
<div class="pre-name">変更前</div>
<pre>[dependencies]<br />cortex-m = "0.6.0"<br />cortex-m-rt = "0.6.10"<br />cortex-m-semihosting = "0.3.3"</pre>
</div>
<div class="pre-box">
<div class="pre-name">変更後</div>
<pre>[dependencies]<br />cortex-m = "0.7.7"<br />cortex-m-rt = "0.7.3"<br />cortex-m-semihosting = "0.5.0"</pre>
</div>
<br /><h3 style="text-align: left;">対象マイコンのHALを設定</h3><a href="https://www.stmcu.jp/technical/hint/no-087/">HALとは「Hardware Abstraction Layer」</a>の略で、ハードウェア抽象化層などと呼ばれる周辺機能を使いやすくするための呼び出し口です。<br /><a href="https://github.com/stm32-rs">srm32-rs</a>で各マイコンのhalが提供されているので、利用するマイコンに合わせて呼び出すHALを変えます。<br />今回はstm32f429zi向けに変更しました。<br />featuresの配列の2番目(0始まりで数えるなら1番目)の<a href="https://docs.rs/svd2rust/latest/svd2rust/#the-rt-feature">「rt」はstm32-rsのinterrupt呼び出しを有効にする機能</a>なので、それを使う場合はマイコン名の後半2文字ではなく「rt」を記述します。<br />バージョンは記事を書いている時点で最新の0.17.1を利用します。<br /><div class="pre-box">
<div class="pre-name">変更前</div>
<pre># [dependencies.stm32f3]<br /># features = ["stm32f303", "rt"]<br /># version = "0.7.1"</pre>
</div>
<div class="pre-box">
<div class="pre-name">変更後</div>
<pre>[dependencies.stm32f4xx-hal]<br />features = ["stm32f429", "rt"]<br />version = "0.17.1"</pre>
</div>
<br /><h2 style="text-align: left;">memory.xの変更</h2>stm32f429ziのデータシートによると、flashメモリの開始位置は0x08000000、flashの大きさは2048KB ((0x08200000-0x08000000)/1024)と分かります。<br />ramの開始位置は0x1000000、大きさは64KBと分かります。<br />しかし、0x20000000から始まる192KBのramも使って良いのか、使うならどう書けば良いかは謎です。<br />指定方法をご存知の方がいらっしゃれば、コメントなどで教えていただけると嬉しいです。<br /><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjUNc5ZHk0WfN45gCsQOHQ-NxPCJeWptaQ4qBipgw-al0VBw_HKVf_qDfdiui6YjR8oLjRGO3svoIhInOxDtrRWL-U9mv4F2vrYyRLgFS0WnS6uMqiJWQWTvyI_FfbSmSfpi5Usr4Wp0Omt4mc_OEX_2-G03hOYfWkRm2KhIF8w1PryuDFFkxeZl2Bs8Uo/s1036/memory_map_of_stm32f429zi.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="770" data-original-width="1036" height="476" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjUNc5ZHk0WfN45gCsQOHQ-NxPCJeWptaQ4qBipgw-al0VBw_HKVf_qDfdiui6YjR8oLjRGO3svoIhInOxDtrRWL-U9mv4F2vrYyRLgFS0WnS6uMqiJWQWTvyI_FfbSmSfpi5Usr4Wp0Omt4mc_OEX_2-G03hOYfWkRm2KhIF8w1PryuDFFkxeZl2Bs8Uo/w640-h476/memory_map_of_stm32f429zi.png" width="640" /></a></div><br /><div class="pre-box">
<div class="pre-name">変更前</div>
<pre> FLASH : ORIGIN = 0x00000000, LENGTH = 256K<br /> RAM : ORIGIN = 0x20000000, LENGTH = 64K</pre>
</div>
<div class="pre-box">
<div class="pre-name">変更後</div>
<pre> FLASH : ORIGIN = 0x08000000, LENGTH = 2048K<br /> RAM : ORIGIN = 0x10000000, LENGTH = 64K</pre>
</div>
<br /><h2 style="text-align: left;">openocd.cfgの変更</h2>stm32f429ziを使うのでstm32f4x向けの設定ファイルに変更します。<br />openocdで設定可能なcfgファイルは<a href="https://sourceforge.net/p/openocd/code/ci/master/tree/tcl/target/">openocdのリポジトリのtcl/target</a>で確認できます。<br />
<div class="pre-box">
<div class="pre-name">変更前</div>
<pre>source [find target/stm32f3x.cfg]</pre>
</div>
<div class="pre-box">
<div class="pre-name">変更後</div>
<pre>source [find target/stm32f4x.cfg]</pre>
</div>
<br /><h2 style="text-align: left;">src/main.rsの変更</h2>nucleo-stm32f429ziはPB7に真ん中の青色LED、PC13にボタンが繋がっているので、それらを利用して、ボタンを押すとLEDの点灯状態が変わるプログラムで動作確認します。<br /><a href="https://qiita.com/Kosuke_Matsui/items/031b2d60f3242617115e#%E5%8B%95%E4%BD%9C%E7%A2%BA%E8%AA%8D">参考にした記事</a>の利用するピンが違う板のプログラムです。<br /><div class="pre-box">
<div class="pre-name">src/main.rs</div>
<pre>#![deny(unsafe_code)]<br />#![no_std]<br />#![no_main]<br /><br />use cortex_m_rt as rt;<br />use hal::prelude::*;<br />use panic_halt as _;<br />use stm32f4xx_hal as hal;<br /><br />#[rt::entry]<br />fn main() -> ! {<br /> if let Some(peripherals) = hal::pac::Peripherals::take() {<br /> let gpiob = peripherals.GPIOB.split();<br /> let mut led = gpiob.pb7.into_push_pull_output();<br /> let gpioc = peripherals.GPIOC.split();<br /> let button = gpioc.pc13;<br /><br /> loop {<br /> if button.is_high() {<br /> led.set_low();<br /> } else {<br /> led.set_high();<br /> }<br /> }<br /> }<br />}<br /></pre>
</div>
<br /><h1 style="text-align: left;">動作確認</h1>nucleo-stm32f429ziにプログラムを書き込んで動作確認します。<br /><br />まず、PCにnucleo-stm32f429ziを接続します。<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh8p9Jtk3Dyn9W8XWvq0jdb8iGmWQdkcm6y0BoV95fm8GwEtNAliO8BOJirGv5wAx9zGYFPnIytz07YnSyoho4KwjY-c7vuUEVZndsHWFGGRnXkfo23s17GRnn8KaNie25rZkhDPHweUqCeQNm_TcQKZxcEosFIRXPZEc1aB8f9KmyU7wctlrjxgXYnm7U/s3296/IMG_20231120_005104.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="2157" data-original-width="3296" height="209" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh8p9Jtk3Dyn9W8XWvq0jdb8iGmWQdkcm6y0BoV95fm8GwEtNAliO8BOJirGv5wAx9zGYFPnIytz07YnSyoho4KwjY-c7vuUEVZndsHWFGGRnXkfo23s17GRnn8KaNie25rZkhDPHweUqCeQNm_TcQKZxcEosFIRXPZEc1aB8f9KmyU7wctlrjxgXYnm7U/s320/IMG_20231120_005104.jpg" width="320" /></a></div><br />プロジェクトのディレクトリをVSCodeで開き、VSCcode左上に表示されているあろうデバッグ機能でOpenOCDを選びます。<br /><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEibQMCMzC9JQFs5arxw-sYqd8Apn4-z0Czxi8BSovOdoZ7fRxRubxkJqo78O_4axjDdMMzxhK6lEtWm5PG9NUuMbGfRTHqmHGE6AnVUrR0aHr1rm9R2iiusoB9VQ3f4UKCynWebtvq20oQDaJqV1zZW7X2J1zbPeApy_37GPCkuFzu_EHJ5zC1CgdFVU68/s224/Screenshot%20from%202023-11-20%2000-57-47.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="201" data-original-width="224" height="201" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEibQMCMzC9JQFs5arxw-sYqd8Apn4-z0Czxi8BSovOdoZ7fRxRubxkJqo78O_4axjDdMMzxhK6lEtWm5PG9NUuMbGfRTHqmHGE6AnVUrR0aHr1rm9R2iiusoB9VQ3f4UKCynWebtvq20oQDaJqV1zZW7X2J1zbPeApy_37GPCkuFzu_EHJ5zC1CgdFVU68/s1600/Screenshot%20from%202023-11-20%2000-57-47.png" width="224" /></a></div><br />デバッグボタンが表示されていない場合は、実行 -> デバッグの開始 を選ぶと実行されて出てくると思います。<br />出てきたら先程説明したとおりOpenOCDを選びます。<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhKTGuhfA0VggCmjG-KCFaXUkeEkGh_H2-bmNfJZl7WrBvf4g0hRbX4IIvp-BH61EHEjy67pn9oDI-jaiYqaT995y0B_KKRJ4ECYKP_1fNw_CA5nEg4izH_bzOnxHmxFlwuxoecRI5iWJGslwAzMe0ODOcgbDnyBHZ0pdxLxz2t0GHDWkTnjq_n3TVIG_k/s268/Screenshot%20from%202023-11-20%2000-59-52.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="135" data-original-width="268" height="135" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhKTGuhfA0VggCmjG-KCFaXUkeEkGh_H2-bmNfJZl7WrBvf4g0hRbX4IIvp-BH61EHEjy67pn9oDI-jaiYqaT995y0B_KKRJ4ECYKP_1fNw_CA5nEg4izH_bzOnxHmxFlwuxoecRI5iWJGslwAzMe0ODOcgbDnyBHZ0pdxLxz2t0GHDWkTnjq_n3TVIG_k/s1600/Screenshot%20from%202023-11-20%2000-59-52.png" width="268" /></a></div><br />デバッグが始まると、USBの横のLEDが緑と赤を交互に切り替える光り方をします。<br />眩しいです。<br /><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjhqyVTad8pR1D0lhYlryWZCwVxEObDbdi9xCktA5VwDo6sqSpt3m3WEJ0AblvmMCXtyY2SbWnLXWFY3DxDHJK6SVt026DJcXESfaDsBzpQoaB6IOAFrDRG4jS49yIvJJEzDzbCfmKtHv1IrlGBcXy9L3OH-vW3jMqXC8rByd09kGaTZ3SDTKZbV9ZzBs0/s1225/IMG_20231120_010107.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1225" data-original-width="1029" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjhqyVTad8pR1D0lhYlryWZCwVxEObDbdi9xCktA5VwDo6sqSpt3m3WEJ0AblvmMCXtyY2SbWnLXWFY3DxDHJK6SVt026DJcXESfaDsBzpQoaB6IOAFrDRG4jS49yIvJJEzDzbCfmKtHv1IrlGBcXy9L3OH-vW3jMqXC8rByd09kGaTZ3SDTKZbV9ZzBs0/s320/IMG_20231120_010107.jpg" width="269" /></a></div><br />処理が進むと「rt::entry」で停止状態になるので、続行ボタンを押してプログラムを動かします。<br /><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgniNG2_71WHs7ZMGXLZF0PEKKUfVvxotNH9hNrBeKf8EwgXgw4Qvm2hJAYUSkIGpcrZeCPCmcS8CiELfrei358WM02me3LK34MHYZ7iAvCcGGbNbjjU2ClTD6eV4qYGTKQ-zaBL62lm5UirnTzfF_zVy5l51YfVooL5f6lZE9QIjYI3o4RpRoz7GznE5w/s482/press_continue_button.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="389" data-original-width="482" height="516" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgniNG2_71WHs7ZMGXLZF0PEKKUfVvxotNH9hNrBeKf8EwgXgw4Qvm2hJAYUSkIGpcrZeCPCmcS8CiELfrei358WM02me3LK34MHYZ7iAvCcGGbNbjjU2ClTD6eV4qYGTKQ-zaBL62lm5UirnTzfF_zVy5l51YfVooL5f6lZE9QIjYI3o4RpRoz7GznE5w/w640-h516/press_continue_button.png" width="640" /></a></div><br />ボタンを押していないと青いLEDが光ります。<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiug33RCjTsJXFa9uby8ZmCpSBAomoUY82CSBU4X1HKzIgtwLzu6Hh4cch2hi0in24-WSB0bH3UMumuiSQlkMBiKcS3yXQJ1R3E757G6BTU3Q_E6cVHKXUpr1tpKlmjJ0MRJjUxGbbIfyTXHqycUpPLbLJm68FuiEvAKM1Y9yzLPPOYME8sUko_jkoplUw/s3427/IMG_20231120_010524.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="2018" data-original-width="3427" height="376" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiug33RCjTsJXFa9uby8ZmCpSBAomoUY82CSBU4X1HKzIgtwLzu6Hh4cch2hi0in24-WSB0bH3UMumuiSQlkMBiKcS3yXQJ1R3E757G6BTU3Q_E6cVHKXUpr1tpKlmjJ0MRJjUxGbbIfyTXHqycUpPLbLJm68FuiEvAKM1Y9yzLPPOYME8sUko_jkoplUw/w640-h376/IMG_20231120_010524.jpg" width="640" /></a></div><br />ボタンを押すと青いLEDが消えます。<br /><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEglvZ6JH2dWG7lrrpuontF-Wi4qP9zCf4aWnypq8eZxRWI45PVYbgrdry531OHPt5ePPpEZYx5hLfwH6U2bX-pxXOgMQeT2dLyPpulos4b18910GPS3TRllX3ynzXIYitHaX5-8iIWOv9rJelEXBLHZVhk9u2dZrRl-OpBkDJ6g7GuNZomt0DEwgkyxr2I/s3362/IMG_20231120_010539~2.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="2027" data-original-width="3362" height="386" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEglvZ6JH2dWG7lrrpuontF-Wi4qP9zCf4aWnypq8eZxRWI45PVYbgrdry531OHPt5ePPpEZYx5hLfwH6U2bX-pxXOgMQeT2dLyPpulos4b18910GPS3TRllX3ynzXIYitHaX5-8iIWOv9rJelEXBLHZVhk9u2dZrRl-OpBkDJ6g7GuNZomt0DEwgkyxr2I/w640-h386/IMG_20231120_010539~2.jpg" width="640" /></a></div><br />期待通りに動きました。<br /><br />停止ボタンを押してデバッグを止めるとマイコンも動作を停止しますが、リセットボタンを押したりUSBを抜き差ししたりするとデバッガと連携せず単体で動きます。<br /><br /><h1 style="text-align: left;">おわり</h1>以前から気になっていたstm32のrustでの環境を構築してプログラムを書き込んで動かせました。<br />思っていたより設定項目が多かったですが、期待通りに動かせて良かったです。<br /><br /><h1 style="text-align: left;">参考</h1>全体の流れを参考にした記事です。<br /><a href="https://qiita.com/Kosuke_Matsui/items/031b2d60f3242617115e">STM32 NUCLEOボードによる組み込みRust開発環境構築</a><br /><a href="https://zeptoelecdesign.com/rust-embedded2/">組み込みRust開発環境構築【STM32 NucleoとVSCodeで構築】 Hello_Rust_World</a><br /><br />今回の記事で作成したプロジェクトです。<br /><a href="https://github.com/asukiaaa/rust-stm32f429zi-test">https://github.com/asukiaaa/rust-stm32f429zi-test</a><br /><br /><br />Asuki Konohttp://www.blogger.com/profile/07813182469285556500noreply@blogger.com0tag:blogger.com,1999:blog-9198372554518889060.post-60887634418574805362023-11-14T00:04:00.002+09:002023-11-14T00:04:12.905+09:00cppのクラスメンバ関数のconst備忘録<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiWW5iZ4hEGRFFDWrzMCm3KDxMbU6irxKezjDWlOh7T54-_MYrdYjdD9k8mM5eE8FHk20NehHIQlWE5Icf99CX_T65DDSD4Kg8UoG8rrxAzVaYZWhJL_ZpIuSe91sXe9Q8EqB5qElWnevUksAFEWsB_hdRhWXLD4Nf__tjb7nCv91bSJaB-fyrORZOyxhc/s382/Screenshot%20from%202023-11-14%2000-01-18.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="114" data-original-width="382" height="190" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiWW5iZ4hEGRFFDWrzMCm3KDxMbU6irxKezjDWlOh7T54-_MYrdYjdD9k8mM5eE8FHk20NehHIQlWE5Icf99CX_T65DDSD4Kg8UoG8rrxAzVaYZWhJL_ZpIuSe91sXe9Q8EqB5qElWnevUksAFEWsB_hdRhWXLD4Nf__tjb7nCv91bSJaB-fyrORZOyxhc/w640-h190/Screenshot%20from%202023-11-14%2000-01-18.png" width="640" /></a></div><br /><h1 style="text-align: left;">背景</h1>cppのプログラムでconstを付けてエラーが出る度にどうだったか迷うので、自分の言葉でまとめます。<br /><br /><h1 style="text-align: left;">クラスメンバ関数のconst</h1>下記のプログラムを書いた時<br />
<pre>class Item {<br /> public:<br /> float getValue() const { return value; }<br /> void setValue(float v) { this->v = v; }<br /><br /> private:<br /> float value = 5;<br />};<br /><br />class A {<br /> public:<br /> const Item* const getItemP(size_t index) const { return &items[index]; }<br /><br /> private:<br /> static const size_t lenItems = 10;<br /> Item items[lenItems];<br />};<br /></pre>
<br />下記でどれが欲しい機能のconstだったか戸惑います<br /><pre>class A {<br /> const Item* const getItemP(size_t index) const { return &items[index]; }<br />};<br /></pre><br /><h1 style="text-align: left;">戻り値の前のconst: 変更を許可しない戻り値(この場合ポインタ)を返す</h1>こう書いていると<br /><pre>class A {<br /> const Item* getItemP(size_t index) { return &items[index]; }<br /> ^^^^^<br />};<br /></pre>getItemPで受け取るポインタが変更を許可しないconst扱いになります。<br /><pre>A a;<br />auto itemP = a.getItemP(0);<br />itemP->setValue(5); // Error</pre><br /><h1 style="text-align: left;">戻り値と関数名の間のconst: 処理内容が変わらない関数?現時点で意味不明</h1>役割不明です。<br />ご存知の方はコメントなどで教えていただけると嬉しいです。<br /><pre>class A {<br /> Item* const getItemP(size_t index) { return &items[index]; }<br /> ^^^^^ 何が嬉しいかが分からない<br />};<br /></pre><br /><h1 style="text-align: left;">引数の丸括弧終わりと関数の処理の間のconst: 関数の処理でメンバ変数の変更を許可しない</h1>こう書いていると<br /><pre>class A {<br /> Item* getItemP(size_t index) const { return &items[index]; }<br /> ^^^^^<br />};</pre>this(インスタンス)がconst扱いになり関数の中でメンバ変数の変更を許可しません。<br />変更する記述があるとエラーになります。(ただし、mutable付きで宣言しているメンバ変数だと変更できてしまうようです。参考: <a href="https://qiita.com/hhgghhh/items/e44c384561ca159d6411#%E6%B3%A8%E6%84%8F%E7%82%B92-const-%E3%83%A1%E3%83%B3%E3%83%90%E5%A4%89%E6%95%B0%E5%86%85%E3%81%A7%E3%81%82%E3%81%A3%E3%81%A6%E3%82%82%E3%83%A1%E3%82%BD%E3%83%83%E3%83%89%E5%A4%89%E6%95%B0%E3%81%8C%E6%9B%B8%E3%81%8D%E6%8F%9B%E3%81%88%E3%82%89%E3%82%8C%E3%81%A6%E3%81%97%E3%81%BE%E3%81%86%E5%A0%B4%E5%90%88%E3%81%8C%E3%81%82%E3%82%8B">const メンバ変数内であっても変数が書き換えられてしまう場合がある</a>)<br /><br />この記述の嬉しい(というかこれが無いとエラーが出て使えない)場面は、クラスのインスタンスをconst型として扱う場合に、値を参照するだけのconstのインスタンスから関数として呼べることです。<pre>void someFunction (const A& a) {<br /> auto itemP = a.getItemP(5); // 処理の前のconstが無いとエラーになる<br />}</pre><br /><h1 style="text-align: left;">おわり</h1>クラスメンバ変数に3箇所も書けるconstの役割の理解が深まりました。<br />真ん中のconstだけ嬉しい場面が分からないので、どなたか教えていただけると嬉しいです。<br /><br /><h1 style="text-align: left;">参考</h1><a href="https://qiita.com/hhgghhh/items/e44c384561ca159d6411"> c++ constメンバ関数まとめ</a><br /><a href="https://cpprefjp.github.io/lang/cpp11/ref_qualifier_for_this.html">メンバ関数の左辺値/右辺値修飾</a><br /><br />Asuki Konohttp://www.blogger.com/profile/07813182469285556500noreply@blogger.com0tag:blogger.com,1999:blog-9198372554518889060.post-57927476437376082442023-11-06T00:34:00.001+09:002023-11-06T00:34:56.175+09:00gitのsubmoduleを配置できないときの対応<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhLr30V_g5AoSLhOthB8GzZweMKvpokWEK0A6yYa63xKs0GpG3rE2y_bup1aQilkNREFX1_l23oPgLYgYF2o2jTjUW9hyphenhyphenUXKUq2c57_Sz8XuYB3xycm0OIPTDjwwhoiGV881R4w5H__Ve7_U2X7GYtjONH1HC8a0ygGDmPc-ajKGfQ1kjcvAydeHZ96BsU/s368/Screenshot%20from%202023-11-06%2000-13-17.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="138" data-original-width="368" height="120" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhLr30V_g5AoSLhOthB8GzZweMKvpokWEK0A6yYa63xKs0GpG3rE2y_bup1aQilkNREFX1_l23oPgLYgYF2o2jTjUW9hyphenhyphenUXKUq2c57_Sz8XuYB3xycm0OIPTDjwwhoiGV881R4w5H__Ve7_U2X7GYtjONH1HC8a0ygGDmPc-ajKGfQ1kjcvAydeHZ96BsU/s320/Screenshot%20from%202023-11-06%2000-13-17.png" width="320" /></a></div><br /><h1 style="text-align: left;">背景</h1>バージョン管理プログラムのgitには、管理中のリポジトリにgitで管理する他のリポジトリを配置するsubmoduleという機能があります。<br />そのsubmoduleを利用してリポジトリを管理していたところ、ディレクトリ構成に齟齬が発生してsubmoduleのディレクトリをダウンロードできなくなり手間取りました。<br />調べつつ試行錯誤した末に期待通りに動く状態にできたので、遭遇した不具合と対応方法を記事に残します。<br /><br /><h1 style="text-align: left;">使ったもの</h1>git<br />ubuntu22.04で動くversion 2.34.1を利用しました。<br /><br /><h1 style="text-align: left;">設定やファイルを消す前に試すべきsubmoduleのコマンド</h1><h2 style="text-align: left;">submodule updateによる設定済みsubmoduleの初期設定</h2>リポジトリのディレクトリ内で下記のコマンドを実行すると、設定済みのsubmoduleのファイルのダウンロード(clone)と配置が行われます。<br /><pre>git submodule update --init --recursive</pre><br />構成が壊れていなければ上記のコマンドでsubmoduleに関するファイルが配置されます。<br /><br /><h2 style="text-align: left;">submodule addのforce実行</h2>submodule addコマンドを実行すると下記のようなエラーが出る場合があります。<br /><pre>git submodule add https://repository-url-for/project-a.git</pre><pre>fatal: A git directory for 'project-a' is found locally with remote(s):<br /> origin https://repository-url-for/project-a.git<br />If you want to reuse this local git directory instead of cloning again from<br /> https://repository-url-for/project-a.git<br />use the '--force' option. If the local git directory is not the correct repo<br />or you are unsure what this means choose another name with the '--name' option.<br /></pre><br />これは.git/modulesにclone済みのsubmodule向けリポジトリが存在している場合に発生します。<br />上記エラーの中でも説明されている通り--forceを付けて実行すると期待通りにaddできることがあります。<br /><pre>git submodule add --force https://repository-url-for/project-a.git</pre><br />注意点として<b>--forceはaddとgitのurlの間への配置が必要</b>です。<br />コマンドの末尾に--forceを付けると「--force」というディレクトリ名でsubmoduleが配置されてややこしくなります。<br /><br />間違って--forceディレクトリを作ってしまった場合は削除対象を「./--force」とすると--forceをコマンドではなくパスと認識させて消せます。<pre>rm ./--force -r</pre>合わせて.gitmodulesの--forceディレクトリの設定も削除してください。<br /><br /><h1 style="text-align: left;">submoduleのディレクトリと.gitmodulesと.git/modulesの削除の後に再配置</h1>今回はproject-aをsubmoduleとして配置したはずなのに動かない場合を例として対応します。<br /><br />期待するファイル構成<br /><pre>リポジトリのディレクトリ<br /> |- .git # gitの管理ディレクトリ 通常は触りません<br /> |- .gitmodules # submoduleの配置を記述するファイル<br /> |- project-a # 配置したリポジトリ<br /> |- project-aの中身のファイル<br /></pre><br />
<div class="pre-box">
<div class="pre-name">.gitmodules</div>
<pre>[submodule "project-a"]<br /> path = project-a<br /> url = https://repository-url-for/project-a.git<br /></pre>
</div>
<br />submoduleとして配置したはずのproject-aディレクトリにファイルが配置(ダウンロードやclone)されなくて困っている場合が、今回紹介する手順の対象です。<br /><br /><h2 style="text-align: left;">submoduleのディレクトリ削除</h2>project-aをsubmoduleとして配置しているディレクトリを消します。<br />何も配置されずに困っている場合は空だと思いますが、後でsubmoduleを再配置する時に同じ名前のディレクトリがあると厄介なので消しておきます。<br /><br /><pre>rm -r project-a</pre><br /><h2 style="text-align: left;">.gitmodulesの該当する設定を削除</h2>project-aに関する設定を.gitmoduleから消します。<br /><br />下記の設定を削除します。<br />.gitmodulesにsubmoduleの設定が複数ある場合は、対象の設定だけを削除します。<br />.gitmodulesにsubmoduleの設定が1つしかないのなら、.gibmodulesファイル自体の削除でも良いです。<br /><div class="pre-box">
<div class="pre-name">.gitmodules</div>
<pre>[submodule "project-a"]<br /> path = project-a<br /> url = https://repository-url-for/project-a.git<br /></pre>
</div>
<br /><h2 style="text-align: left;">.git/modulesの該当ディレクトリ削除</h2>この手順がこの記事の肝です。<br /><br />.git/modulesにclone済みのsubmoduleのリポジトリが配置されるので、問題が発生しているsubmoduleのディレクトリがあるなら削除します。<br />削除には管理者権限が必要です。<br /><pre>sudo rm -r .git/modules/project-a</pre><br />.gitディレクトリ内の他のファイルを消すとgitのバージョン管理が壊れる可能性があるので、対象となるパスに注意して削除してください。<br /><br /><h2 style="text-align: left;">削除したらcommitして再配置</h2>.gitmodulesに削除の変更があるとsubmoduleの追加を行えないので、変更したファイルとディレクトリをcommitします。<br /><pre>git add .gitmodules project-a<br />git commit -m 'Remove submodule setting for project-a'<br /></pre><br />上記のcommitで.gitmodulesに削除の変更がなくなり、submoduleの追加が可能になるので配置したいsubmoduleを再度配置します。<br /><pre>git submodule add https://repository-url-for/project-a.git</pre><br />配置できたら、対象の.gitmodulesの設定とディレクトリをコミットします。<br /><pre>git add .gitmodules project-a<br />git commit -m 'Add project-a as a submodule'<br /></pre><br />自分の遭遇した不具合では上記の操作でsubmoduleのファイル(project-a)を配置できました。<br /><br /><h1 style="text-align: left;">おわり</h1>submoduleの扱いに四苦八苦しましたが、関連する設定とディレクトリの削除後にコミットした後submodule addし直したら正常に戻りました。<br />なお、この記事を書いて理解が進んだことで、addの「--force」の位置がgitのurlの前だと把握したので、自分が遭遇した不具合は正しい場所に--forceを書けば直ったのかもしれません。<br /><br />ともあれ、submoduleを期待通りに配置できて良かったです。<br /><br /><h1 style="text-align: left;">参考</h1><a href="https://stackoverflow.com/a/1260982/3774895">How do I remove a submodule?</a><br /><br />Asuki Konohttp://www.blogger.com/profile/07813182469285556500noreply@blogger.com0tag:blogger.com,1999:blog-9198372554518889060.post-23773625773374379142023-10-29T21:56:00.000+09:002023-10-29T21:57:00.012+09:00ros2のパッケージ情報はROS Indexから辿るのが良い<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhJsnsse7-ZQYLA7w52WPAZJYI5yzo4CiT6zajefzM9za0_oC-J1kMBOs9-xS4E_EoI39BTXoTEsoVrhnIB2QBVXiRSwZrJc8AVLQ9FUUlZ3CEefPMht4kXJw7EoDO_gj3Id5jCfZ7aFzYS51V6_3-8Y2oPBP6VJMuOF-0tiNrzR8Egg2LTZNyWRWzOsZE/s175/Screenshot%20from%202023-10-29%2021-44-30.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="94" data-original-width="175" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhJsnsse7-ZQYLA7w52WPAZJYI5yzo4CiT6zajefzM9za0_oC-J1kMBOs9-xS4E_EoI39BTXoTEsoVrhnIB2QBVXiRSwZrJc8AVLQ9FUUlZ3CEefPMht4kXJw7EoDO_gj3Id5jCfZ7aFzYS51V6_3-8Y2oPBP6VJMuOF-0tiNrzR8Egg2LTZNyWRWzOsZE/s16000/Screenshot%20from%202023-10-29%2021-44-30.png" /></a></div><br /><h1 style="text-align: left;">背景</h1>ros2のteleop_twist_keyboardに変更を加えるためソースコードをダウンロードして試行錯誤していたところ、google検索に出てくるros1の顔ぶれがcontributorに多いリポジトリではなく、ROS Indexで辿って判明した別のリポジトリがrollingのパッケージとして配布されていると分かりました。<br /><br />ROS Indexのページはこちらです。<br /><a href="https://index.ros.org/">https://index.ros.org/</a><br /><br />備忘録として検索と参照方法を記事にします。<br /><br /><h1 style="text-align: left;">使ったもの</h1>使ったPC: ros-rollingをインストールしたubuntu22.04<br />辿る対象: teleop-twist-keyboard<br /><br /><h1 style="text-align: left;">ros2 pkg xmlコマンドでパッケージ情報を確認可能</h1>下記コマンドでパッケージのxmlを表示できます。<br /><pre>ros2 pkg xml パッケージ名</pre><br />記事を書いている時点でのrollingのteleop-twist-keyboardはこのように表示されました。<br /><pre>ros2 pkg xml teleop_twist_keyboard</pre><pre><package format="2"><br /> <name>teleop_twist_keyboard</name><br /> <version>2.3.2</version><br /> <description><br /> A robot-agnostic teleoperation node to convert keyboard commands to Twist<br /> messages.<br /> </description><br /><br /> <maintainer email="clalancette@openrobotics.org">Chris Lalancette</maintainer><br /><br /> <license>BSD License 2.0</license><br /><br /> <url type="website">http://wiki.ros.org/teleop_twist_keyboard</url><br /><br /> <author email="namniart@gmail.com">Austin Hendrix</author><br /> <author>Graylin Trevor Jay</author><br /><br /> <exec_depend>geometry_msgs</exec_depend><br /> <exec_depend>rclpy</exec_depend><br /><br /> <test_depend>ament_copyright</test_depend><br /> <test_depend>ament_flake8</test_depend><br /> <test_depend>ament_pep257</test_depend><br /><br /> <export><br /> <build_type>ament_python</build_type><br /> </export><br /></package><br /></pre><br />Graylin Trevor Jayさんが管理するバージョン2.3.2のパッケージと分かります。<br />(xml上のurlがros1のteleop-twist-keyboardのwikiになっているので<a href="https://github.com/ros2/teleop_twist_keyboard/pull/28">削除の要望(pull request)</a>を送りました。)<br /><br /><h1 style="text-align: left;">ROS Indexでパッケージを検索してリポジトリを確認</h1>ROS Indexとはros1とros2のパッケージ情報を検索できるページです。<br /><br /><a href="https://index.ros.org/">https://index.ros.org/</a><br /><br />google検索で出てくるリポジトリは、ros1のだったり、ros2向けなものの管理されてなかったりするので、該当するパッケージのリポジトリはROS Indexから辿るのが確実です。<br /><br />「teleop_twist_keyboard」と検索してrollingのパッケージを探します。<br />スペース区切り「teleop twist keyboard」やケバブケース「teleop-twist-keyboard」の検索では似た名前の別のパッケージも出てくるので、スネークケース「teleop_twist_keyboard」で検索するのが今回は都合が良かったです。<br /><br /><a href="https://index.ros.org/search/?term=teleop_twist_keyboard">Serach: teleop_twist_keyboard</a><br /><br />rolling版のteleop_twist_keyboardがあるので、それのNameのリンクを押して詳細を確認します。<br />(なお、不具合なのか、Repoのリンクでもリポジトリに飛ばずROS Indexの詳細ページに移ります。)<br /><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjdE6CXnqc17eM2F17m0u9UFwavs129N9v1AM0FqqYsLT774hyphenhyphen0-sBGISaME5FYovmkkp2Mp3LDf-vEkgUQAvUns_OKL1b630NT3kt0S5RuYi20CGSoecNQ3GY2tlxfknd2wg3qWJfK9eHgMcsDTTlB7RoOMrCDJJGPTSImS837_u6YhZCNiB-Ikt8qFxg/s805/rolling_teleop_twist_keyboard.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="319" data-original-width="805" height="254" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjdE6CXnqc17eM2F17m0u9UFwavs129N9v1AM0FqqYsLT774hyphenhyphen0-sBGISaME5FYovmkkp2Mp3LDf-vEkgUQAvUns_OKL1b630NT3kt0S5RuYi20CGSoecNQ3GY2tlxfknd2wg3qWJfK9eHgMcsDTTlB7RoOMrCDJJGPTSImS837_u6YhZCNiB-Ikt8qFxg/w640-h254/rolling_teleop_twist_keyboard.png" width="640" /></a></div><br />詳細ページの Repository Summary の Checkout URI がリポジトリのリンクです。<br /><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgWJ9uzZ7iu2rIeHa4DNK0pX4iWrMkjXF4PYjCRrm9HsVGilcchk5O2LulXW8e9UWWthK10wq5e80EmXfiUNgdf1KsUBacYYsbg_w4sgm1D9d-OauVqqd5mqIJBgjvyr2mNOdXunNGoqojUz39EaLFQQpetUQTDifQ0AThsZ5Vo2UI1XDkGqc_bogsH3qE/s695/checkout_uri_of_teleop_twist_keyboard.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="695" data-original-width="609" height="640" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgWJ9uzZ7iu2rIeHa4DNK0pX4iWrMkjXF4PYjCRrm9HsVGilcchk5O2LulXW8e9UWWthK10wq5e80EmXfiUNgdf1KsUBacYYsbg_w4sgm1D9d-OauVqqd5mqIJBgjvyr2mNOdXunNGoqojUz39EaLFQQpetUQTDifQ0AThsZ5Vo2UI1XDkGqc_bogsH3qE/w560-h640/checkout_uri_of_teleop_twist_keyboard.png" width="560" /></a></div><br />リポジトリのurlが分かりました。<br /><br /><a href="https://github.com/ros2/teleop_twist_keyboard">https://github.com/ros2/teleop_twist_keyboard</a><br /><br /><a href="https://github.com/ros2/teleop_twist_keyboard/blob/dashing/package.xml">リポジトリ内のpackage.xml</a>はros2 pkg xmlで表示した内容と同じなので、間違い無さそうです。<br /><br /><h1 style="text-align: left;">google検索で先頭に出てくるリポジトリは配布版のリポジトリではないことがある</h1>「ros2 teleop twist keyboard github」で検索すると下記のリポジトリが先頭に表示されます。<br /><br /><a href="https://github.com/rohbotics/ros2_teleop_keyboard">https://github.com/rohbotics/ros2_teleop_keyboard</a><br /><br />ros1のrosserialを管理していた<a href="https://github.com/mikepurvis">Mike Purvis</a>さんがcontributorに入っているのでこれが本家かと思いきや、2016年(8年前)が最後の更新で、バージョンが0.0.0とコマンドで確認した番号と合わない、rollingのteleop-twist-keyboardとは異なるリポジトリです。<br /><br />teleop_twist_keyboardの<a href="https://github.com/ros2/teleop_twist_keyboard">rollingで使われるリポジトリ</a>はフォーク元が<a href="https://github.com/ros-teleop/teleop_twist_keyboard">ros1のリポジトリ</a>ですが、<a href="https://github.com/rohbotics/ros2_teleop_keyboard">実装内容はgoogle 検索で先頭に表示されたリポジトリ</a>が主なのでどうしてこうなったのか疑問です。<br /><br />このため、google検索で出てくるものよりROS Indexで検索して辿ったリポジトリを見るのが良いです。<br /><br /><h1 style="text-align: left;">おわり</h1>ros2 pkg xmlコマンドでパッケージのバージョンを確認し、それと合致するバージョンのリポジトリを<a href="https://index.ros.org/">ROS Index</a>を通して把握できました。<br />google検索で先頭に出てきたリポジトリを確認せずに使うと、<a href="https://github.com/rohbotics/ros2_teleop_keyboard/pull/1">コードが古くて実行環境を整えるのに時間がかかったり</a>、使っているパッケージとは異なるものだったりするので、ROS Indexを通して探すのが良いです。<br /><br /><h1 style="text-align: left;">参考</h1>ROS Indexです。ここでパッケージを検索できます。<br /><a href="https://index.ros.org/">https://index.ros.org/</a><br /><br />ros2 rollingで使われているteleop-twist-keyboardのコードを管理するリポジトリです。<br /><a href="https://github.com/ros2/teleop_twist_keyboard">https://github.com/ros2/teleop_twist_keyboard</a><br /><br />google検索で「ros2 teleop twist keyboard github」で検索すると、記事を書いている時点で先頭に出てくるリポジトリです。(しかし、rollingで使われているものではない)<br /><a href="https://github.com/rohbotics/ros2_teleop_keyboard">https://github.com/rohbotics/ros2_teleop_keyboard</a><br /><br />Asuki Konohttp://www.blogger.com/profile/07813182469285556500noreply@blogger.com0tag:blogger.com,1999:blog-9198372554518889060.post-80325752636460739482023-10-23T00:11:00.002+09:002023-10-23T00:11:21.856+09:00ros2で発生する「_rclpy_pybind11.cpython-310-x86_64-linux-gnu.so」のインポートエラーは全てのパッケージを再インストールすると直ることがある<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhKt-J8bpsbkIyob_Cu9vX6Zom3cqLfPddiul7lFZgByFLbWGmvk_j2Ub2ISgvhjpdOTz6UAzc1ONRBq8DS0dDNDXyC3Irm6MxHsRwMCRtJdIKbxhUxwpcCynklzPjS37X9cuK2ppUFZxfPkPWX9eNi9yjLgNmIBGZFEAy8rG3_g2xs1Q8xUTDV80AEAIg/s285/Screenshot%20from%202023-10-23%2000-09-15.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="67" data-original-width="285" height="67" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhKt-J8bpsbkIyob_Cu9vX6Zom3cqLfPddiul7lFZgByFLbWGmvk_j2Ub2ISgvhjpdOTz6UAzc1ONRBq8DS0dDNDXyC3Irm6MxHsRwMCRtJdIKbxhUxwpcCynklzPjS37X9cuK2ppUFZxfPkPWX9eNi9yjLgNmIBGZFEAy8rG3_g2xs1Q8xUTDV80AEAIg/s1600/Screenshot%20from%202023-10-23%2000-09-15.png" width="285" /></a></div><br />ros2のパッケージをapt操作で部分的に削除したりインストールしたりしたところ下記のエラーが発生するようになりました。<br />
<pre>ImportError: /opt/ros/rolling/lib/python3.10/site-packages/rclpy/_rclpy_pybind11.cpython-310-x86_64-linux-gnu.so: undefined symbol: rcl_count_services<br />The C extension '/opt/ros/rolling/lib/python3.10/site-packages/rclpy/_rclpy_pybind11.cpython-310-x86_64-linux-gnu.so' failed to be imported while being present on the system. Please refer to 'https://docs.ros.org/en/rolling/How-To-Guides/Installation-Troubleshooting.html#import-failing-even-with-library-present-on-the-system' for possible solutions</pre>
<br />試行錯誤したところ、エラーが発生しているrosのdistributionの全てのパッケージをアンインストールしてインストールしなおしたらエラーが出なくなりました。<br /><pre>sudo apt remove ros-rolling-*<br />sudo apt install ros-rolling-desktop-full</pre><br />関連するgithubのissueにも自分が行った操作を共有しました。<br /><a href="https://github.com/ros2/rclpy/issues/1144#issuecomment-1774027074"> _rclpy_pybind11.cpython-310-x86_64-linux-gnu.so failed to be imported while being present on the system #1144 </a><br /><br />rosのパッケージの更新で齟齬が発生したのか、自分のapt操作が悪かったのか、エラーが発生する状況を再現できないので詳細は不明ですが、とりあえず全部インストールし直しで動くようになって良かったです。<br /><br />Asuki Konohttp://www.blogger.com/profile/07813182469285556500noreply@blogger.com0tag:blogger.com,1999:blog-9198372554518889060.post-46292758577459085772023-10-16T01:15:00.002+09:002023-10-16T11:58:41.369+09:00ubuntuのアプリ検索結果の順序を変える<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgMMzfgioOztMeufBvGBoLCQxb438SgkWtMsL3dw42GCqX4CmI3hrpOCTZhASFoHCXApTtkE9_pTAiNpYPo9ntQIAFf6Ica4_Evn2AwZvbdjzRqFFdL2_kC3vfZ7g3YqcUbwQyuF1VgMpvQVXV15T7fxfoU4QfMdPeY7XrdNK2i1WpE4jnE54j_PjF3XbI/s480/change_order_of_calc_on_ubuntu_app_search_result.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="480" data-original-width="474" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgMMzfgioOztMeufBvGBoLCQxb438SgkWtMsL3dw42GCqX4CmI3hrpOCTZhASFoHCXApTtkE9_pTAiNpYPo9ntQIAFf6Ica4_Evn2AwZvbdjzRqFFdL2_kC3vfZ7g3YqcUbwQyuF1VgMpvQVXV15T7fxfoU4QfMdPeY7XrdNK2i1WpE4jnE54j_PjF3XbI/s320/change_order_of_calc_on_ubuntu_app_search_result.png" width="316" /></a></div><br /><h1 style="text-align: left;">背景</h1>電卓(計算機)アプリを使う時にアプリ検索で「calc」と検索するとlibreoffice-calcが電卓の前に表示されて誤って起動させることが多かったので、電卓が先に表示される設定を調べて適用しました。<br />施した設定と分かったことを共有します。<br /><br /><h1 style="text-align: left;">試した環境</h1>ubuntu22.04<br /><br /><h1 style="text-align: left;">設定: 計算機の名前を「Calculator」から「calculator」変えて英語表示にする</h1>計算機のアイコン表示設定ファイルのNameを下記のように変えます。<br />
<div class="pre-box">
<div class="pre-name">/usr/share/applications/org.gnome.Calculator.desktop</div>
<pre># Name=Calculator<br />Name=calculator<br /></pre>
</div><br />これにより、表示名が多分辞書の単語から外れるため「電卓」から「calculator」に変わり、「calc」で検索した時に表示名と一致するようになり、利用頻度が高ければlibreoffice-calcより先(左)に表示されます。<br /><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh_PV9inoTs7u_i5YjlrA0khhJgkdjb_HTf-83DwlzciwbD3efvFRXVw7Bs0IukpU7KGs6VHmp-xN7iO6TzEBXwlAfinam_eSHYHLQrhfbU1dsORp8YTPbn5C8eRxBfxmMrunR4YeNKqG1QFk-RAnM9eUasIkrVIDRWq5PZ28R_T7FWNziHuvVZ-lVHFzc/s361/Screenshot%20from%202023-10-16%2000-01-12.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="229" data-original-width="361" height="203" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh_PV9inoTs7u_i5YjlrA0khhJgkdjb_HTf-83DwlzciwbD3efvFRXVw7Bs0IukpU7KGs6VHmp-xN7iO6TzEBXwlAfinam_eSHYHLQrhfbU1dsORp8YTPbn5C8eRxBfxmMrunR4YeNKqG1QFk-RAnM9eUasIkrVIDRWq5PZ28R_T7FWNziHuvVZ-lVHFzc/s320/Screenshot%20from%202023-10-16%2000-01-12.png" width="320" /></a></div><br /><h1 style="text-align: left;">それでも変わらない場合: アプリ利用状況得点を増やす</h1>自分の環境ではlibfeorriceよりcalculator(電卓)の方が利用頻度が高いので、表示名を英語にしたら先に表示されるようになりました。<br />しかしながら、libreoffice-calcの方が利用頻度が高いと「calc」の検索で電卓よりlibreoffice-calcの方が先に表示されます。<br /><br />その場合はアプリの利用状況を管理している「~/.local/share/gnome-shell/application_state」の電卓の得点(score)をlibreoffice-calcより増やします。<br /><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjlJS_KYHgbiWO9kBxwfnHImfvKfIvpaxneW5xQ2oSGfHpdPue7B5dBsVyQBFEYT_kXY8GsV32jHuhJVlMcIHa314nYtSGyYMJrSpzOeMzRQgdD5jRsaXXd5Aa6LMSSkpUexWk_bS-INUjL68hC5UBBzOcmVpzsvkBWiK4vf0vbGuOgEeNW5A7kjxbP2WA/s896/bigger_score_for_gnome_calculator.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="239" data-original-width="896" height="170" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjlJS_KYHgbiWO9kBxwfnHImfvKfIvpaxneW5xQ2oSGfHpdPue7B5dBsVyQBFEYT_kXY8GsV32jHuhJVlMcIHa314nYtSGyYMJrSpzOeMzRQgdD5jRsaXXd5Aa6LMSSkpUexWk_bS-INUjL68hC5UBBzOcmVpzsvkBWiK4vf0vbGuOgEeNW5A7kjxbP2WA/w640-h170/bigger_score_for_gnome_calculator.png" width="640" /></a></div><br />この「application_state」はログイン直後に読み込まれ、ログイン後は読み込まれず更新されるファイルなので、<b>値を書き換えたらログインしなおして</b>読み直させます。<br /><br /><h1 style="text-align: left;">点数付不要な場合は無効化可能</h1>下記のコマンドを実行してログインしなおすと、利用状況の更新を止めれます。<br /><pre>gsettings set org.gnome.desktop.privacy remember-app-usage false<br /></pre><br />application_stateを消してログインし直すと初期の順序になります。<br /><pre>cd ~/.local/share/gnome-shell<br />cp application_state backup_application_state # 戻せなくて困らないようにバックアップ<br />rm application_state <br /></pre><br />点数の更新が止まって「application_state」が無い状態だと、アプリは初期の順序で表示され、何かを起動するとそれが先頭に表示されますが、ログインし直すと初期の順序に戻ります。<br /><br /><h1 style="text-align: left;">おわり</h1>アプリの検索結果の順序を制御できたので、電卓が使いたいのに間違ってlibreoffice-calcを起動する機会を減らせて嬉しいです。<br /><br /><h1 style="text-align: left;">参考</h1><a href="https://unix.stackexchange.com/questions/192095/modify-gnome-3-search-bar-results">Modify Gnome 3 search bar results</a><br /><a href="https://www.reddit.com/r/gnome/comments/4eh3on/activities_search_how_do_i_change_the_order/">Activities Search - how do I change the order?</a><br /><br />Asuki Konohttp://www.blogger.com/profile/07813182469285556500noreply@blogger.com0tag:blogger.com,1999:blog-9198372554518889060.post-52978953219730799382023-10-09T00:44:00.000+09:002023-10-09T00:44:42.405+09:00stm32arduinoで多機能なピンの特定の機能を呼ぶときはaltが付いたピンのマクロの利用が必要<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj2c-GJZFlw8tpT0bum0u0sinIJCcOqSbjPNgh5CuLmy2NUgbpQzDNtJ2QSUFz-avhOfsxPBAn1tPFw4YbVDXbkOWPE_Cf3malf6hvCymQoBV8XIYpmGIXy49ywxNEGM2XArI8zzvQyDRWL948V1REPmu2RmX82nSsdUyXJubIF5cgxf4g5QLJ1TTAsv0w/s550/P_20231009_003800_1.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="550" data-original-width="437" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj2c-GJZFlw8tpT0bum0u0sinIJCcOqSbjPNgh5CuLmy2NUgbpQzDNtJ2QSUFz-avhOfsxPBAn1tPFw4YbVDXbkOWPE_Cf3malf6hvCymQoBV8XIYpmGIXy49ywxNEGM2XArI8zzvQyDRWL948V1REPmu2RmX82nSsdUyXJubIF5cgxf4g5QLJ1TTAsv0w/s320/P_20231009_003800_1.jpg" width="254" /></a></div><br /><h1 style="text-align: left;">背景</h1>stm32マイコンはuartやspiのバスを複数持っているものがあります。<br />1つのピンに割り当てられているバスが1種類なら問題ないのですが、複数のバスを割り当てられている場合はバスが利用するalt付きのピンを使利用したバスの定義が必要です。<br /><br />とりあえず動くからとalt無しで動かしたら他のバスと混信する不具合に悩まされたので、stm32arduino環境での書き方を共有します。<br /><br /><h1 style="text-align: left;">プログラム作成対象: stm32h753zi</h1>nucleo-stm32h753ziを利用しました。<br />記事を書いている時点で上記ボードのarduino環境はまだ公開されていない(次回2.7.0で対応される見込み)ので、以前試行錯誤して把握したstm32h743ziの環境を利用して動かしました。<br /><a href="https://asukiaaa.blogspot.com/2022/10/nucleo-h753zi-on-platformio.html">nucleo-h753zi向けにPlatformIOを通してArduinoプロジェクトをビルドしてとりあえず動かせた</a><br /><br /><h1 style="text-align: left;">やりたいこと: PB3,PB4,PB5でSPI3を使いたい</h1><a href="https://www.st.com/en/microcontrollers-microprocessors/stm32h753zi.html">stm32h753zi</a>のデータシートのPB3,PB4,PB5を見ると、SPI1,SPI3,SPI6が利用可能と分かります。<br /><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEigpXNddAtMvZPtaAPW0ZdzxzOTOJahYaZ4pkElXOXOhNj82DruvyO9DVK27l6jFYUkVK8Lc56ef6pQKmtmad4BYuhA9k1USNTfHSUyWPhi2SBMPajS9VFPnQwRfc62WQjLoyOV91cX4efqa63ydkJYETU6nLyF29EEQTUbHBs-JIWlW7_Mywr7DtcBzpw/s792/Screenshot%20from%202023-10-08%2023-46-30.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="792" data-original-width="780" height="640" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEigpXNddAtMvZPtaAPW0ZdzxzOTOJahYaZ4pkElXOXOhNj82DruvyO9DVK27l6jFYUkVK8Lc56ef6pQKmtmad4BYuhA9k1USNTfHSUyWPhi2SBMPajS9VFPnQwRfc62WQjLoyOV91cX4efqa63ydkJYETU6nLyF29EEQTUbHBs-JIWlW7_Mywr7DtcBzpw/w630-h640/Screenshot%20from%202023-10-08%2023-46-30.png" width="630" /></a></div><br /><h1 style="text-align: left;">SPI3に割り当てられているaltピンを調べる</h1>stm32arduinoの場合はボードごとにピンの設定ファイルがあるので、それを見てSPIのバスがどのピンに割り当てられているか確認します。<br />設定ファイルは<a href="https://github.com/stm32duino/Arduino_Core_STM32/tree/main/variants">Arduino_STM32_Coreのvariantsディレクトリ</a>の中にあるので、対象のマイコンのPeripheralPins.cppを探します。<br /><br />今回はstm32h743ziの環境を利用しているので、下記のファイルを見ました。<br /><a href="https://github.com/stm32duino/Arduino_Core_STM32/blob/main/variants/STM32H7xx/H742Z(G-I)T_H743Z(G-I)T_H747A(G-I)I_H747I(G-I)T_H750ZBT_H753ZIT_H757AII_H757IIT/PeripheralPins.c">stm32duino/Arduino_Core_STM32/variants/STM32H7xx/H742Z(G-I)T_H743Z(G-I)T_H747A(G-I)I_H747I(G-I)T_H750ZBT_H753ZIT_H757AII_H757IIT/PeripheralPins.c</a><br /><br />SPIのピンは役割ごと(MOSI, MISO, SCK, SS)にまとまっています。<br /><br />MOSIとして動くPB5のSPI3の割当を調べると、PB_5_ALT1として定義されていると分かりました。<br /><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjUkhJD8SJT9SZU6n018-US8WuhNqsvKA2dOzMbQ0-otYFYTMQYoQqJqGf1SelktN3_bwZ59QOk2tEfjQxQT-GyuH1Pbcpu2EW9O5uE_8750owcw-fpBDOpsCmjNL7ycmpICHsdBQt11Dd31dETTVE6MYCtw_SEt8hKWVSBiFGECkdzp1OM5aV0H69rlZc/s716/Screenshot%20from%202023-10-09%2000-01-22.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="203" data-original-width="716" height="182" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjUkhJD8SJT9SZU6n018-US8WuhNqsvKA2dOzMbQ0-otYFYTMQYoQqJqGf1SelktN3_bwZ59QOk2tEfjQxQT-GyuH1Pbcpu2EW9O5uE_8750owcw-fpBDOpsCmjNL7ycmpICHsdBQt11Dd31dETTVE6MYCtw_SEt8hKWVSBiFGECkdzp1OM5aV0H69rlZc/w640-h182/Screenshot%20from%202023-10-09%2000-01-22.png" width="640" /></a></div><br />同様に調べてSPI3向けのピンはMISOはPB_4_ALT1、SCKはPB_4_ALT1として割り当てられていると分かりました。<br /><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjZJUL7GDi0IBrVZ2iqICDvLulKzQXHY3NaDDlmNx6_un0EcPpLS6KJLl3Yhpm-krPZHH_SOvdoHNRRzIUoVHB8nQH2jyC8qKNVpNZ7Sf7dXhNVKPqVOcHmqh4ySmg1KjOtYzhZUO2tmkw8XkkfGrO0tZFqQP2xsz-dlfPQ-YbDysPT9_4RWN_onHOoSiE/s716/Screenshot%20from%202023-10-09%2000-23-26.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="203" data-original-width="716" height="182" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjZJUL7GDi0IBrVZ2iqICDvLulKzQXHY3NaDDlmNx6_un0EcPpLS6KJLl3Yhpm-krPZHH_SOvdoHNRRzIUoVHB8nQH2jyC8qKNVpNZ7Sf7dXhNVKPqVOcHmqh4ySmg1KjOtYzhZUO2tmkw8XkkfGrO0tZFqQP2xsz-dlfPQ-YbDysPT9_4RWN_onHOoSiE/w640-h182/Screenshot%20from%202023-10-09%2000-23-26.png" width="640" /></a></div><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhstcqUsWmBzJkIhxH7smnLUKR47daFCL8MZaORDqtJnw3QlXBQS__1BZ9f6yxrcpUluTdzp0t3-0C0wrNm1DiTZ6EdCIINBDZfuNSiIosw0JtNbGAxLcom8XWSARQFEEUMYTqj-CvXWruvbbBsDZrL7bQBsAuf7DArtmak01cufatWeWZInSqbtlc85uQ/s716/Screenshot%20from%202023-10-09%2000-23-14.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="203" data-original-width="716" height="182" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhstcqUsWmBzJkIhxH7smnLUKR47daFCL8MZaORDqtJnw3QlXBQS__1BZ9f6yxrcpUluTdzp0t3-0C0wrNm1DiTZ6EdCIINBDZfuNSiIosw0JtNbGAxLcom8XWSARQFEEUMYTqj-CvXWruvbbBsDZrL7bQBsAuf7DArtmak01cufatWeWZInSqbtlc85uQ/w640-h182/Screenshot%20from%202023-10-09%2000-23-14.png" width="640" /></a></div><br /><h1 style="text-align: left;">altピンを利用してSPI3を呼び出す</h1>SPI3向けのaltピンを利用してSPI3を呼び出します。<br />今回はSPI_Bという変数でSPI3を使います。<pre>// コンストラクタでピンを指定する書き方<br />#define PIN_SPI_B_SCK PB_3_ALT1<br />#define PIN_SPI_B_MISO PB_4_ALT1<br />#define PIN_SPI_B_MOSI PB_5_ALT1<br /><br />#include <SPI.h><br />SPIClass SPI_B(pinNametoDigitalPin(PIN_SPI_B_MOSI),<br /> pinNametoDigitalPin(PIN_SPI_B_MISO),<br /> pinNametoDigitalPin(PIN_SPI_B_SCK));<br /><br />void setup() {<br /> SPI_B.begin();<br />}<br /></pre><br />ALT付きのピンのマクロはstm32arduino内でPinNameという型の変数として扱われます。<br />一方、PB3などで呼べるピンはuint32_t型で定義されdigitalPinと呼ばれています。<br />記事を書いている時点では<a href="https://github.com/stm32duino/Arduino_Core_STM32/blob/61a1680ef96871a38672b5d9ea57d7a9df9b3141/libraries/SPI/src/SPI.h#L113-L114">SPIのコンストラクタにはdigitalPinを受け付ける実装が無い</a>ので、<a href="https://github.com/stm32duino/Arduino_Core_STM32/blob/61a1680ef96871a38672b5d9ea57d7a9df9b3141/cores/arduino/pins_arduino.c#L25">pinNametoDigitalPinという関数</a>を利用してdigitalPinに変換して渡します。<br /><br />setMOSIなどの関数は<a href="https://github.com/stm32duino/Arduino_Core_STM32/blob/61a1680ef96871a38672b5d9ea57d7a9df9b3141/libraries/SPI/src/SPI.h#L134-L149">PinNameを受け付けるもの</a>と<a href="https://github.com/stm32duino/Arduino_Core_STM32/blob/61a1680ef96871a38672b5d9ea57d7a9df9b3141/libraries/SPI/src/SPI.h#L117-L132">digitalPinを受け付けるもの</a>の2種類が用意されているため、setupでbegin前にピンを割り当てる方式でも良いです。<br /><pre>// setMOSIなどを使ってピンを指定する書き方<br />#define PIN_SPI_B_SCK PB_3_ALT1<br />#define PIN_SPI_B_MISO PB_4_ALT1<br />#define PIN_SPI_B_MOSI PB_5_ALT1<br /><br />#include <SPI.h><br />SPIClass SPI_B();<br /><br />void setup() {<br /> SPI_B.setMOSI(PIN_SPI_B_MOSI);<br /> SPI_B.setMISO(PIN_SPI_B_MISO);<br /> SPI_B.setSCLK(PIN_SPI_B_SCK);<br /> SPI_B.begin();<br />}</pre><br />上記の書き方でSPI3を呼び出せました。<br /><br /><h1 style="text-align: left;">余談: digitalPinで定義するとalt無しのSPIバスが割り当てられる</h1>digitalPin PB3,PB4,PB5を使ってSPIを定義するとalt無しのPinNameで定義したのと同等のSPI1が割り当てられます。<br />stm32は同一のSPIバスを別のピンで呼び出しても内部で接続されるため、繋いでいるピンが違うものの同じ信号が出てきます。<br />意図せず同じバスを割り当てていまうと送信データが壊れることがあるので要注意です。<br /><br /><h1 style="text-align: left;">おわり</h1>機能豊富なピンの特定の機能を呼び出す方法が分からなくて戸惑いましたが、stm32arduinoのマイコンごとのPeripheralPins(周辺機能のピン)を見て使いたい機能のピンを割り当てたら良いと分かりました。<br /><br /><h1 style="text-align: left;">参考</h1><a href="https://github.com/stm32duino/Arduino_Core_STM32/tree/main">Arduino_Core_STM32</a><br /><br />Asuki Konohttp://www.blogger.com/profile/07813182469285556500noreply@blogger.com0tag:blogger.com,1999:blog-9198372554518889060.post-29017027353106632882023-10-02T01:34:00.002+09:002023-10-02T01:34:41.626+09:00ubuntuのノートPCの画面の自動回転を止める<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiqy-WjFMtvAabIfB0X0KFCN52gug006t0xi2UgNNMFTRlA4C05xYTpZBP_ycpsmLbD5MbPP-iLddHaVdkjIRQO3K3WrodeU1fDOnPwysai8IFxeBHg20x6nfKw6g7SrJ6ZpoASDNr4h3GOvl61SMIGM5qzd5e7u4urLvijxwmfAGx5NOEcCQEPNgTgX7A/s2936/IMG_20231002_012837.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="2849" data-original-width="2936" height="311" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiqy-WjFMtvAabIfB0X0KFCN52gug006t0xi2UgNNMFTRlA4C05xYTpZBP_ycpsmLbD5MbPP-iLddHaVdkjIRQO3K3WrodeU1fDOnPwysai8IFxeBHg20x6nfKw6g7SrJ6ZpoASDNr4h3GOvl61SMIGM5qzd5e7u4urLvijxwmfAGx5NOEcCQEPNgTgX7A/s320/IMG_20231002_012837.jpg" width="320" /></a></div><br /><h1 style="text-align: left;">背景</h1>ノートPC(パソコン)を持って作業中に画面を縦に向ける方が見やすいと思って傾けると、画面の自動回転処理が動いて意図せず縦長画面になることがあります。<br />勝手に変わってほしくないので無効化方法を調べました。<br />備忘録として記事に残します。<br /><br /><h1 style="text-align: left;">使ったもの</h1><ul style="text-align: left;"><li>ubuntu22.04</li><li>Lenovo Thinkpad Yoga S1<br />ubuntuをインストールしているノートPCです。<br /></li></ul><br /><h1 style="text-align: left;">iio-sensor-proxyのaccelを無効化</h1>iio-sensorというプログラムが加速度情報を解釈して画面回転に繋がるようです。<br /><br /><a href="https://www.thelinuxfaq.com/ubuntu/ubuntu-17-04-zesty-/iio-sensor-proxy?type=uninstall">iio-sensor-proxyをaptでアンインストールする</a>のを無効化方法として紹介しているところもありますが、このプログラムは明るさ情報なども解釈するようなのでアンインストールすると画面回転以外の機能に影響が出そうです。<br /><br /><a href="https://askubuntu.com/a/864783/655102">udev rulesの加速度センサの設定だけ無効</a>にすれば、画面回転を止めれると分かりました。<br /><br />udev rulesを開きaccelと書かれている行を全て # でコメントアウトします。<br />自分がコメントアウトを実施したときは、accelに関する行が3行ありました。<br />/lib/udev/rules.d/80-iio-sensor-proxy.rules<br /><pre>#SUBSYSTEM=="iio", TEST=="in_accel_x_raw", TEST=="in_accel_y_raw", TEST=="in_accel_z_raw", ENV{IIO_SENSOR_PROXY_TYPE}+="iio-poll-accel"<br />#SUBSYSTEM=="iio", TEST=="scan_elements/in_accel_x_en", TEST=="scan_elements/in_accel_y_en", TEST=="scan_elements/in_accel_z_en", ENV{IIO_SENSOR_PROXY_TYPE}+="iio-buffer-accel"<br />#SUBSYSTEM=="input", ENV{ID_INPUT_ACCELEROMETER}=="1", ENV{IIO_SENSOR_PROXY_TYPE}+="input-accel"<br /></pre><br />accelの行をコメントアウトしたら再起動して設定を反映します。<br />成功すればPCを横にしても画面が回転しなくなると思います。<br /><br /><h1 style="text-align: left;">余談: 効果がなかったこと</h1><ul style="text-align: left;"><li>iio-sensor-proxyのservice disable<br />再起動で復活してしまいます。<br />強い。<br /></li><li>super(windowsボタン) + o での画面回転設定<br />ロックマークが濃くても薄くても回転しました。<br />意味ない。<br /></li></ul><br /><h1 style="text-align: left;">おわり</h1>画面の自動回転を無効化できました。<br />意図せぬ回転が発生して元に戻すためにPCを振り回したり、画面設定から元に戻したりする手間を減らせて嬉しいです。<br /><br /><h1 style="text-align: left;">参考</h1><a href="https://askubuntu.com/a/864783/655102">What process is responsible for auto-screen rotation? I want to disable it (on 16.04)</a><br /><br />Asuki Konohttp://www.blogger.com/profile/07813182469285556500noreply@blogger.com0