スゴイロガーはじめました

Fenrirさん企画のスゴイロガーことNinjaScanのお手伝いをしています.

スゴイロガーはすごいです.何がすごいって,説明などはそのうち・・・w

自分が忙しかったために9月中は手をつけていませんでした,10月に入って本格的にお手伝いということで,部品の実装をしています.電源部分まで動作確認しました.このあとSTM32F4の動作確認をしてセンサをつなげていきます.

写真はUSB給電で,電源が来ているのを確認しているところです.電源ICが面白くて,USB/外部電源/電池の電源切り替え,LiPo充電機能,DC/DCコンバータを1チップでもつ電源ICなので電源だけでも楽しめてます.

 

LEDをチカチカ

ちょっと考えがあってLEDをチカチカさせたりしています。

左からArduino、MSP430、STM32のマイコンボードでLEDチカチカさせています。早いうちに何かの成果物の形になって、ここで見せれたらなぁという野望の元、基本の基本、LEDをチカらせてテンション上げてます。

気圧高度計(MS5611)をArduinoで使ってみた その1

前回までに以下の様な基板を作っていました。

MPU-6050基板作ってみた(前半)基板設計

MPU-6050基板作ってみた(後半)リフローしてみた

これは加速度ジャイロ地磁気、更に気圧計を載せて10軸の情報を得られるものです。ロケット姿勢・位置の計測用に使う予定です。当初の予定では秋月電子にも売っているMPL115A2というセンサを使う予定でしたが、さらに高精度な気圧計があるということでピンコンパチなこともあって、そちらのセンサを試してみました。

measurement社のMS5611-01BA03というものです。系列としては秋月電子などにモジュールとして売られているパララックス社高度計測モジュールに載っている気圧高度計のセンサ(MS5607)の次世代バージョンのものになります。

高分解で10cmまで測れると宣言していて本当かよ、とにわかに信じがたいので実際の動作を見てみました。

マイコンはArduinoでI2Cで接続しています。SPIでも繋げられるのでSPIの方が良さそうですが、今回の基板がそもそもMPU-6050というI2Cで繋がる基板への追加部品ということでI2Cでつなげています。

写真のように、5VのArduinoと繋がるようにセンサボートの前にI2Cのレベル変換モジュールを入れています、そしてSDカードに記録するために抵抗分圧で3.3Vで駆動するSDカードとつなげています。SDカードはArduinoにライブラリがあるのでそのまま使いました。すごくお手軽にうごくので嬉しいです。

MS5611でも秋月に売っているパララックス社の高度計測モジュールでも動くライブラリは存在しますが、センサがどのように動いているか理解のために自分でコード書いてみました。

Arduinoの既存のライブラリとしては

パララックス社が公開しているものFreeIMUを作っている方のブログに公開されているもの

があります。他にもmbedのライブラリとしてセニオネットワークさんが作っておられるライブラリとサンプルがあります。このmbedのライブラリはプロの仕事なので抽象度も高くキレイにまとまっていて勉強になります。

サンプルライブラリ

上のライブラリの方がオススメですが、自分で作ったものも公開しておきます。今回はシリアル通信でPCに表示させるところまでです。このあと、ログをSDカードに保存したり、生データにフィルタをかませたり、加速度ジャイロと合わせたりします。

/*
MS561101BA用スケッチ
MS5607でも使えるはず(たぶん)
I2Cでセンサデータを取得し、シリアル通信でPCに表示
by ina111
2012/07/16
*/

#include <Wire.h>

//気圧計のアドレス
#define MS5611_ADDR 0x76 //CBR =HIGHの時は0x76,LOWの時は0x77
//#define MS5607_ADDR 0x76

//気圧計で使う変数
uint16_t C_[6] ={40127, 36924, 23317, 23282, 33464, 28312}; //初期値
uint32_t D1=0,D2=0;
int32_t dT,TEMP=0;
int64_t OFF,SENS;
int64_t T2,OFF2,SENS2;
int32_t P=0;
int32_t Height;

unsigned long now;                   //現在時間を入れて変換時間を計算
unsigned long lastD1Conv,lastD2Conv; //最後に変換した時間micros()
unsigned long ConvTime = 10000;      //変換時間[マイクロ秒]
boolean SWD1Conv = true, SWD2Conv = true; //D1,D2どっちを処理しているか
boolean SWD1D2 = true;               //trueでD1の処理,falseでD2の処理

void setup(){
  Wire.begin();
  Serial.begin(9600);
  //Serial.begin(115200);
  delay(100);
  readPROM();
}

void loop(){
  getD1();
  getD2();
  getPressTemp(D1,D2);
  getHeight(P);

  Serial.print(millis());Serial.print("\t");
  Serial.print(TEMP);Serial.print("\t");
  Serial.print(P);Serial.print("\t");
  Serial.println(Height);
}

/*
 * func name  : getD1,getD2
 * processing : MS5611の生データD1,D2を取得
 * param      : 
 * summary    : 後述のstartConvとreadADC使用
 *              変換の時間前だと変換、変換後なら読み出しを行う
 *              D1とD2は交互に読み出されるようにスイッチしている
 * return     : 
 */
void getD1(){
  now = micros();
  //SWD1D2==trueだとD1,falseだとD2
  //SWD1Conv==trueだと変換、falseかつ時間経過後は読み出し
  if(SWD1Conv == true && SWD1D2 == true){
    startConv(0x48); //D1のとき0x48,D2のとき0x58,OSRによって変化
    lastD1Conv = micros();
    SWD1Conv = false;
  }else if(now - lastD1Conv >= ConvTime && SWD1D2 == true){
    D1 = readADC();
    SWD1Conv = true;
    SWD1D2 = false;
  }
}

void getD2(){
  now = micros();
  if(SWD2Conv == true && SWD1D2 == false){
    startConv(0x58); //D1のとき0x48,D2のとき0x58,OSRによって変化
    lastD2Conv = micros();
    SWD2Conv = false;
  }else if(now - lastD2Conv >= ConvTime && SWD1D2 == false){
    D2 = readADC();
    SWD2Conv = true;
    SWD1D2 = true;
  }
}

/*
 * func name  : getPressTemp,getHeight
 * processing : MS5611の生データから温度TEMP、気圧P、高度Heightを計算
 * param      : ADC1,ADC2    / getD1,getD2で得られたD1,D2
 *              hPa          / getPressTempで得られたPをhPaにしたもの
 * summary    : MS5611のデータシートによる計算,と高度気圧式から線形化
 * return     : 
 */
void getPressTemp(uint32_t ADC1, uint32_t ADC2){
  dT   = (int32_t)(ADC2 - ((int32_t)C_[4] << 8));
  TEMP = 2000 + ((dT * (int64_t)C_[5]) >> 23);
  OFF  = (((int64_t)C_[1]) << 16) + (((int64_t)C_[3] * dT) >> 7);
  SENS = (((int64_t)C_[0]) << 15) + (((int64_t)C_[2] * dT) >> 8);
  P    = ((ADC1 * SENS) >> 21) - OFF >> 15;

  if (TEMP < 2000) {
    T2    = (dT * dT) >> 31;
    OFF2  = 5 * (TEMP - 2000) * (TEMP - 2000) >> 1;
    SENS2 = 5 * (TEMP - 2000) * (TEMP - 2000) >> 2;
    TEMP = TEMP - T2;
    OFF  = OFF - OFF2;
    SENS = SENS - SENS2;
  }  
}

void getHeight(int32_t hPa){
  //Height = -938.502 * hPa/100.0 + 948697; //t0=30[deg]で1000mまでの線形近似
  float t0 =30.0;float P0 = 1013.25;
  Height = 153.8*(t0+273.2)*(1-pow((hPa/100.0/P0),0.1902));
}

/*
 * func name  : startConv,readADC
 * processing : MS5611の内部ADCの変換開始関数
 *              変換後OSRの時間はアクセス不可
 *              ADCの結果を読み込む関数。returnでuint32_tが出てくる
 * param      : command    / D1,D2,OSRによってアドレスが異なる
 *                         / OSR(Over Sampling Ratio)             
 * summary    : startConv(command) -> delay(10) -> readADC()
 *              変換コマンドを送信
 *              値呼び出しコマンドを送信、受信
 * return     : 
 *              conversion    / ADCした値.D1,D2のこと
 */
void startConv(uint8_t command){
  Wire.beginTransmission(MS5611_ADDR);
  Wire.write(command);
  Wire.endTransmission();
}

uint32_t readADC(){
  uint32_t conversion = 0;
  // start read sequence
  Wire.beginTransmission(MS5611_ADDR);
  Wire.write(0x00);
  Wire.endTransmission();

  Wire.beginTransmission(MS5611_ADDR);
  Wire.requestFrom(MS5611_ADDR, 3); //3byteリクエスト
  if(Wire.available()){
    conversion = Wire.read() * 65536 + Wire.read() * 256 + Wire.read();
  }
  return conversion;
}

/*
 * func name  : readPROM
 * processing : MS5611の工場校正値を読み込み
 * param      : 
 * summary    : C_[i]に0~5読み込む(C1~C6とは一つズレている)
 * return     : 
 */
void readPROM(){ 
  for(int i=0; i<6; i++){
    Wire.beginTransmission(MS5611_ADDR);
    Wire.write(0xA2 + i*2); //PROMの最初 データシートでは0xA0に見えるが0xA2から   
    Wire.endTransmission();

    Wire.beginTransmission(MS5611_ADDR);
    Wire.requestFrom(MS5611_ADDR,2);
    if(Wire.available() >= 2){
      C_[i] = Wire.read() * 256 + Wire.read();
    }
  }
}

 

AVRライターでArduinoのスケッチを書き込む

 

組み込みのプログラムはArduinoやってて、それ以外のマイコンを勉強するのは面倒くさくて、でも小さいマイコンを安く使いたいなぁというズボラでケチな発想で色々いじったことの自分用メモです。

Arduinoはいいんだけど大きすぎるということで、表面実装のATmega328-Pを使いたいと考えています。Arduino miniだかproだかを買えばすごく簡単だけど、値段が高いのでただのチップにAVRライターで書き込もうと考えました。

  1. AVRにブートローダだけライターで書き込んで、USB-シリアル変換基板でプログラムは書き込むという方法
  2. ライターだけでArduino IDEを使って書き込む。

 

1の欠点は変換基板買わないといけないし、外にシリアル変換基板と繋げやすい配線つくらないといけないのがめんどくさい。2には欠点はないと思ったのが大間違い、いくつかひっかかった。

 

ブートローダの書き込み

この記事の最後に書いてるやり方だとブートローダは必要ないけど、手続きがほぼ同じなのでまとめておきます。

AVRにArduinoブートローダーを焼き込み成功までの過程」「ATMEGA328P の Arduino化まとめ」「本家」とか参考にしました。ただ、チップが違ったりソフトがAVR Studioから新しいAtmel Studioになってたりするので変更部分だけまとめ。

Atmel Studio 6を起動して、「ツール」→「Device programing」。左上の「Tool Device Interface」をそれぞれ「AVRISP mkⅡ Atmega328P ISP」に設定。Apply押すと画面のようなものが出てくる。書き込み速度などはいじらず、ブートローダを書き込みました。ヒューズはチットと設定によって変えなければならないが、今回はAtmega328-Pの最初のままのものにしましした。

EXTENDED:0xFD
HIGH:0xDA
LOW:0xFF
Lock bits:0xFF

ライターを使ってArduinoIDEから書き込めない

Arduino IDEで書いたスケッチ(プログラム)はライターを使って「書込装置を使って書き込む」でOKだと思ったら、「avrdude: usbdev_open(): did not find any USB device “usb”」というエラーを吐いてしまう。Atmel Studioで使っているAVR ISP mk2のドライバとArduino IDEで使っているドライバが違く、しかも共存できないのが原因でした。しかも自分の環境だとArduino IDEの方のドライバを認識してくれないというトラブルがあって、方針変更しました。参考:「AVRISP mkII とAVR StudioとArduinoIDE

Arduino IDEでスケッチを書き、書き込み用のファイルであるHEXファイルを出力させてAVRライターを使ってAtmel Studioで書き込む。

HEXファイルの出力とライターで書き込み

Arduino IDEからHEXファイルを作るためには以下を参考にさせてもらった。

Arduinoのスケッチを買ってきたマイコンに書き込む

Arduino1.0だとC:\\[User]\AppData\Roaming\Arduino\preferences.txtに設定ファイルがあるのでそのtxtファイルに

preproc.save_build_files = true
build.path = build

と追記した。変更したら、Arduino.exeがあるフォルダにbuildフォルダを作る。フォルダ作り忘れるとIDEでエラーが出る。

ここまでくれば簡単で、Ardino IDEでターゲットとなるマイコンボードの種類と書込装置の設定を確認して、コンパイル(「検証」ボタン)するとArduino.exeの中のbuildフォルダに沢山のファイルができる。この[プロジェクト名].cpp.hexファイルをブートローダを書き込んだのと同様に「ツール」→「Device Programming」→「Memories」の中のFlashに書き込むHEXファイルを参照して「Program」ボタンを押す。

これで無事動きました。

先にブートローダのことを書きましたが、この方法だとブートローダは必要無いです。色々と遠回りをしてるような気がして滅入りぎみ・・・

MPU-6050基板作ってみた(後半)リフローしてみた

前半からの続きです。

作った基板のセンサのハンダをつける足は外にでてない恥ずかしがり屋さんばかりです。特に地磁気センサや気圧計は基板につけると足が全く見えない真性の引きこもりです。このハンダ付けについてのことです。

QFNパッケージなどのハンダ付けはホットエアーを使えばできたのと、Fenrirさんがやってる方法もあるみたいです。しかし、手先の器用さが関係なく誰でも作れるようになるといいなと思ってリフローを試してみました。

参考にしたのはスイッチサイエンスのご自宅リフローキットのページです。

準備

大学にいると環境が良く、以下のものが使えました。スイッチサイエンスの例ではクラフトロボというカッティングマシーンではんだのマスク(ステンシル)を作っています。自分はEagleで基板設計したものを直接読み込めるメリットを考えて基板切削機を使いました。

  • ステンシル作り:基板切削機(LPKF社製)
  • ヒーター:ホットプレート(加熱実験用)
  • ステンシル1:OHPシート(厚さ100μm)
  • ステンシル2:レーザープリンター専用紙(サンワのつやなしマット紙厚手0.174mm)
  • クリームはんだ:鉛ありのもの(鉛フリーの方が健康的に使えそうだったと反省)
  • 道具類:ピンセット、スキージ(使用済みクオカード)、基板固定用基板、両面テープ、薄刃カッター

最初に試したOHPシートはちょうどいい厚み(100μm)で硬さも良さそうで、紙みたいに濡れないので使ってみました。しかしこれが上手くいきませんでした。

OHPシートの失敗

OHPシートを切削機で削るとバリが出るのではんだを塗るときに浮いてしまい、境界がきちっとでませんでした。目で見えるバリは取ったつもりでも、端面が曲がっているようなバリは取りきれませんでした。

写真は最初にOHPシートでカットしてプリヒートまで行った一番ヒドイときのものです。基板とステンシルが離れているためにクリームはんだが広がって細かい部分が全部潰れてしまっています。あと、プリヒートすると少し粘度が下がってはんだが流れていくので写真のような状態になりました。

このまま部品を付けずにリフローすると多くがブリッジしてしまいました。

レーザープリンター専用紙

そこでスイッチサイエンスのページの通りにポリプロピレン合成紙というのを使ってみようと思いました。同じ物かわからなかったのですが、似ていると思いレーザープリンター専用の紙(生協で売っていたサンワのつやなしマット紙厚手0.174mm)を使いました。

基板切削機のユニバーサルカッターは刃が円錐状になっているので表面と裏面でステンシルの大きさが違うので広い方が基板につくようにした方が良さそうでした。

以前作った基板用のステンシルはこんなです。薄刃カッターで切り残りなどアヤシイ部分を手直ししています。

やってみて

スイッチサイエンスのページにほとんど書いてるようなことですが、ポイントだなと思った点は以下です。

  • Eagle上のCAM ProcessorでtCreamを表面反対にして(Mirrorをチェック)ガーバーデータ(GERBER_RS274X)を出力する
  • そのままだとtCREAMを残して切削してしまうので、カットオフを利用して読み込んだガーバーデータを切り抜く形にする
  • 基板をしっかり固定する
  • ステンシルを浮かせない(浮かないように周りの押さえの基板よりハンダ塗布の基板の下に紙を挟んで高くした)
  • スキージはカードが薄くて良かった
  • スキージで細かい部分にしっかりクリームはんだを入れ込む
  • スキージを立ててしっかりこそぎ落とす
  • リフローの温度管理を時間を守ってしっかり
  • リフローしたらルーペで検査

全部の端子がうまくいくわけではないので手ハンダである程度修正を行なっています。ルーペは大事です。

ステンシルを基板に貼ったところと、出来た基板はこんなです。

参考

スイッチサイエンスさんが作ったサイトと動画が参考になります。

http://trac.switch-science.com/wiki/HomeReflowKit

 

リフローをせずにホットエアーでハンダ付けようと思うと以下の動画が参考になるみたいです。