この記事は
マイクロマウス(2) Advent Calendar 2024 - Adventarの22日目の記事となっています。
はじめましてこみです。
今回は12/1に行われたマイクロマウス学生大会について振り返っていこうと思います。
学生大会の振り返り
クラシック 結果 最短失敗
クラシックは最近全く触っておらず、にも関わらず前回の中部地区大会で2位になってしまったので、ちょっとまずいなと思ったので今回は力を入れました。
具体的には、これまでは制御においてターン中や直進中は相対的な角度でしか扱ってなかったのですが、絶対的な角度で扱うように変更しました。今のクラシック機は吸引するとセンサにノイズがのって、斜めの壁制御が効かなくなる問題があるので、斜め直進中に理想角度に追従させるようにして、角度だけでも直すことで、斜めの安定性が多少上がりました。
また、絶対角度をつかって、前回のターンの理想角度と現在の角度の差を求め、次のターンの角度を調整するという制御も入れてみましたが、これは壁にぶつかったりして大幅に姿勢がブレても稀に立て直すということがあったので、導入した意味はあったと思います。
さて大会の結果ですが、探索のみで最短失敗という結果になりました。長い斜めに入る前の連続ターンで姿勢がぶれ、角度制御で姿勢を直す前に、柱に接触してフェイルセーフがかかってしまったようです。フェイルセーフ緩めるか、切るかしてればワンチャン走ってたので、出走が終わってからすごく後悔しました。また、この機体はいっぱい吸引すると振動で制御が暴走するという問題もあるので、あまり吸引力を上げられません。その結果高速ターンで滑って再現性が悪くなるといった問題もあります。このように問題を抱えすぎていてこの機体で調整するのが辛くなってきたので新機体作りたいです。ただ、そんな余裕はなさそうなので今シーズンはこの機体で出場すると思いますが...
ハーフ 結果 5位
クラシックに力を入れたのでハーフは今回は攻めたことをせず、完走してポイントを取りにいくことを重視しました。
ハーフ機はデンソーカップのときから探索や最短時に再現性なく暴走するという問題に悩まされていました。当初は配列への領域外参照などソフトウェアのバグを疑っていたのですが、制御関係なく左右のモーターをduty100%で回したり、走行中にタイヤを手で押さえたりすると、マイコンが落ちることからハードウェアの問題だとわかりました。機体の回路をサークルの人に見てもらって、電源のコンデンサ容量が低いのではないかという、アドバイスをもらい、電源のコンデンサを違法増築しましたが、あまり改善しなかったです...
結局モーターのdutyを50%に制限する事である程度暴走を抑えるようにはなりました。
ただ、電圧を制限してもタイヤがロックしたりして電流がいっぱい流れるとマイコンが落ちてしまうので、そうなる前にフェイルセーフをかけるようにしています。
そしてハーフの大会結果は5位でした。今回は探索で出た経路が簡単だったこともあり、初めて5走全て走り切ることができました。今回の複数ポイントで全日本は32x32になりそうなので、この機体では安定した探索と、非吸引斜めで完走を目標に頑張りたいと思います。
大会の振り返りはここまでにして、ここからはサークルの人にstm32の内蔵flashへの迷路保存についてブログを書くように頼まれたので,ここからはflashに迷路保存をする方法について書いていこうと思います。
マイコンはSTM32G491REU6を使用し、開発環境はSTM32CubeIDEを使用しています。
まずstm32g4シリーズのリファレンスマニュアルを参照して、flashのどこのアドレスを使用するかを決めました。どうやらflashメモリは番号の若い順に使われていくみたいなので、下の図のバンク1のページ126、127(0x0803F000~0x0803FFFF)の4KBの領域を使うことにしました。
次にSTM32G491CEUX_FLASH.ldのMEMORYコマンドの定義に使用するメモリの領域を追加しました。
- /* Memories definition */
- MEMORY
- {
- RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 112K
- FLASH (rx) : ORIGIN = 0x8000000, LENGTH = 508K
- MYDATA (rx) : ORIGIN = 0x803F000, LENGTH = 4k
- }
ビルドした後にcubeideのWindow->Show ViewからBuildAnalyzerを開くとメモリの配置が変更されたことが分かります。
以下はHALライブラリでのflashに情報を書き込むコードです。マイコンのデータシートを読むと、FLASHへの書き込みは制限されており、書き込みを行う際にはロックを解除する操作が必要なようです。HALライブラリのHAL_FLASH_Unlock()、HAL_FLASH_Lock()を呼べばロック解除とロックの操作をやってくれるみたいです。
flashの仕様とHALの関数の仕様はこちらのブログの方が詳しく書かれているため、ここでは省略します。
迷路情報は構造体にまとめてflashに保存するようにしました。今回は8byte単位でflashに書き込むことにしたため、構造体の変数のサイズも8byteのuint64_tにしました。
- #include "stm32g4xx_hal.h"
- #define START_ADR 0x0803F800
- #define MAZE_SIZE 16
- typedef struct FLASHMAZEDATA//迷路情報を格納する構造体
- {
- uint64_t Maze_Row[MAZE_SIZE-1];//1横壁
- uint64_t Maze_Column[MAZE_SIZE-1];//2縦壁
- uint64_t Maze_M_Row[MAZE_SIZE-1];//3最短の横壁
- uint64_t Maze_M_Column[MAZE_SIZE-1];//4最短の縦壁
- uint64_t Maze_KnowMap[MAZE_SIZE];//5既知の区画かどうか(0:未知、1:既知)
- }FLASH_MAZE_DATA;
- uint32_t EraseFlashMaze();//Bank1、127page目をすべて1にする
- void WriteFlashMaze(FLASH_MAZE_DATA* data);//8byte単位でデータをflashに書き込む
- void ReadFlashMaze(FLASH_MAZE_DATA* retdata);//迷路情報を読み出す
- void InitFlashMaze();//FLASHの迷路情報を初期状態にする
- #include "PL_flash.h"
- uint32_t EraseFlashMaze()//Bank1、127page目をすべて1にする
- {
- HAL_FLASH_Unlock();
- FLASH_EraseInitTypeDef erase;
- erase.TypeErase=FLASH_TYPEERASE_PAGES;
- erase.Banks=FLASH_BANK_1;
- erase.Page=127;
- erase.NbPages=1;
- uint32_t error=0;
- HAL_FLASHEx_Erase(&erase, &error);
- HAL_FLASH_Lock();
- return error;
- }
- void WriteFlashMaze(FLASH_MAZE_DATA* data)//8byte単位でデータをflashに書き込む
- {
- EraseFlashMaze();
- HAL_FLASH_Unlock();
- uint32_t adr=(uint32_t)START_ADR;
- uint64_t size=sizeof(FLASH_MAZE_DATA)/sizeof(uint64_t);//8byte単位のdata数を求める
- uint64_t* ptr=(uint64_t*)data;//8byteづつ書き込みを行うため、uint64_t*にキャストする
- for(uint64_t i=0;i<size;i++){
- HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD, adr, *ptr);//8byte分flashに書き込み
- ptr++;//ポインタの指すアドレスを8byte進める
- adr+=sizeof(uint64_t);//addressを8byte分進める
- }
- HAL_FLASH_Lock();
- }
- void ReadFlashMaze(FLASH_MAZE_DATA* retdata)//迷路情報を読み出す
- {
- *retdata=*(FLASH_MAZE_DATA*)START_ADR;//0x0803F800からFLASH_MAZE_DATA構造体のサイズ分を読み取る
- }
- void InitFlashMaze()//FLASHの迷路情報を初期状態にする
- {
- EraseFlashMaze();
- HAL_FLASH_Unlock();
- uint32_t adr=(uint32_t)START_ADR;
- uint64_t size=sizeof(FLASH_MAZE_DATA)/sizeof(uint64_t);
- for(uint64_t i=0;i<size;i++){
- if(i==15)//(0,0)の東壁を立てる
- {
- HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD, adr, 1);//8byte分flashに書き込み
- }
- else
- {
- HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD, adr, 0);//8byte分flashに書き込み
- }
- adr+=sizeof(uint64_t);//addressを8byte分進める
- }
- HAL_FLASH_Lock();
- }
flash実装したら何度も探索を走らせる必要がなくなったので、最短走行のデバックにはとても効果的でした。実装して良かったと思います。