2014年3月31日月曜日

ビデオ提出完了!

一年ハード班のライカです。


今回も様々なことがありましたが、無事二次審査用のビデオ撮影も終わり、先ほどMIさんが編集が完了し、提出したとの報告がありました。

今回のビデオ撮影までの製作過程において、自分自身まだまだ未熟だと感じることは多かったですが、先輩方の努力の甲斐あって、スムーズに制作が完了しました。

また、今回は体育館が工事中のため、撮影に使えるほど大きな場所がほとんどなく、撮影自体がなかなかシビアで、自分も初めて徹夜をしました。

しかし、メンバーの努力もあって三月中にはビデオが提出できました。

本当に皆さん、お疲れ様でした。


本戦は六月のはじめにあり、それまでに新入生の勧誘や部内ロボコン、機体の調整など、まだまだ忙しいですが、頑張っていきましょう。



次回のブログはacoさんによろしくお願いします。

2014年3月13日木曜日

二次審査に向けて

一年回路班のMIです。
二次審査突破を目指し、各班気合を入れて活動しています。
自分もリレーの回路を作ったりしてましたが、先輩がH_bridgeを完成させてくれたのでお役御免に(笑)。しかし、この回路作成を通して先輩から熱転写でのエッチング方法を学ぶことができ、さらに技術をつけれたかと思います。今後も先輩たちからどんどん技術を吸収して、新入生に笑われないように精進したいです。

次のブログ担当はライカにお願いします。

2014年3月4日火曜日

二代目タイヤ

 1年ハード班ヒビです。
 残念ながら前回のタイヤは「重い」、「大きい過ぎる」、「シリコン使いすぎ」と、散々に言われたので改良しました。

完成品がこちら

 シリコンの厚みは以前の三分の一、直径はΦ116くらい、質量もだいぶ減りました。乾燥にかかった時間はひとつあたり約3日。たぶん2日でも大丈夫だとは思いましたが、今回は急ぎでもなかったのでゆっくりとやらせてもらいました。(決して、大学へ行くのが面倒だったとかじゃないですよ?)

 ちなみに、型はケーキ型の4号を使ったのですが100均の安物ということもあり、底蓋がずれやすいです。つまりホイール部の固定がしっかりとなされないので、中心がずれるということです。養生テープで底蓋の固定はしましたが、実際に機体を走らせたとき揺れたらどうしようか...。底蓋の直径と型本体の内径がぴったりと合うような型がほしいです。

 タイヤ製作に関するノウハウを次の新入部員にも伝え、あわよくばよりよい方法を考案してくれたらなぁ、などとまた楽をしようとしてますが、まぁそれはとりあえず置いておきましょう。
 
 納期まで後わずかなので、NHK二次ビデオ審査に向けて機体の改良をがんばっていきます。


 次のブログはMIさんにお願いします。

2014年3月1日土曜日

STBeeでSDカードデータロガー

概要

STBeeを使用してSDカード(FAT16でフォーマットされているもの)にSPI通信で書き込み、読み出しする。
 

 仕様

・今回は、ロボットに動作ログ保存を保存するために組み込むことを目標としており、電源投入時に新ログファイルを生成し、生成されたログファイルには書き込むことしかしない。
・上記の過程で新規ログファイルを作るためにファイル名を管理している別のファイルには書き込み読み出し両方を行う。
・SPIはSTBeeにある3CHのうち、1CH を使用する。


開発環境

・使用するマイコンボードはSTBee。
・STBeeの開発環境は書籍『マイコン徹底入門』(通販サイトに飛びます) と、webサイト『マイコン徹底入門』を使用して構築した開発環境(Eclipse)を利用する。
(書き込みはDFU旧版、開発環境はEclipse同梱の20101215版を使用)
・SDカードへのアクセスには上記で構築した開発環境に入っているFatFsを利用する。


SDカードの動作テスト

まず、開発環境にサンプルとして入っている spi_sd_test_terminal を実行する。
今回利用した書籍(初版2010/12/15)には誤植があるが、それについてはまた後ほど。
(3版でも同様の誤植を確認しました)
今回の回路はこちら↓


やってること

PC-STBee間をシリアル通信で接続し、PC側からのコマンドでSTBeeがSDカードに書き込み読み出しを行う。
コマンドとその内容についての解説はマイコン徹底入門に譲るとして、読み出して書き換えるまでの手順を簡単にまとめると以下のようになる。

1. 作業領域の確保(f_mount)
2. 操作対象とするファイルを開く(f_open)
   この時、書き込み、読み出し位置を指定するRWポインタは0になっている。
3. 読み出しを行いたい場所にRWポインタを移動(f_lseek)
4. 読み出し(f_read)
5. 書き込み(f_write)
6. キャッシュのフラッシュ(f_sync)
7. ファイルを閉じる(f_close)


SPI1CHを使用してSDカードにアクセスする

ライブラリのリネーム

まず、マイコン徹底入門によると、SPIを用いてSDカードにアクセスするライブラリを利用するには /lib/SPI_SDlib/SD と書き換える必要があるとされている。
しかし、ここを指示通り書き換えるとコンパイルエラーを吐いてしまう。
試しに書き換えをせずにコンパイルしたところ、正常にコンパイルされた。


SPI通信のチャンネル変更

マイコン徹底入門の環境では、デフォルトでSDカードを使用する時のSPI通信は2CHを使用するようになっている。
今回、基板の都合で1CHを使用したかったので、チャンネルの変更が必要となった。
マイコン徹底入門によると、この変更は platform_config.h 書き換えればチャンネルの変更が出来ると書かれている。
しかし、ここにはSPI通信の設定らしきものはない
正しくは、 STBee.h である。
STBee.h後半部分にSDカードにアクセスするときのSPI通信のピン配置についてのマクロがあるので、ここを使用するチャンネルに対応するように変更する。
1CHに設定するときは下のとおり。
//Definition for sd_spi_stm32.c / ff.c
#define CARD_SUPPLY_SWITCHABLE   0
#define SOCKET_WP_CP_CONNECTED   0
#define GPIO_WP_CP               GPIOC
#define RCC_APB2Periph_GPIO_WP_CP  RCC_APB2Periph_GPIOC
#define GPIO_Pin_WP              GPIO_Pin_6
#define GPIO_Pin_CP              GPIO_Pin_7
#define GPIO_Mode_WP_CP          GPIO_Mode_IN_FLOATING
#define SPI_SD                   SPI1
#define GPIO_CS                  GPIOA
#define RCC_APB2Periph_GPIO_CS   RCC_APB2Periph_GPIOA
#define GPIO_Pin_CS              GPIO_Pin_4
#define DMA_Channel_SPI_SD_RX    DMA1_Channel2
#define DMA_Channel_SPI_SD_TX    DMA1_Channel3
#define DMA_FLAG_SPI_SD_TC_RX    DMA1_FLAG_TC2
#define DMA_FLAG_SPI_SD_TC_TX    DMA1_FLAG_TC3
#define GPIO_SPI_SD              GPIOA
#define GPIO_Pin_SPI_SD_SCK      GPIO_Pin_5
#define GPIO_Pin_SPI_SD_MISO     GPIO_Pin_6
#define GPIO_Pin_SPI_SD_MOSI     GPIO_Pin_7
#define RCC_APBPeriphClockCmd_SPI_SD  RCC_APB2PeriphClockCmd
#define RCC_APBPeriph_SPI_SD     RCC_APB2Periph_SPI1
#define SPI_BaudRatePrescaler_SPI_SD  SPI_BaudRatePrescaler_4
#define STM32_USE_DMA




動作テスト

結果としてはマイコン徹底入門にある通りなので具体的な内容は割愛するが、SDカードのフォーマットや、ファイルの数、容量、その中身を読み出すことができた。


データロガーの制作

ロボットのデータロガーを制作する。

ログファイルの生成

今回、ロボットに搭載するデータロガーということで、いつ電源を喪失するか分からないので、同一ファイルに上書きするのではなく、電源投入時に毎回個別のログファイルを生成してそこに保存する必要がある。
そこで、起動時にログファイル名を管理するための管理ファイルを読み出し、その内容から新しいログファイルを生成する方法をとる。
手順は次の通り。
1. 管理ファイルからデータの読み出し。
2. 読みだしたデータを元に生成するログファイルの名前を文字列で生成。
3. 読みだしたデータ をインクリメントして管理ファイルに書き込む。
4. 2で生成したファイル名のログファイルを生成。
5. 4で生成したログファイルを書き込みモードでオープン。


ff.cにf_size関数が存在しない

そもそもこのような形式をとることを決める前には、1つのログファイルの末端にログを書き足していくことを考えていた。
FatFsにあるf_size関数を使ってログファイルのサイズを取得、末端にRWポインタを移動して、そこから書き込むつもりであったが、 この関数が定義されていないという問題が発覚した。
結局は起動時に新しいログファイルを生成するほうがログの管理にも都合が良いということでこの方式は廃案となったため、これ以上手は加えていない。


管理ファイル

予めSDカード内にログファイル名を管理する管理ファイル(ファイル名は任意に設定できる)を作成して、以下のように書き込む必要がある。

0000

電源投入時にこのファイルの中身を読みだして、次回起動時のためにインクリメントしてデータを書き込まれる。


atoi関数とitoa関数

SDカードに保存されているログデータはテキストデータであり、その内容はアスキー文字である。
したがって、これを数字に変換する必要があるが、 itoa関数はこの開発環境には用意されていない上に、移植性が無いため使用は推奨されていない。
そこで、数値で言う0から9までがアスキー文字コードの10進数表記で48から57までで対応していることを利用して自作で互換処理を書く。
実際に埋め込んだ処理は下のソースコードの
//-- アスキーコードを数値に変換(atoi) --//以下と、
//-- 数値をアスキーコードに変換(itoa) --//以下に記述してある。

ファイル名長の制限

FAT16でフォーマットされていると、8文字までのファイル名と3文字までの拡張子の制限内でファイル名を決めなければいけない。
FAT、HPFS、NTFS ファイル システムについて


sprintf関数

実際にファイル名を決める時に"log○○.txt"(○○は数字)としたいが、数値と文字列が混じってしまうので、sprintf関数を使って文字列にまとめる。
 しかし、この関数を使用すると"undefined reference to `_sbrk'"とエラーが発生する。
この開発環境はEclipse上で動作するARM開発環境であるyagartを使用しているが、どうやらこの環境だとsprintf関数に限らず文字列操作系の関数は同様のエラーが発生するようである。
対策としては、プロジェクトにsyscalls.cを導入する方法がある。 
syscalls.cは記載されているURLからはDL出来なかった(2/26現在)ので、下に書かれている内容をコピペしてsyscalls.cを作った。

ログファイルを生成し、書き込み可能な状態にする関数は以下のようになる。


int8_t manage[] = "/manage.dat";//保存先管理ファイル
uint8_t manageNumber[4];    //管理番号
char nextNumber[4];
unsigned int logfileNumber;   //ログ管理番号
int8_t filename[100];           //保存先
UINT data_read, data_write;


/*
 * @brief ログファイルの管理、生成、書き込み可能処理までを行う
 */
void initLogManage(){
  f_open(&ftxt, manage, FA_READ|FA_WRITE);//管理ファイルオープン

  f_lseek(&ftxt, 0);//先頭を指定

  f_read(&ftxt, manageNumber, 4, &data_read);//管理番号読み出し

  //-- アスキーコードを数値に変換(atoi) --//
  manageNumber[0] = manageNumber[0] - 48;
  manageNumber[1] = manageNumber[1] - 48;
  manageNumber[2] = manageNumber[2] - 48;
  manageNumber[3] = manageNumber[3] - 48;

  logfileNumber = manageNumber[3] + manageNumber[2]*10 + manageNumber[1]*100 + manageNumber[0]*1000;

  sprintf(filename, "log%d.txt", logfileNumber);//ログファイル名生成(ファイル名は拡張子除いて8文字まで)

  logfileNumber++;//次の管理番号に移行

  //-- 数値をアスキーコードに変換(itoa) --//
  nextNumber[0] = (logfileNumber/1000) + 48;
  nextNumber[1] = (logfileNumber/100 - (logfileNumber/1000)*10) + 48;
  nextNumber[2] = (logfileNumber/10  - (logfileNumber/100)*10) + 48;
  nextNumber[3] = (logfileNumber - (logfileNumber/10)*10) + 48;

  f_lseek(&ftxt, 0);//先頭を指定
  f_printf(&ftxt, "%s", nextNumber);//次の管理番号書き込み
  f_close(&ftxt);//ファイルクローズ


  makeSDcard(filename);//ログファイル生成

  openSDcard(filename);//ログファイルオープン

}

/*
 * @brief SDカードにファイルを生成する
 * @param filename ファイル名
 */
void makeSDcard(int8_t filename[]){
    if(cardMount == MOUNTED){
        f_open(&ftxt, filename, FA_CREATE_NEW);//ファイル作成
    }
}

/*
 * @brief SDカードにあるファイルを開く
 * @param filename ファイル名
 */
void openSDcard(int8_t filename[]){
  if(cardMount == MOUNTED){
      f_open(&ftxt, filename, FA_WRITE);//ファイルオープン
      f_lseek(&ftxt, 0);//ファイル先頭まで移動
  }
}

ログデータの書き込み

ログファイルが生成された時点でRWポインタは先頭に設定されているので、そのまま書き込む処理をする。
ただし、データの見やすさを考慮して、書き込みが終了したら改行コードを挿入する。
また、いつ電源が切られてもいいように文字列を書き込み終わったらf_sync関数でキャッシュをフラッシュしておく。
/*
 * @brief 開いているファイルに書き込む
 * @param str 書き込みたい文字列
 */
void writeSDcard(char str[]){
  f_printf(&ftxt, "%s", str);//文字列書き込み

  f_putc('\n', &ftxt);//改行

  f_sync(&ftxt);//書き込み
} 

管理ファイル(manage.dat)を元に電源投入の度に新しいログファイルを生成してログを保存する。

書き込まれたログデータ。1s毎に割り込みを入れて時間もカウントしている。


使用上の注意事項

SDへの書き込みには時間がかかるようで、この遅延は予想以上に大きなものだった。
例として上であげたログデータのACD is initialised. の書き込みまでで人間が検知できるほどの遅れが発生しているため、ロボットのログ取りで特にPID制御中のセンサの値を書き込むときなどは毎回書き込ませると制御に影響が出るおそれがある。
何度かに一度の書き込みにして書き込み回数を減らすか、本末転倒になるがシリアル通信でPCに送るかの方法に変更したほうが安全であると思われる。
あくまでSDカードの利用はどこまで処理が実行されているかのチェックポイント程度が調度良いと思われる。
また、書き込み中に割り込みで別の文字列を書き込む処理が発生した場合、上手く書き込みができなくなることがあるので、どうしても割り込みで書き込む必要がある場合は書き込み関数で割り込みを無効にしてから書き込むか、割り込みを保留にして書き込む工夫が必要になる。