食わず嫌いしていた正規表現を勉強し直したら、単純作業がめっちゃ楽になった話

はじめに

この記事は WMMC Advent Calendar 2025 の 12 日目の記事です。(日付 2 回変わってるけど)
昨日の記事 に続き、James がお送りします。

tech-kotalog.hatenablog.com

adventar.org

今日のテーマについて

さて、今日のテーマは 正規表現 です。
なぜこのテーマを選んだのか、少しお話しします。

昨日の記事 の中で、PowerRename という機能を紹介しました。その中で「講義 ○○ 用」というフォルダ名から「○○」だけを取り出すために、 「講義 」を消してから、さらに「 用」を消す、という 2 段階の方法を載せました。

しかし実は、これは正規表現を使えば一発でできます。(恥ずかしい…)

正規表現は、プログラミングの授業で Python を扱ったときに少し触れたものの、 正直あまり覚えておらず「使い方がよく分からない」状態でした。

そこで今回、正規表現をあらためて勉強し直すことにしました。

この記事では、正規表現の網羅的・教科書的な仕様説明は行わず、 マウス開発や日常的な作業の中で実際に使えそうな部分に絞って解説します。

学習に使用したサイトはこちらです。

また、Gemini に簡単な問題を出してもらいながら練習もしました(本当に基礎だけですが)。

これだけは押さえよう

\d(デジット)

数字を意味します。とりあえず「数字を探したい」ときは、まずこれを使えば OK です。

.(ドット)

任意の 1 文字を表します。「なんでもいい 1 文字」です。

*+(繰り返し)

直前の文字が何回続くかを指定します。

  • *アスタリスク:0 回以上(なくてもいいし、何個あってもいい)
  • +(プラス):1 回以上(最低 1 個は必要)

よく使う .* は「なんでもあり」という意味になります。
また \d+ と書くと、「1 桁以上の数字(123 や 4567)」を表します。

()$1(グループ化とキャプチャ)

マッチした部分を、変数のように保存できます。
たとえば (\d+) でつかんだ数字は、置換時に $1 と書くことで再利用できます。

いろいろ使ってみる

PowerRename の例

先ほどは 2 回削除する方法を紹介しましたが、正規表現を使えば次のように 1 回で変換できます。

PowerRename 正規表現

検索:

講義 (.*) 用

置換:

$1

とすることで、「講義 」と「 用」に挟まれた部分だけを取り出せます。

 

ここからは、VSCode などのエディタで使える正規表現をいくつか紹介します!

先頭のスペースを消したい!

ネット上のコードをコピペした際、先頭にスペースや行番号が入り、 BackSpace を連打して消した経験はありませんか。

これも正規表現を使えば一発です。

ここでは「先頭に半角スペースが 1 つ入っている」ケースを例にします。 (今回は例としてスペースですが、タブでも同様です)

置換前

検索:

^(半角スペース)(.*)
  • ^:行頭
  • (半角スペース):先頭にあるスペース
  • (.*):それ以降のすべての文字

置換:

$1

これにより、「先頭のスペースを除いた部分」だけが残ります。

数百行のコードを扱う場合、非常に便利です。

置換後

もし先頭が 1. のように「行番号 + ピリオド + スペース」の場合は以下のようにします。

検索:

^\d+\. (.*)

置換:

$1

デバッグ用の printf を大量に削除・コメントアウト・変更したい!

デバッグ用に printf を多用することはよくありますが、 提出前や本番前には削除・コメントアウトしたくなります。

単純に printf を検索すると、 残したいものまで巻き込んでしまうのが問題です。

そこで、デバッグ用の printf は必ず "debug" から始める という運用ルールを提案します。

printf("debug: hoge = %d\n", hoge);

こうしておくと、正規表現デバッグ用だけを狙い撃ちできます。

検索例:

^.*printf\("debug.*\);$

これらを削除したい場合は、置換を空欄にします。
コメントアウトしたい場合は、置換に //$0 を指定します。

$0 は「マッチした行全体」を意味します。

この方法は非常に便利なので、ぜひ「debug ルール」を導入してみてください!

関数の引数の順番を入れ替えたい!

自作関数として仮に motor_set(speed, duty) という関数があったとします。しかし途中で仕様変更で motor_set(duty, speed) に直したくなった時、全てを変えに行くの大変ですよね…

これも正規表現を使うと簡単に置換することができます。

検索:

motor_set\(([^,]+), ([^)]+)\)

置換:

motor_set($2, $1)

解説:

  • ([^,]+) : カンマ以外の文字が1回以上続く(=第1引数全体)
  • ([^)]+) : 閉じカッコ以外の文字が1回以上続く(=第2引数全体)
  • $2, $1 : 2番目と1番目を逆順で出力

終わりに

いかがだったでしょうか。正規表現は「呪文」みたいでとっつきにくいイメージがあるかもしれませんが、今回紹介したものを覚えるだけで単純作業の効率が爆上がりします!
覚えるの苦手な人とかはせめて「正規表現」という便利なツールがあることだけ覚えておいて、面倒なタスクにあった時に、「あれ使えるかも!」と思い出して、ぜひチャッピーやジェミ兄に聞いていきましょう!

明日は、tomoya さんによる記事です!お楽しみに~!

気づくと手放せないPowerToysの便利機能

はじめに

この記事は WMMC Advent Calendar 2025 11日目の記事です。

adventar.org

どうも James です。

昨日の記事はよつ先輩の 令和最強版 STM32 マイコンの開発環境のすすめ vol.0 基礎知識編 でした。普段何気なくしている”ビルド”の中で何が起こっているか、とても分かりやすかったです!

PowerToysって何?

Microsoft PowerToys は、Microsoft 公式が出している便利機能を集めたアプリで、Windows には標準搭載されていないもののテスト用?のアプリです。(本当にこの説明でいいんか?)

この便利機能の中には、毎日のように使用する便利機能から、誰が使うのか分からないような癖強な機能まであります。

本記事ではこの中から私がおすすめしたい機能を紹介します。

今回もまた Windows ユーザ向けの記事となっています。。

※私の環境では PowerToys v0.96.1を使用していますが、バージョンにより画面・設定項目・挙動が異なる場合があります。
また、各機能のショートカットが他のアプリと競合することがあるので、適宜変更してください。

1. Always On Top

これ、めちゃくちゃ便利です!

これを使うとウィンドウを他のウィンドウの上にピン留めできます。

百聞は一見に如かず、以下が使用例です。

Always On Top

ブラウザとメモ帳を同時に開いて、メモ帳をピン留め(青い枠で囲まれているのが見えます)。これにより、メモ帳を見ながらそのままブラウザにも入力出来るようになります。

私は、「画面分割するほどではないけど、最前面にいて欲しいとき」に使用しています。メモ帳とかエクスプローラーですね。

一度使えばその便利さから離れられなくなるはずです。

 

2. PowerRename

ファイル名やフォルダ名を一括で変更することができます。使える場面は限られていますが、使える時はめちゃくちゃ活躍します!
例えば、大量の写真整理や規則的なファイル名変更が必要な時です。

以下は大学で配布された資料のフォルダ名を一括して変更した例です。

変更前の様子

これらを全選択して右クリックから、「PowerRenameで名前を変更」を選択します。

変更の様子

こんな感じの画面が開くのでフォルダ名を一括変更しました。今回は「講義 」を消した後に、もう一度「 用」を消す操作を行いました。

変更後の様子

こんな感じで一気に名前を変更することができました!

 

3. マウスユーティリティ

これはマウスカーソルに関する設定ができる機能が詰まっていますが、私が使用しているのは Find My Mouse です。
Ctrlキーを2回連続でタップするとカーソルの位置が分かります。

はい、それだけです。

それだけなんですけど、よく使っています。
よく見失っていて、どんな時に見失っているかが思い出せないですけど、背景が白いWebページを見ているときとかマルチモニターを使用しているときとかですかね。

使うとこんな感じになります。

Find My Mouseの使用したときの様子

4. Keyboard Manager

キーの再配置をしたり、独自のショートカットを作成できるツールです。
CapsLock とか 無変換 とか、使ってないキーに別の役割を与えたりするのにどうぞ。
実はまだ使用したことがないけど気になっているので紹介

PowerToysを使用すると既存のショートカットと被ることがあるのでこれを使って解決してください(被ってるけど直してなくて、たまに困ってるなんて口が裂けても言えない)

 

5. テキスト抽出ツールとColor Picker

この2つの機能も PowerToys 便利だよ!と伝えたくて、本記事のメインキャラになってもらう予定だったのですが、便利なので Windows 標準機能にレベルアップしていました(PowerToysを入れなくても使えるということ)!

使用方法は簡単で、スクショと同じで、Snipping Tool を Win + Shift + S で開くだけです。
画面上部からそれぞれの機能を選択できます。

Snipping Toolをショートカットから起動したときの画面

・テキスト抽出ツール

このツールを使用すると、OCR技術により画面内の文字をクリップボードにコピーすることができます。
文字選択できないPDFや画像中の文字などから文字を抽出するのに便利です。
コピーしたら、メモ帳などに貼っ付けて間違っているところがあったら軽微な修正をします。

今回は英文の画像を用意し、それにノイズを乗せてどれくらい正しくテキストを抽出することができるかを検証しました。

テストした画像(ノイズ加工済み)

だいぶ読みにくいですね。

以下にテスト結果を出します。

テスト結果

あのレベルまでノイズをのせてようやくミスをするようになりました。

精度は昔と比較して格段に向上しています!

 

・Color Picker

これは画面上のピクセルの色情報を読み取ることができます。私はパワポで資料作るときなどに使用しています。

Color Picker 使用例

 

おわりに

いかがだったでしょうか。

他にもここで紹介していない癖強な機能がたくさんあるので調べてみてください!

Always On Top と マウスユーティリティ は本当に便利なのでぜひ使ってください!

 

明日はまだ誰も登録してませんね…
誰か書いて~~

使うとちょっと幸せになれるかも? 私のおすすめWindowsショートカット集

はじめに

この記事は WMMC Advent Calendar 2025 3日目の記事です。

adventar.orgどうも James です。
昨日の記事は Tanaport 先輩の魔改造サークル標準機(立志編) | タナポートの工作部屋でした。最低定格電圧 15V の QDDモータを使用した改造標準機、楽しみですね。

ショートカット、使ってますか?

ショートカットを使用すると少し幸せになれるらしいです。この記事では Windows11 ユーザ向けに(Macの人ごめんなさい)私が毎日のように使用しているショートカットを紹介します。知らないものがあったら要チェックです📝一緒に生産性上げていきましょう!

知らないとは言わせない!基本のき

Ctrl + C / V / X / Z / Y

※「+」は同時に押すこと、「/」はその中のどれかを押すことを意味しています。また()は状況に応じて押すことを表します。例えば Ctrl + C なら、Ctrl キーを押しながら C のキーを押します。

さて、これは皆さんご存じでしょう。Ctrl + C でコピー、Ctrl + V で貼り付け、Ctrl + X で切り取り(削除)、Ctrl + Z で操作を一つ戻る、Ctrl + Y で「戻った操作」の取り消しです。

例えば、編集していて元の状態に戻りたくなったときに Ctrl + Z を連打して、「あ、戻り過ぎた!」ってなったら Ctrl + Y で進む、みたいな使い方をします。

Shift + ← / → / ↑ / ↓

カーソルがある部分からテキストを選択できます。
← / → で左右に1文字、↑ / ↓ で上下に1行ずつ選択範囲を広げられます。
ちなみに、矢印の「→」を入力するときは、日本語入力でハイフン(ー)と大なり(>)を連続入力して Space を押すと変換されます。「←」は<-を入力して Space です。地味に便利ですよ!

Ctrl + A

A は All の A で、全選択です。テキストを全て選択してコピーしたり、書式設定を一括変更したりするときに使います。ちなみに Excel だと、表の中にいる時に1回押すと「表全体」が、もう1回押すと「シート全体」が選択されます。

Ctrl + S

S は Save の S。ファイルを上書き保存します。呼吸をするようにこまめに使用しましょう。

Win + L

これ知らない人結構いると思うんですけど、L は Lock の L でパソコンをロックできます。

大学の自習室やカフェなどで、ロック解除されたまま離席する人がたまにいますが、離席する時は必ず Win + Lリテラシーとして習慣づけましょう。

マルチタスク・仮想デスクトップを使いこなそう!

ここではウィンドウ操作に関するショートカットと、合わせてタッチパッドでのジェスチャー操作(James流の設定)を紹介します。
タッチパッドジェスチャー操作をするには、設定を開き(Win + I)、Bluetooth とデバイス > タッチパッドから設定を確認できます。「高度なジェスチャ」から自分好みにカスタムも可能です。

James のタッチパッドジェスチャー操作設定

Win + D

全ウィンドウを最小化し、一瞬でデスクトップを表示します。私は3本指または4本指でタッチパッドを下にスワイプすると同じ動きになるようにしています。

Win + ← / →

画面分割ができます。矢印を押した後、Win を押したままさらに ↑ / ↓ キーを押すことで、4分割(上下方向)も可能です。私はよく、左で調べもの(ブラウザ)・右に生成AI、あるいは左にブラウザ・右に Word のような構成で作業しています。

Win + ↑ / ↓

で今操作しているウィンドウの最大化、で最小化です。

Alt + Tab

今開いているデスクトップ内でのウィンドウ切り替えです。例えば、ブラウザの後ろに隠れているエクスプローラーを選んで前に持ってくる、なんて時に使います。
私は3本指でタッチパッドを左右にスワイプして切り替えるときもあります。

さて、皆さんは仮想デスクトップ使いこなしてますか?控えめに言ってこれ使うと QOL 爆上がりします。
デスクトップを複数作成し、タスクやプロジェクトごとに作業スペースを分けることで、画面をごちゃつかせずに済みます。
ちなみに今の私のデスクトップは、サークルの作業スペースが連続して3つ、空のデスクトップを挟んで、大学の課題用デスクトップが3つ並んでいました。

Win + Ctrl + ← / →

仮想デスクトップ間を移動します。
私は、4本指でタッチパッドを左右にスワイプすると移動できるようにしています。これ、めちゃくちゃ快適です。

Win + Tab

タスクビューを開きます。仮想デスクトップの一覧や、各デスクトップで開いているウィンドウを俯瞰できます。
私は3本指または4本指でタッチパッドを上にスワイプして呼び出しています。

超時短!エクスプローラー・ブラウザのショートカット

エクスプローラーもブラウザも「タブ方式」が採用されているので、共通のショートカットが多いです。ただ、片方でしか使えないものもあるので注意してくださいね。また使用ブラウザにより挙動が異なる場合もあります⚠️

まずは、エクスプローラーでのみ使えるショートカットから見ていきましょう。

Win + E

新しいエクスプローラーのウィンドウを開きます。

Ctrl + Shift + N

新しいディレクトリ(フォルダ)を作成します。
ちなみにブラウザでこれを押すと、シークレットウィンドウが開いたり、最近閉じたページが開いたりします(ブラウザによります)。

Alt + ↑

1階層上のディレクトリに移動します。Linux でいう ../ コマンドと同じ感覚ですね。

Alt + Enter

プロパティを開きます。右クリックしなくていいので楽ちんです。
ちなみに、タッチパッドで右クリックするとき、カチッと押し込んでいませんか?2本指でタップの方がスマートなのでおすすめです!

(Fn +) F2

名前を変更できます。Fn キーを押すかどうかはキーボードの設定によります。

 

次に、共通して使えるショートカットです。

Ctrl + T

新しいタブを開きます。

Ctrl + (Shift) + Tab

タブ間を移動します。Ctrl + Tab で右のタブへ、Shift キーを足すと左のタブへ移動できます。

Ctrl + (Shift) + W

タブを閉じます。Ctrl + W で現在のタブを削除し、Shift キーを足すと全タブ(ウィンドウごと)閉じることができます。
テストが終わったとき、勉強のために開いていた大量のタブをあえて Shift を押さずに Ctrl + W 連打で消していくのが、めちゃくちゃ気持ちいいんですよね!

Alt + ← / →

で1つ前のページ(階層)に戻り、で進みます。
前者が Ctrl + Z 、後者が Ctrl + Y に相当するイメージです。
私の場合、この操作をする時だけキーボード右側の Alt キーを使うので、右手だけで完結している気がします。

Ctrl + L

ブラウザならURLバー(リンク)、エクスプローラーならパスバーを選択状態にします。 Ctrlキーを押しながら LC とタタン♪と押せば、マウスを使わずにリンクコピー完了です!

Ctrl + F

F は Find の F。ページ内検索ができます。大量のファイルから特定のファイルを探したり、長い文章の中からキーワードを探すのに必須の機能です。

スタートメニューは開かない!アプリ起動とシステム設定

Win + X

クイックアクセスメニューを開きます。私がよく使うのは再起動とシャットダウンです。再起動なら Win + X → U → R、シャットダウンなら Win + X → U → U です。※日本語版 Windows 特有のキー割り当てらしいので注意。

Win + I

設定画面が一発で開きます。

Win + (1~9)

タスクバーに配置されているアプリを、左から順に Win + 1, Win + 2... で呼び出せます。

James のタスクバー

私の場合、Win + E (または Win + 1) でエクスプローラー、Win + 2Firefox を開くようにしています。Win + 7VSCodeWin + 8 でメモ帳を開くのも手癖になってます。

Win + R

「ファイル名を指定して実行」ウィンドウが開きます。

Win + R で開く画面

ここで cmd と入れて実行すればコマンドプロンプトが起動します。あと便利なのが sysdm.cpl です。これを実行すると「システムのプロパティ」が開き、そこから環境変数の設定画面へスムーズに行けます。

Ctrl + Shift + Esc

タスクマネージャーを直接開きます。アプリがフリーズした時などは、ここから強制終了させちゃいましょう。

Ctrl + Backspace 使ってる?入力・テキスト編集のショートカット

Win + V

クリップボード履歴が表示されます(初回のみ有効化が必要)。これがない世界はもう考えられません。コピペしたいものが複数あるとき、先に Ctrl + C をしまくって、最後に Win + V で履歴からペタペタ貼り付けていくのが最強です。

Win + .

絵文字パネルが出ます。チャットの時などにどうぞ。

Win + Shift + S

Snipping Tool が起動し、画面キャプチャが撮れます。

Ctrl + Shift + ← / →

「基本のき」で紹介した Shift + 矢印Ctrl を足すと、1文字ずつではなく「単語単位」で選択できるようになります。大幅な時短になります。

Ctrl + Backspace / Delete

普段使っている BackspaceDelete と同時に Ctrl を押すと、「単語単位」で削除できます。これ、めちゃくちゃ便利です。コーディングやレポート作成で確実に役立ちますよ。

おわりに

長々と愛用のショートカットを紹介してきましたが、ここには載っていないものも山ほどあります。各アプリ固有のショートカットも用意されているので、ぜひ覚えて生産性上げていきましょう!
最後に1つおまけ! Wordなどで使える Ctrl + Shift + > / < というショートカットがあります。これで文字サイズを瞬時に変更できるので、ぜひ使ってみてくださいね。

 

明日の記事は akiaki96 さんによる「マウス初心者でも斜めを走りたいのです」です。お楽しみに~!

VSCode上で迷路情報を表示する

はじめに

この記事はWMMC Advent Calendar 2024 15日目の記事です。

adventar.org

こんにちは!Jamesです。

昨日の記事はYuki先輩の第39回全日本学生マイクロマウス大会 参戦レポでした。ロボット学会学生特別賞の受賞おめでとうございます!!

VSCode上で迷路の壁情報を表示させたい!!

なぜ壁情報を表示させたいのか

  • 先輩たちが実際に表示させていてかっこいいと思った
  • マイクロマウスが探索走行で得た壁情報を可視化して客観的に見たい
  • 今後探索系をいじる時やデバッグの時に使いたい

実装方法

実装に当たって、2つの方法を思いつきました。

  • センサ値をprintfを使用してteratermなどに表示させる時と同様に、機体側に迷路情報を表示するプログラムを書く。
  • 迷路情報をデータとしてPCに送り、PC側に迷路情報を表示させるプログラムを書く。

前者の方がシンプルな仕様になりますが、そのうち迷路情報に関するデータをコネコネしてみたいなと思い(使い道は未定)、後者を採用しました。printfではなく、配列を送ることになるので、以下のプログラムはシリアル通信に関するものが多くなっています。

ということで、ChatGPT(以下チャッピー)と相談しながらVSCode上で迷路情報を表示させるプログラムを作成しました。(エディタは別にVSCodeに限らず、正確にはターミナル上で迷路情報を表示)

実装した結果

PCと機体をUSB接続し、PC側でプログラムを実行した後、機体のスイッチを押してやると迷路情報が表示されます。

実際に自分の機体が学生大会2024で得た迷路情報

いい感じに表示できました。(語彙力)

?が表示されている部分は、機体が行っていない未探索の部分で、未知の領域には壁があるものとして表示しています。

↓は公開されている迷路情報です

学生大会2024 クラシックマウス競技の迷路 🔴部分がスタートとゴール

tech-kotalog.hatenablog.com

プログラムを見ていく

概要

最初に、動作環境はWindowsなので注意してください。

main文の流れは大体こんな感じです。

  1. シリアル通信に関する変数、二次元配列を作成
  2. シリアルポートを開く
  3. シリアルポートを設定
  4. 残留データをクリア
  5. マップデータを受信
  6. 受信した生データを表示(デバッグ用に残している)
  7. シリアルポートを閉じる
  8. 迷路情報に変換し表示

Tanaport先輩がこの記事で、VSCode上でST-LINKを使った書き込みやprintfの話をしていて「ST-LINK最高!」みたいな感じなんですけど、そんな中でUARTの話をするのってアリなんですかね? (ST-LINKとマイコン間の通信はUARTを使用しているそうです 2024/12/16)

マイコン側のプログラム

for(int i = 0; i < 16; i++){
    for(int j = 0; j < 16; j++){
        map_data[i][j] = (uint8_t)eeprom_read_halfword(i * 16 + j);
    }
}
HAL_UART_Transmit(&huart2, (uint8_t *)map_data, sizeof(map_data), HAL_MAX_DELAY); // send data

配列map_dataにEEPROM(不揮発性メモリ)に格納された迷路情報を格納し、それを送るシンプルなものです。

PC側のプログラム(関数系)

シリアル通信に関わる部分は大体チャッピーに教えてもらいました。

シリアルポートを開く関数
// 引数 : portName - オープンするCOMポート名
// 戻り値 : 成功時 - シリアルポートのハンドル, 失敗時 - INVALID_HANDLE_VALUE
HANDLE Open_SerialPort(const char* portName) {
    HANDLE hSerial = CreateFile(
        portName,                           // 開くシリアルポートの名前
        GENERIC_READ | GENERIC_WRITE,       // 読み書き両方のアクセス権を要求
        0,                                  // 共有モード(0は共有無し)
        NULL,                               // セキュリティ属性(デフォルト)
        OPEN_EXISTING,                      // 既存のポートを開く
        FILE_ATTRIBUTE_NORMAL,              // 通常のファイル属性
        NULL                                // テンプレートファイル(使用しない)
  );
    if (hSerial == INVALID_HANDLE_VALUE) {
        printf("Error: Unable to open COM port (%s)\n", portName);
  }
    return hSerial;
}

自分の場合、使用するCOMポートはCOM8でした。

シリアルポートを設定する関数
// 引数 :
//   hSerial - シリアルポートのハンドル
// dcbSerialParams - シリアルポート設定用構造体へのポインタ
//   baudRate - 通信速度(ボーレート)
// 戻り値 : 成功時 - TRUE, 失敗時 - FALSE
BOOL Conf_SerialPort(HANDLE hSerial, DCB* dcbSerialParams, DWORD baudRate) {
    dcbSerialParams->DCBlength = sizeof(DCB);       // DCB構造体のサイズ
    dcbSerialParams->BaudRate = baudRate;           // 通信速度(115200bps)
    dcbSerialParams->ByteSize = 8;                  // データビット長(8bit)
    dcbSerialParams->StopBits = ONESTOPBIT;         // ストップビット(1bit)
    dcbSerialParams->Parity   = NOPARITY;           // パリティ(なし)
 
    // シリアルポートの設定を適用
    if (!SetCommState(hSerial, dcbSerialParams)) {
        printf("Error: Failed to configure COM port\n");
        return FALSE;
  }
    return TRUE;
}

SetCommState関数でシリアルポートを設定。

残留データをクリアする関数

機体とPCをUSB接続しているときに、PCでこのプログラムを実行する前に、機体のモード選択をすると、モード選択時に出るprintfなどにより送られるデータがPC側の配列に格納され、正しく迷路情報が表示されないのでこの関数を追加しました。(配列を送る時にヘッダーとフッターを付ける方法も検討しましたが、今回は手軽にできる方法にしました。)

// 引数 : hSerial - シリアルポートのハンドル
// 戻り値 : 成功時 - TRUE, 失敗時 - FALSE
BOOL Clear_SerialBuffer(HANDLE hSerial) {
    // 送受信バッファをクリア
    if (!PurgeComm(hSerial, PURGE_RXCLEAR | PURGE_TXCLEAR)) {
        printf("Error: Failed to purge COM buffers\n");
        return FALSE;
    }
    return TRUE;
}

PurgeComm関数で残留データをクリア。

※PCとUSB接続した状態で、PCでプログラムを実行していないときにモード選択が出来るようにしたが、PCでプログラムを実行している際にモード選択をすることはこの方法ではできない。実行スイッチを押す前の状態にし、PCでプログラムを実行し、機体の実行スイッチを押す必要がある。

マップデータを受信し二次元配列に変換する関数
// 引数 :
//   hSerial - シリアルポートのハンドル
//   buffer - データを格納するバッファ
//   size - 読み込むバイト数
//   bytesRead - 実際に読み込んだバイト数を格納する変数へのポインタ
// 戻り値 : 成功時 - TRUE, 失敗時 - FALSE
BOOL Read_SerialData(HANDLE hSerial, uint8_t* buffer, DWORD size, DWORD* bytesRead) {
    // シリアルポートからデータを読み込み
    if (!ReadFile(hSerial, buffer, size, bytesRead, NULL)) {
        printf("Error: Failed to read data from serial port\n");
        return FALSE;
  }
    return TRUE;
}

ReadFile関数でデータを読み込み。

一次元配列を二次元配列に変換し表示する関数
// 引数 :
//   buffer - 1次元配列のデータ
//   size - バッファのサイズ(バイト数)
// 戻り値 : なし
void Process_Print_Data(uint8_t map[ROWS][COLS],uint8_t* buffer, size_t size) {
    // サイズチェック
    if (size != ROWS * COLS) {
        printf("Error: Data size mismatch (expected %d, got %zu)\n", ROWS * COLS, size);
        return;
  }
    // 2次元配列に再構築
    for (int i = 0; i < ROWS; i++) {
        for (int j = 0; j < COLS; j++) {
            map[i][j] = buffer[i * COLS + j];
        }
  }
    // データを表示
    for (int i = ROWS -1; i >= 0; i--) {
        for (int j = 0; j < COLS; j++) {
            printf("%3d ", map[i][j]);
        }
        printf("\n");
    }
}

扱いやすくするために二次元配列へと変換し、デバッグのためにと一応生データを表示させています。

左下を(0, 0)の区画、右上を(15, 15)の区画にしたいので行は減る方向、列は増える方向のfor文で書いています。

生データから迷路データに変換する関数
// 引数 :
//   map - 受信したマップの生データ
//   maze - mapを迷路データに変換したデータを格納する
// 戻り値 : なし
void Process_Maze_Data(uint8_t map[ROWS][COLS], uint8_t maze[ROWS][COLS]){
    for(int i = 0; i < ROWS; i++){
        for(int j = 0; j < COLS; j++){
            maze[i][j] = (map[i][j]) >> 4;
        }
    }
}

弊サークルの標準プログラムでは、迷路情報は上位4ビットに格納されているので、ビットシフトしたものをmazeに格納します。

なお、迷路情報とは各区画における4方向の壁の有無で表現されており、

#define north 0x08
#define east 0x04
#define south 0x02
#define west 0x01

のように4ビット目に北壁、3ビット目に東壁、2ビット目に南壁、1ビット目に西壁があったら1を無かったら0を格納しています。

例えば、0x0C(1100)のとき、北壁(4ビット目)と東壁(3ビット目)が存在し、南壁(2ビット目)と西壁(1ビット目)が存在しないことを示しています。(0xは16進数の意)

0x05(0101)のとき、東壁と西壁が存在し、北壁と南壁は存在しません。

迷路情報を表示する関数

長いので全部は載せません。特に複雑なことはしていません。

for (int i = ROWS -1; i >= 0; i--) {        //迷路データを16進数で表示
  for (int j = 0; j < COLS; j++) {
      printf("%3x ", maze[i][j]);
  }
  printf("\n");
}

今回もまたデバッグ用に変換した迷路データを表示させています。

あとは体裁を整えていい感じに迷路情報を表示させます。

PC側のプログラム(main文)

int main() {
    const char* portName = "COM8";      // シリアルポート名の設定
    HANDLE hSerial;     // シリアルポートのハンドル
    DCB dcbSerialParams = {0};      // シリアルポートの設定用構造体(0で初期化)
    uint8_t buffer[ROWS * COLS];    // 16x16マップデータを格納する1次元バッファ
    DWORD bytesRead;    // 実際に読み取ったバイト数を格納する変数

    // 2次元配列の定義
    uint8_t map[ROWS][COLS];
    uint8_t maze[ROWS][COLS];
   
    // シリアルポートを開く
    hSerial = Open_SerialPort(portName);
    // ポートが開けなかった場合はエラー終了
    if (hSerial == INVALID_HANDLE_VALUE) {
        return 1;
    }

    // シリアルポートのパラメータを設定(ボーレート:115200)
    if (!Conf_SerialPort(hSerial, &dcbSerialParams, CBR_115200)) {
        CloseHandle(hSerial);  // エラー時はポートを閉じて終了
        return 1;
    }

    // 受信バッファに残っているデータをクリア
    if (!Clear_SerialBuffer(hSerial)) {
        CloseHandle(hSerial);  // エラー時はポートを閉じて終了
        return 1;
    }

    // マップデータを受信
    if (Read_SerialData(hSerial, buffer, sizeof(buffer), &bytesRead)) {
        // 期待したサイズのデータを受信できた場合
        if (bytesRead == sizeof(buffer)) {
            printf("Received map data successfully.\n");
            // 受信データを2次元配列に変換して表示
            Process_Print_Data(map, buffer, bytesRead);
        } else {
            // 受信サイズが一致しない場合はエラーメッセージを表示
            printf("Error: Data size mismatch (expected %zu, got %lu)\n", sizeof(buffer), bytesRead);
        }
    }

    // 使用したシリアルポートを解放
    CloseHandle(hSerial);

    // マップデータを迷路データに変換して表示
    Print_Maze(map, maze);

    return 0;
}

こんな感じになりました。

現状と展望

良い点

  1. エラーが何なのかが分かりやすい。
  2. 綺麗に表示される。

1番について、PCと機体を接続するの忘れてプログラムを実行して、Error: Unable to open COM port (8) の表示を既に何回か見ました。

改善したい点

  1. ヘッダーとフッターを追加し、プログラム実行中でも機体を操作できるようにしたい。
  2. 実は未探索の区画だけど?が表示されていない区画がある。

2番について、区画には入っていないけれど横を通過し、そこに壁がなかった場合に?が表示されません。解決するためには、入った区画を格納する配列を機体側で用意してそれを基にやるのがいいかと。まだ、全面探索などをする段階にないのでいったん放置します。

追加したい機能

  1. 最短経路を表示したい。
  2. 歩数マップを表示して、経路導出を視覚的にイメージしやすくしたい。
  3. データをコネコネするにあたって、データをファイル出力して、いつでも使えるようにする機能を追加したい。

終わりに

今回はVSCode上で迷路情報を表示させるということで、完全に自己満足でプログラムを作成しました。とりあえず今は満足しているのでそのうちアップデートします。もっといいやり方あるのに~って方はぜひ教えて欲しいです!

なんかもっと解説っぽい記事にしたかったのですが、ただコードを貼っ付けたみたいな記事になってしまいました…。書き方も少しずつ習得していきたいですね。

明日はPotewo先輩の、自宅サーバーの紹介です。お楽しみに!

全日本学生マイクロマウス大会2024に参加した話

この記事はWMMC Advent Calendar 2024 6日目の記事です。

adventar.orgみなさん初めまして。Jamesです。

昨日の記事はTanaport先輩のVScode上でST-LINKを使って書き込み、printfもしている話 | タナポートの工作部屋でした。ST-LINKの通信速度が480Mbpsも出て、STM32のUARTのデフォルト通信速度の約4000倍にもなることに驚きました。(#°Д°)

 

 

マイクロマウスってなに??って方に向けて

マイクロマウスについて超簡単に説明すると、ロボットが人の指示などなしに自律的にスタートからゴールへと迷路(16×16区画で1区画の大きさが決まっている)を進んでいき、2回目以降の走行では、1回目で得た迷路情報を基に最短経路で速度を上げて走行し、そのスタートからゴールまでのタイムを競う競技です。

 

第39回全日本学生マイクロマウス大会

第39回全日本学生マイクロマウス大会@東京理科大学野田キャンパス

私は今回の大会が2回目の大会でした。1回目は2024年10月5日~10月6日に開催された東北地区大会に参加したもので、センサトラブルなどもあり5R(5回ともゴールにたどり着かず)という悔しい結果を残しました…

そして、今回は私の出走順が1番目だったこともあってめちゃくちゃ緊張していたのですが・・・

学生大会2024 クラシックマウス競技の迷路 🔴部分がスタートとゴール

無事完走することができました!!🎉🎉

これで全日本大会への出場切符を手に入れました!ヾ(≧▽≦*)o

 

結果

1走目:02:08.122

2走目:00:43.996

3走目以降は時間切れ

 

1走目の探索走行では行きのタイム(スタート→ゴール)が02:08.122で、帰りも探索したので5分の制限時間の中でだいぶ時間に余裕がなくなってしまいました。

2走目では時間が残り1分ほどで、間に合わせたい&やらずに後悔したくなかったので用意していた最高パラメータで走らせました。

今回、横壁補正の際に、制御量を速度に応じて変化させる機能を追加し、今回の速度の範囲ではとても安定して走ってくれました。

 

ロボットの紹介

荒風(あらかぜ)

この機体は、弊サークルの標準機体で、2つのステッピングモータで駆動し、壁情報は赤外線LEDとフォトトランジスタを用いて読み取ります。

名前は荒風(あらかぜ)です!

てか用意していた最高パラメータで走らせて44秒って遅くない???ていう感じなのですが、(今回の優勝者のタイムは00:03.696)

 

今回の課題

スラローム走行の未実装

元々入れていた円弧スラロームでは滑りが発生し、その後の機体位置を補正するのが大変だったので封印しました。

ということで、クロソイドスラローム(滑らかなカーブを描く走行方式)を実装しよう!という事になったのですが、、作業に取り掛かるのが遅すぎた。。普通に授業がある中で5日間では間に合いませんでした。

という事で本番は超信地旋回(一度停車し、その場で旋回する方式)で走らせたのでだいぶ遅くなりました。

 

ゴール座標の設定に関して

ゴール座標は決まって(7, 7)に設定していましたが、今回の迷路の場合、(7, 8)に設定しておけば右側からの長い直線を加速してタイムを縮めることが出来たと予想されます。

 

東日本地区大会に向けて

12月21日/22日に東京工芸大学厚木キャンパスにて東日本地区大会が開催されるので、そこでクロソイドスラロームをお披露目します(宣言)。

それから今回追加した速度に応じた補正項の最大値を調整する機能が、今回の迷路では長い直線区間が少なかったことから、機体速度がさらに上がった時の挙動がまだ分からないので、それの調整もします。

 

その他

スポンサー様からいただいたものと大会記念品

前川製作所さんのブースのガチャガチャで非売品の産業用冷凍機の圧縮機(間違ってたらごめんなさい🙇)のミニチュアを当てられたのが嬉しかったです。三菱電機さんのムブアイもかわいくていいです!スポンサーの皆様ありがとうございました。

 

終わりに

今回の大会では無事に初完走を決めることが出来ました!しかし、計画力のなさが露呈した大会でもありました。今後の教訓にします。次は東日本地区大会が待っているのでそこで今回の悔しかった点をぶつけたいと思います。

明日は、よつさんの新機体の紹介 ~obsidian~です。お楽しみに!