どどーんはじめました。~その3~

今回のマルチコプターでS.BUSを初めて使ったので信号をArduinoで読み出してみました。
S.BUSとは何かという詳しい説明はコチラ→https://ja.wikipedia.org/wiki/S.BUS
要はラジコン受信機から昔ながらのサーボ信号を出すのではなくシリアル通信にする事で全チャンネルを1本の信号線で制御するという物です。

飛行機の場合はサーボの位置が分散しているので結局それぞれに配線する必要があり、あまりメリットを感じませんでした。しかしマルチコプターでは受信機の信号は全てフライトコントローラ基板に接続するのでこれが一本で済むのは大きなメリットになります。

S.BUS信号はシリアル通信ですが、UARTでよく使う仕様とは微妙に違うところがあり面倒になっています。例えば次のところ・・・

  • ボーレートが100Kbps。
    なぜか115.2Kbpsではなく100Kbpsです。妙なボーレートですがArduinoではSerialBegin()のとき100000と指定する事で対応できます。
  • 信号極性が逆転。
    Arduinoに入れる信号はインバータで反転してやる必要があります(もしかするとArduino側に反転機能があるのかもしれませんが見つけられませんでした)。

あと受信後のデータが11bit区切りなので並べ替えがややこしいです。

S.BUSプロトコルに詳細はこちらを参考にしました。→https://os.mbed.com/users/Digixx/notebook/futaba-s-bus-controlled-by-mbed/http://anarchy.hatenablog.com/entry/2014/12/07/181853

そして最低限の部分をスケッチに書きます。

int count;
long interval;
void setup() {
 Serial.begin(115200); // Terminal
 Serial1.begin(100000,SERIAL_8E2); // S-BUS
 count=0;
}

void loop() {
 int data[26];
 int val[19];
 int i;
 if (Serial1.available() > 0) {
 data[count]=Serial1.read();
 interval=millis();
 count++;
 }
 if ((interval+4 < millis()) && (0 < count) ) {
 count=0;

 val[0] =((data[1] & 0xff)<<0) + ((data[2] & 0x07)<<8);
 val[1] =((data[2] & 0xf8)>>3) + ((data[3] & 0x3f)<<5);
 val[2] =((data[3] & 0xc0)>>6) + ((data[4] & 0xff)<<2) + ((data[5] & 0x01)<<10);
 val[3] =((data[5] & 0xfe)>>1) + ((data[6] & 0x0f)<<7);
 val[4] =((data[6] & 0x0f)>>4) + ((data[7] & 0x7f)<<4);
 val[5] =((data[7] & 0x80)>>7) + ((data[8] & 0xff)<<1) + ((data[9] & 0x03) <<9);
 val[6] =((data[9] & 0x7c)>>2) + ((data[10] & 0x1f)<<6);
 val[7] =((data[10] & 0xe0)>>5) + ((data[11] & 0xff)<<3);

 val[8] =((data[12] & 0xff)<<0) + ((data[13] & 0x07)<<8);
 val[9] =((data[13] & 0xf8)>>3) + ((data[14] & 0x3f)<<5);
 val[10]=((data[14] & 0xc0)>>6) + ((data[15] & 0xff)<<2) + ((data[16] & 0x01)<<10);
 val[11]=((data[16] & 0xfe)>>1) + ((data[17] & 0x0f)<<7);
 val[12]=((data[17] & 0x0f)>>4) + ((data[18] & 0x7f)<<4);
 val[13]=((data[18] & 0x80)>>7) + ((data[19] & 0xff)<<1) + ((data[20] & 0x03) <<9);
 val[14]=((data[20] & 0x7c)>>2) + ((data[21] & 0x1f)<<6);
 val[15]=((data[21] & 0xe0)>>5) + ((data[22] & 0xff)<<3);
 val[16] = (data[23] & 0x1) ? 0x7ff : 0 ;
 val[17] = (data[23] & 0x2) ? 0x7ff : 0 ;
 val[18] = (data[23] & 0x8) ? 0x7ff : 0 ; // Failsafe

 for (i=0 ; i<19; i++ ) {
 Serial.print(val[i],DEC);
 Serial.print(F(" "));
 }
 Serial.print(F("\n"));
 }
}

S.BUSから取り込んだデータをUSB経由でシリアルモニタに表示したいので、シリアルポートが複数あるArduino MEGA2560で動かしてみます。

S.BUSモニタ

Arduino MEGA2560でS.BUSをモニター。
ブレッドボード上のICは信号極性反転のための74HC00。

 

こんな感じでデータが出てきました。
送信機が6CHなので7CH以降が正しいかどうかは確かめられていません。また19番目のデータはFailsafeが働いたときに1になるはずですが、これも確かめていません。

S.BUS monitor

モニター中。

各データが11bitt幅なので0~2047が表せるはずで、どうやらニュートラルが1024の様です。
ところでCleanflightにも受信データを表示する機能があります。しかし今回のモニターとCleanflightの値が一致しません。そこで何ポイントか対応を取ってみました。

 SBUSモニタ Cleanflight
       102         943
       697        1315
      1024        1520 ←ニュートラル
      1435        1776
      1681        1930

グラフにすると・・・

SBUS-CleanFlight

SBUSとCleanFlightの読値対応

恐らくCleanflightの表示値は昔ながらのPWMサーボ信号のパルス幅に換算した値をμS単位で表示しているのだと思います。例えばニュートラルはS.BUSの生データは1024ですがPWMだと1520μSといった感じ。
ということでS.BUSの生の値にざっと0.625掛けて879.5を足すとほぼCleanFlightの値になる様です。

フライトシムのモーションシミュレータ化~5~

モーションシミュレータの座席にラダーペダルを固定するため、金具を切り貼りしたいのですが、先週の雨に続き今週末も台風がやってきて降ったり止んだりしているので外での作業が出来ません。
そこで近所のホームセンターハンズマンにある工作室で金具のカットと穴あけをしてきました(工作室での写真は撮り忘れました)。
切り終えたのがこれ。

Mostionsim6

座席に取付ける金具(切ったあと)。
3mm厚で幅40mm、各辺270mmのL型金具(1本170円)。
元々は建築用みたいです。

現状の座席にも同様の金具をフレームとして使っており、これに溶接する予定ですがハンズマンの工作室でも溶接はできないので晴れたら庭でやろうと思います。が、雨が止んだかなーと思って準備を始めるとまたポツポツと降ってきます。

てるてる坊主

 

晴れるのを待ちながら制御基板の続きを作る事にします。先日故障した基板切削CNCも調子よくなっており切削完了。

MotionSim6-2

切削を終えた基板の両面テープをスクレーパーで剥がします。

部品を実装しました。(一か所回路図段階でミスっておりパターンを修正しましたがこちらの面からだと見えないのでナイショ)

MostionSim6-3

実装も完了。

これくらいの配線量だとユニバーサル基板の方が手っ取り早いかもしれません。でもそこは趣味の世界です。 またArduino標準のピンヘッダ配置はユニバーサル基板がピッタリ納まる様になっていないという問題もあります。

基板を作った後で気づいたのですが、手元の古いArduinoUNOには無い端子を使う配線になっていました。I2C通信で使うSDA,SCL端子は現在のUNOでは端子が追加されて2か所にありますが古いUNOには1か所しかありません。

MotionSim6-4

ArduinoUNOのピンヘッダ新旧比較
(左の新しい方はバッタ物ですが・・・)
左下のAD4,AD5端子がSDA,SCLと兼ねており昔からある端子です。これに対し今のUNOでは右上にも同じ信号がSDA、SCLとして追加されています

仕方ないので新しい方(バッタ物)を使う事にします。

とかやっている間にAliExpressに何となく注文していた基板が届きました。
1枚108円で送料無料です。こんなのを使うのが一番簡単でした(いまさら今回のには使いませんが)。

MotionSim6-5

Arduinoシールド用ユニバーサル基板

 

何はともあれ基板が出来たのでブレッドボードを取り外して交換します。
だいぶスッキリしました。
基板上のトグルスイッチはマニュアルとオートの切替です。オート側にするとPCから仮想COMポート経由で制御でき、マニュアルにしておくと基板上の4つのタクトスイッチで動作させる事が出来ます。

MotionSim6-6

ブレッドボードから基板に変更してスッキリした図

そうこうしている内に雨が止んだ様です。日没まであまり時間がありませんが少しでも溶接作業を進めます。
といっても2本を接合しただけで日が暮れました。座席のフレームとの接合は後日行います。

MostionSim6-7

2本を接合。

少しずつしか進みませんが続けていきます。

フライトシムのモーションシミュレータ化~4~

前回FlightSimulatorXからデータを取出して座席の傾きを計算しArduinoに送るところまで来ました。引き続きArduino側でのスケッチを書いていきます。

PCからArduinoに送るデータフォーマット

PCからArduinoへはシンプルに下のフォーマットでデータを送ります。

ピッチ,バンク\n

第一フィールドが座席のピッチ、第二フィールドがバンク角で、それぞれ’度’単位の角度を10倍した整数で表します。10倍しているのは小数以下一桁までを整数で表し、少しでもArduino側の計算負荷を減らす目的です。

Arduino内での処理

Arduinoのスケッチではシリアルポートを定期的にチェックし、1行分のデータが来たらピッチとバンク角を取出します。そしてこの値を元にリニアアクチュエータの目標とする長さを左右それぞれ算出します。

また加速度センサーの値も定期的にチェックします。加速度センサーは座席裏側に取付けてあるので座席の傾きを示しており、この値から現在のリニアアクチュエータの長さを推定します。

あとはモータードライバーに対し、目標長と現在長の差が無くなる方向に動かす信号を送ればアクチュエータが動作して座席が目標角度になるという算段です。

実際にはアクチュエータが停止状態から動き出す時はPWMで徐々に加速し、目標に近づくと徐々に減速する事でなるべくスムーズな動作を目指しています。

なお当初、加速度センサーは座席の背板付近に取付けていました。しかしこれでは重力加速度による傾き検出以外に本当の加減速も検出してしまいます(軸から遠いので特に上下には大きく動く)。今回は傾きの情報だけ欲しいのでなるべく軸の近い場所に移動しました。

動かしてみる。

まだモニターもペダルもコントローラーも取り付けていませんが、とりあえず動作させてみます。
PC側でFSXを起動し、DOS窓から先日作ったデータ抽出プログラムを起動し、リダイレクトで仮想COMポートに送ります。

動画で・・・

最低限のところが動いた感じですが、なかなか楽しいです。
ペダルやコントローラを取付けていきます。

フライトシムのモーションシミュレータ化~3~

引き続きソフトを作っています。

SimConnectから得られる値について

モーションシミュレータではシミュレータ世界で体が受けるであろうGの方向を実世界の重力の方向に合わせる様に制御しようと思います。例えば離陸のために加速する時は後ろ向きにGが掛かるので座席を上向きに傾ける事で体にそれっぽい力が加わります。しかし以前の投稿で体にかかるGの方向がSimConnectから上手く取れない話を書きました。

SimConnectから得られる変数に「ACCELERATION BODY X(同様にY,Z)」と「ACCELERATION WORLD X(同様にY,Z)」という変数があります。
ドキュメントに詳しい説明が見当たりませんが、名前からするとこれらが体にかかる加速度およびワールド座標での加速度かと思います。しかしこれらの変数を表示させても妙に小さな値ですし思った様な変化をしていません。

下の4つのグラフは出来るだけ水平を保って右旋回を続けた時の変化です。
一番上のグラフは機体のピッチ、ロール、ヘディングを表します。単位はラジアンでヘディングの0(又は2π)は北を示しており、ノコギリ状のグラフになっているのは右方向に2回転した事を示します。

2番目のグラフは各方向への速度(単位はFeet/s)を示します。東西がvX、南北がvZなのでこの二つが90度位相がずれたサインカーブをほぼ描いており回転している事が判ります。

そして3番目のグラフが加速度を示すと思われる変数「ACCELERATION WORLD X(及びY,Z)」の値ですが、何を示しているのかよく分かりません。

そこで4番目のグラフに速度から算出した加速度をプロットしてみました。横軸が1秒ステップなので2番目のグラフの値を元に、それぞれ一つ前からの差を計算すればFeet/S2(フィート/毎秒毎秒)になるはずです。これだと最大120feet/S2で速度を90度ずらしたそれっぽい波形になっています。

・・・という事で速度の変化から計算した加速度を用いる事にします。
なお、この加速度に重力は含まれていないのでY軸方向に32.174feet/S2(=1G)足した上で機体座標に変換して座席の姿勢を決める事にします。

SimConnectの座標

SimConnectが出す値を調べた結果、各座標は下の様に表しているみたいです(座標変換するとき何度もこんがらがるので覚書き)。

MotionSim4-2

SimConnectの座標

以上で求めた座席の傾きをUSBのCOMポートに書き出し、後はArduinoでの処理となります。

フライトシムのモーションシミュレータ化~2~

フライトシミュレータのモーションシミュレータ化、まだくじけずに続けています。

アクチュエータ連結部のガタ減らし

リニアアクチュエータの連結部分の上側が特にガタが大きいので対策しました。この部分もキャスターの車輪を外したものを流用していて、元々の車輪の軸がΦ8でした。しかしリニアアクチュエータの取り付け穴はΦ6です。アクチュエータの穴を広げるか細い軸を用いる必要がありますが穴を広げると強度が落ちそうなので細軸を採用し、M6の半ねじボルト(のねじを切っていない部分)で連結しています。
Φ8の穴にΦ6の軸なので遊びが多くてガタつきます。何かいい方法はないかと物色していたらモノタロウでこんなものを発見。バイクのパーツを取付ける部品らしいです。

MositonSim3-1

キタコ ツバ付カラー

内径がΦ6.2、外形がΦ8.2。これを軸受けに挟み込んでみます。

MotionSim3-2

こんな感じ。外形Φ8.2はちょっと固いけど押し込めば入りました。

これで少しガタが減りました。まぁそもそもキャスター自体のガタもあり、こちらは改善できないんですが。

モータードライバー

そしてラダーペダルやフライトヨーク、PCモニターの取付け方法も考えねばなりませんが、これらは置いといて電気的なところを進めます。

モータードライバーは瞬間最大で4.5A流せるTB6643KQを用います。リニアアクチュエータは定格4Aという事になっていますが、実測すると(私が座った状態で)1Aちょっとしか流れてなかったので余裕だと思います。

MotionSim3-3

TB6643KQ。秋月電子で購入。

これを用いてドライバー基板を作っていきます。

MotionSim3-4

基板を削って・・・

MotionSim3-5

実装しました。

MotionSim3-6

放熱を兼ねて金属部分にねじ止めします。

フィードバック系

今回使用するリニアアクチュエータはDCモータに電流を流すだけの制御です。端まで行くとストップする仕組みは内蔵していますが、RCサーボやステッピングモータの様にオープンループで制御する訳にはいかず、何らかの方法で動作量を検出してフィードバックしなければなりません。 大体こういう時はボリューム(可変抵抗)を使いますが、今回の構造でボリュームを取付けるのは結構面倒に思えます。そこでこれを使ってみることにしました。

MotionSim-6

GY-521(6軸ジャイロMPU6050搭載)

だいぶ前にAliExpressで140円くらいで買ったジャイロ3軸+加速度3軸のセンサーです。座席に貼付けて加速度から傾きを検出しようという魂胆です(ジャイロは使いません)。

このセンサー、マイコンとはI2Cで接続します。センサー自体は3.3V系なので電源には降圧レギュレータが入っていて5V電源を接続できますが信号は3.3Vのままです。マイコンにはArduinoを使おうと考えていますがUNOだと5V系です。ProMiniなら3.3V版を保有していますが今回の用途はPCと常に通信するためFT232RL等のUSBシリアル変換回路を外付けする必要があり面倒です。

ところでArduinoのI2Cの使い方を調べていると5V系Arduinoを3.3VのI2Cデバイスに接続する場合はレベル変換回路を入れろとあちこちに書いてあります。でも本当にレベル変換が必要なのでしょうか?
I2Cはバス全体をプルアップしておき、各デバイスはオープンドレインでLに落とすことにより通信を行います。ならば3.3Vでプルアップしておけば少なくともデバイスを壊す事はない様に思えます。問題は5V系Arduinoが3.3VをHと認識してくれるかどうかですが、ATmea328Pのマニュアルを見ると入力のVIHは0.6VCCとなってるのでVCC=5Vの場合は3V以上ならHと認識してくれる筈です。H=3.3Vで通信すると0.3Vしか余裕が無いのは気持ち悪いですが実力はもう少し余裕があるでしょうし、実用上はイケるんではないでしょうか(今のところイケてます)。
実際の回路ではGY-521モジュール内で4.7KΩを経由して3.3V電源に接続されています。一方ArduinoUNOもデフォルトでは20K~60KΩで5V電源に接続されている様です。Arduinoのプルアップは切り離しもできる様ですが仮にそのまま動作させた場合、Arduino側を最悪値の20KΩで考えると・・・「3.3V—4.7KΩ—バス—20KΩ—5V」という接続にないります。この時バスには3.7Vが加わる事になりますがMPU6050の入力最大定格はVDD+0.5V(=3.8V)となっており、これもギリギリですが規格内です(それに実際に定格を大きく超えようとするとデバイス内の保護ダイオードが順方向になって電流が流れるので20Kのプルアップではそれ以上電圧を上げる事ができなくなり助かるはずという目論みもあります)。
・・・という事で5V系のUNOを使ってレベル変換無しでやってみようと思います(真似してトラブっても責任負えませんけどね)。

取付け

という事でArduino UNOとセンサーを取り付けたところです。まだブレッドボードなので、うまく行く様ならしっかりした基板に変更しようと思います。

MotionSim-8

Arduiono他一式、仮止めの図。

MotionSim-9

念のための非常停止スイッチ。どこに固定しましょう?

簡単なプログラムでモーターの制御とセンサーの読み出しが確認できたのであとは実際にPCから指定した角度に座席が動くプログラムを作っていきます。

ArduinoでPICマイコンに書込む~OpenStickLite(PIC18F14K50)編~

ジョイスティック自作用ツールキットOpenStickは元々PIC18F2550(又は2553)を採用していました。このマイコンは28pinで、DIPパッケージだと結構大きい部類になります。
そこで先日PIC18F14K50を使用したOpenStickLiteをβリリースしました。こちらは20pinなので入力ピン数は少なくなりますが、これでも大抵の用途には事足りると思っています。
価格もこちらの方が大幅に安くてすみます。

OpenStickもOpenStickLiteもUSBからプログラムを書き込む為のブートローダを使用しています。 電源投入時(またはリセット時)の条件設定によりブートローダが書き込みモードで立ち上がります。この状態で書き込みツール「MybootOS」を使うとUSBポート経由でプログラムを書き込める訳です。

この種の話題でいつも問題になるのがブートローダ自体はどうやって書き込むかという事です。 ブートローダでブートローダを書き込む事はできないので、通常はそのマイコン専用のライター(PICKit3など)を使用します。
しかし皆がライターを持っているわけではありません。 そこでArduinoを使ってPIC18F2550にブートローダを書き込む実験を過去に行い、問題なく書きこむ事ができました(下記を参照ください)。

今回はArduinoからPIC18F14K50にブートローダを書き込んでみます。これが可能になればOpenStickLiteを安価に使用できます。

まずここの資料でPIC18F14K50の書き込み仕様を調べます。 大体はPIC18F2550と同じですが微妙に違うところがあります。一番問題なのはPGD,PGC端子が耐圧3.3Vという記述です。 PIC18F2550の時はArduinoUNOを用いて5Vで駆動していました。特にPGDは双方向なのでレベル変換は面倒です。 よって今回は3.3V版ArduionoProMiniを用いることにします。
またスケッチには若干のWAITタイムの変更と書き込みイネーブルONのコードを追加しました。
スケッチ→PICWrite18F14K50.ino

書込み電圧は006Pの積層乾電池(9Vの四角いやつ)を用いる事にします。先の資料によると書込み電圧の上限は9Vという事なので、新品の電池だと定格を超える可能性がありダイオード一本で電圧を下げました(使い古した電池だとそのまま繋いで大丈夫です)。

回路

ArduinoProMiniはUSBシリアル変換回路を内蔵していないので、外部にFT232RLの変換回路を接続し、Arduino/PIC18F14K50に供給する3.3V電源もFT232RL内臓のレギュレータから取っています。
PIC18F14K50の電源-GND間のコンデンサは当初0.47μFを使いましたが、PIC18F14K50に電源を投入した瞬間にArduinoProMiniから反応が無くなる事がありました。恐らくFT232RLの3.3V出力が瞬間的にダウンする為と思われ0.22μF(実際には0.1μ×2本)に変更しました。 

PIC14K50WriteByArduinoProMiniSch

PIC18F14K50へArduinoProMiniで書き込む回路図。

参考までにUSBシリアル変換は次の回路です(最近の電子工作には何かと登場しますね。一家に一台FT232RLです)。
FT232RLは3.3Vのレギュレータを内蔵しており、これをVCCIO端子に入力する事で3.3Vレベルで使用できます。この回路ではスイッチを設けて5Vと3.3Vを切り替える様にしています。
但しレギュレータから取れるのは50mAまでなのであまり大きくはありません。

USBSerial

FT232RLによるUSBシリアルインターフェース

PIC18F14K50WriteByArduinoProMini

Arduino ProMiniで書き込み中。
横のFRISKケースはUSBシリアル変換です。

書込み手順

PIC18F2550の時に書いた内容とほぼ同じです。
※前回同様TeraTermの「貼り付けの行間遅延設定」を50mS程度にしておく必要があります(書込み時間待ちの為です)。

<PIC18F14K50にブートローダを書込む手順>

  1. まずPIC18F14K50の3.3V電源と9V電池は切り離しておく。
  2. Arduino IDEを立ち上げこのスケッチを書込む。
  3. TeraTermをシリアルモードにしてArduinoに接続する。
    シリアル設定:9600bps,8bit,パリティ無し,stop=1,フロー制御=none
    改行コードは送信・受信共にCRにする。
    また、「設定」→「その他設定」メニューの「コピーと貼り付け」タグを選び、「貼り付けの行間遅延」を50mS程度にしておく。
  4. 接続するとTeraTerm上に以下のメニューが表示される。
    r  <start address> <count>: read from PIC
    e : all erase
    w : write to PIC
    v : verify
  5. ここでPIC18F14K50に3.3V電源→9V電池の順で供給する。
  6. 必要に応じ’r’コマンドで現在書かれている内容を確認する。たとえば・・・
    r 0 0×100<CR>
    と入力すると、FLASHメモリの0番地から0FF番地の内容を表示する。
    消去済ならCODEエリア全ての内容がFFになっているはずである。
    (消去チェック機能はないので、どちらにしても次の消去コマンドを実行しておくべきです)
  7. 消去済みでない場合はeコマンドで消去する。
    ALL Erase <y/n>?と効いてくるのでyを入力する。
    このコマンドはチップ全体を消去する(一瞬で終わります)。
  8. ‘w’コマンドで書込む。w <cr>を入力すると’Send me intelhex text’と表示されるので、ここでIntelHEXファイルを送る。この際、上に書いた理由でコピペで貼り付ける方法で送る。 たとえばブートローダのHEXファイルである’Bootloader18F14K50.hex’をメモ帳等で開いて全域をコピーした後、Teratermの画面上に貼り付ける。
    (前に書いた様に「ファイル」→「ファイル転送」メニューからの送信だと取りこぼしが発生する)
  9. エラーなく書き込みが完了したら’v’コマンドでベリファイを行う。方法は’w’コマンドと同じで、v<cr>入力後IntelHEXテキストを貼付けるとFlashメモリを読出して比較する。  エラーが出なければ正常に書き込めた筈である。
  10. 9V電池→3.3V電源の順で切り離し、TeraTermの接続を切りArduinoのUSBケーブルを抜く。

やっぱりArduinoUNOでやってみる。

と、ここまでで書き込みが出来たのですが、やっぱり3.3V版Arduinoは少数派で手元にない場合もあると思われ、メジャーなArduino UNO等でも書けると何かと便利です。 この場合5Vで動作するArduinoと3.3Vで動作するPIC18F14K50の間をどう繋ぐかが問題です。ArduinoからPIC18F14K50へ一方的に入力するPGC信号は単に抵抗分割で問題ありません。一方PGD信号は双方向なのでまじめにレベル変換器を入れると結構面倒な事になります。しかし3.3VのHレベルはArduinoはHと認識してくれる筈と期待しPGDも単純抵抗分割で試してみました。

PIC14K50WriteByUNOsch

ArduinoUNOでPIC18F14K50に書き込んでみる回路図。

実験風景・・・

ArduinoUNOで書き込み

ArduinoUNOで書き込み。UNOは直接USBケーブルを繋げるのですっきりします。

特に問題なく書けました。これが手っ取り早いです。
気をよくしてFritzingでも回路を書いてみました。

PIC14K50WriteByUNO_ブレッドボード

Fritzingでも描いてみた。

 

各ファイル 

※PIC18F14K50用ブートローダは上記バイナリセットかソースのどちらにも収録しています。※言うまでもないとは思いますが、同様の実験をされて万一デバイスが壊れたりしても責任は持てませんので、そこんとこはよろしくお願いいたします。

 

ヨットレースのスタート練習用タイマー

ヨットレースのスタート練習用タイマーを作ってみました。
ヨットのレースはまずスタート5分前に旗が上がり、それから色々と手順を踏んで5分後にスタートとなります。この5分の間に選手は色々な準備を行います。
たとえば陸上の競技と違ってスタートラインに線を引く訳にはいかないので海上のブイとコミッティボートの間の直線がスタートラインとなるのですが、自分がはみ出しているかどうかが判りにくいので一旦ライン上に船を止め、ブイの向こうに見える景色を確認しておきます。そうするとスタートの瞬間にブイと向こうの景色を見る事で自分がラインを超えているかいないかが一目でわかるわけです。
また風の方向や海面の状況をチェックし、どのあたりを走っていくと有利かを予想します。 さらにスタート直前になるとラインの手前に多くの船が集まり混雑する中で有利と思われる場所に船を停止させる必要があります(
船は同じ場所に留まるのが難しいのです)。

RaceStart

スタート前


で、日ごろからスタート練習をやる訳です。
その際、ゴムボート上の先生や関係者が時計を睨みながら5分前とか1分前とか叫んだり、スタートの瞬間にホイッスルを鳴らしたりします。しかし5分間ずっと時計を睨んでいるのは結構苦痛ですし、ホイッスルを鳴らし忘れたりしもします。

そこでこのタイマーです。
スタートボタンを押すと「スタート5分前の5秒前」からカウントダウンし、1秒毎に発信音が鳴ります。そして5分前には長音1回+単音5回で5分前である事を知らせます。
その後、10秒置きに単音1回。また4分前には 長音1回+単音4回、3分前には長音1回+単音3回といった風にカウントダウンしていき、スタート10秒前からは1秒毎に発信音が鳴ります。
また5分スタートの他、4分、3分でのスタート練習にも切り替えられます。

製作

今回はArduinoを使用しました。
プログラムはArduinoUNO上でデバッグし、生のATmega328Pに書き込みます。

Arduionoブートローダ書き込み。

まずFT232RLでArduinoブートローダを書き込み、その後ArduinoUNOに挿してスケッチをダウンロードします。

 

そしてプリント基板を切削。

ヨットスタート練習タイマー基板

切削中。

 

ケースはポリプロピレンのタッパーです。
初めてレーザーでポリプロピレンを切ったので加減が分からず、スピーカー側は十分切れていなかったため後から手で切り抜く羽目に。

ヨット練習タイマー4

十分に切れていませんでした。
結局手作業で切り抜き中。

ヨット練習タイマー5

こちら側はパワーを上げたのでバッチリ切れています。というか少し強すぎたかも。

 

液晶は以前カホパーツセンターのジャンク市で買ったものです(既に3年も経っていました)。
液晶の前面にはクリアーのプラバンを張り、押しボタンの前には厚手のビニールを張って防水しました。
スピーカーを鳴らすアンプには秋月電子で購入したPAM8012モジュールを使いました。D級なので2W出せるのに小さいです。

ヨットスタート練習タイマー

モバイルバッテリーで電源供給。

ヨット練習タイマー2

こちら側はスピーカー。海上でも聞こえる様に3Wクラスです(アンプからは1Wしか入っていませんが)。
ケースとの間にビニールを貼って防水処理しました。

 

回路図

ヨットレース練習用タイマー回路図

クリックすると拡大します。

Arduinoスケッチ

 

まだ実際にスタート練習で使っていません。今度試してみます。

ArduinoでPICマイコンに書込む~その3~

先日の「ArduinoでPICマイコンに書込む」ではMCLR端子の電源として12Vのスイッチング電源を用いたが、今回は9V電池(006Pという四角いやつ)で試してみた。
PIC18F2550の規格上は「VDD+4V~12.5V」の範囲となっており、VDDが5VならばMCLRには9Vの印加で書き込めるはずだ。

やってみたところ特に問題なく消去/書込み/ベリファイができた。
これが一番手軽な書込み方法かもしれない。

PIC write with Arduino AND 006p BATTERY

Arduinoと9V電池を使用したPICマイコンへの書込み

 

ArduinoでPICマイコンに書込む~その2~

先日ArduinoをPICライター代わりにした事を書いた。その際、書込みモードに設定するために外部電源から12Vを印加したが、今回は5Vのみで書き込んでみた。

まず5V書込み(Low Voltage ICSP)を実行するにはコンフィグビットのLVPを’1′にセットしておく必要がある。 PIC18F2550の工場出荷時設定はLVP=’1′なので問題ないが、ブートローダを書込むと’0′に変更してしまうので一旦ブートローダを書込むと5Vモードでは変更できなくなってしまう(LVPビットは12Vモードでなければ変更できないのだ)。

また、LVP=’1′の場合、通常動作時にRB5端子(PRMと兼用)をGPIOとして使用できなくなる。この端子はLにしておかなければ正常動作しないので、OpenStickとして動作させる場合IN16が使用不可となる(デジタル入力端子が一つ減る)。

これらの制約はあるが、12V印加が不要なのは便利かもしれない。

実験開始

まず書込むべきブートローダファイルをLVP対応に変更しなければならない。 具体的には’20M-18f2550.hex’の最後から8行目あたりにある次の記述「:010006008178」を「:010006008574」に変更し、’20M-18f2550LVP.hex’というファイル名で保存した。

次に回路を変更する。12V印加回路は取り除き、Arduinoの10番ピンをPGM、11番ピンをMCLRに接続した。

PICwriteLVPsch

5V書込み(LVP-ICSP)用回路図

Arduinoのスケッチを5Vモード仕様に変更した。

あとは12Vを印加しない事以外、前回と同じ手順で(先程つくったLVP版)ブートローダの書き込みを行なった。

なお先程書いた通りPIC18F2550をLVP=’1′状態で使用する場合はPGM端子(RB5)をLに接続する必要があるので、OpenStickの回路を変更してGNDと接続しなければならない。
あとはいつも通り、OpenStick基板上のModeスイッチを押しながらリセットする事でブートローダが起動し、MyBootOSツールでOpenStickファームウェアを0×800番地から書込み、OpenStickConfigツールで作成した定義ファイルを0×4000番地から書込むとジョイスティックコントローラとして動作した。

この方法での弱点はRB5をGPIOとして使用できなくなる事であるが、そこまでデジタル入力を使う事は少なく、むしろOpenStick基板を変更するのが面倒な事が一番問題かもしれない。
また上にも書いた通り一旦通常のブートローダを書込むとLVP=’0′(5Vモード使用不可)になり5Vモードでは消去すらできず、12Vモードでしか変更できないので注意が必要である(但しそもそも5VモードではLVPを変更できないので最初から5Vモードだけを使うなら間違って使用不可にしてしまう心配はない)。
このあたりの管理を間違うとハマるかもしれない。

・Arduinoのスケッチ(5V書込み版)
・ブートローダ(LVP=’1′版)

 

ArduinoでPICマイコンに書込む

MakerFaireOpenStickを展示していると、「Arduinoでできないの?」と聞かれる事がある。
しかしArduinoでは(Leonardo等の一部を除き)USBとは仮想シリアルで接続しており、HIDデバイスを実現しにくいのだ。 しかもPIC18F2550で製作するのと比べて値段も高い。

PICでなくてArduinoを使いたい理由のひとつとしてはPICライタが必要という点であろう。
OpenStickの場合、あらかじめPIC18F2550のFlashメモリにブートローダを書込んでおくのだが、その為にPICライタが必要になる。しかし一般的なライターであるPICKit3秋月電子でも¥4500する。
こんな自作ライターを使っていた時もありましたが最近のPCはプリンタポートが無いし・・)

昨今、PICライタよりもArduino基板の方がよっぽど浸透しているだろう。
OpenStickをArduinoに移植するのは難しいが至る所に存在するArduinoを使ってPIC18F2550にブートローダを書込む事ならできそうな気がする。という事で実験を行った。

PIC18F2XXXにプログラムを書込む方法はマイクロチップテクノロジー社のこの資料に書いてあった。 このマイコンでは書き込みモードに設定する為に12Vを印加するHigh Voltage ICSPモード(以下12Vモードと呼ぶ事にする)と、5V電源のみで済むLow Voltage ICSPモード(以下5Vモード)がある。 但し5Vモードを使うには制約があり、コンフィグ設定のLVPビットに’1′が書かれていなければならない。新品購入時、LVPビットはデフォルトで’1′なのだが、ブートローダを書込むと’0′になってしまう。 5Vモードだけだと一度書き込んだら書き換えができないという事になるので、今回は外部電源を使って12Vモードで書込む事にした。

<今回の回路図>

PIC write schematic

今回の実験に使用した回路図

MCLR端子に外部から12Vを与えている。デバイスの規格でここの電源はVDD+4V~12.5Vの範囲となっており、12V電源のままで入力可能な筈だが上限値に近いので、念のためダイオードで少し電圧を落とした。 ArduinoはUNOを用い、+5V,GNDのほかは8ピンをPGC、9ピンをPGDに接続した。PGDは双方向なので念の為3.3KΩを挿入したが、デバッグ完了後はダイオードも抵抗も直結で問題なく動作した。

PIC Writer with Arduino

ArduinoでPICライター

PC側はTeraTermでArduinoに接続し、キーボードからコマンドを入力して操作する。
プログラムの書込みおよびベリファイは’w'コマンドに続いてIntelHEXのデータをテキストとして送る。 Arduino UNOのRAMは2KBしかないので全部を蓄えてから書込む事はできず、IntelHEXデータを1行ずつ読んでは書込みを繰り返すのだが、ArduinoとPC間のシリアル通信ではフロー制御を行っていないため、一気にデータを送ると書込みが間に合わず取りこぼしが発生してしまう(この場合パリティエラーとなる)。 この対策としてTeraTermの「貼り付けの行間遅延」設定を増やしておく必要があった(こちらの環境では行間遅延が20mSだと取りこぼしが発生し、50mSだとOKだった)。 なお、この関係でTeraTermからIntelHEXデータを送る際はコピペで送る必要があり、これを「ファイル」→「ファイル転送」メニューで送ると行間遅延が加わらないらしく取りこぼしが発生した。

結果として下記の方法で書き込み/読み出しができ、更にOpenStickを使ってジョイスティックコントローラとして動作させる事ができた。

<PIC18F2550にブートローダを書込む手順>

  1. まず12V電源はOFFにしておく。
  2. Arduino IDEを立ち上げこのスケッチを書込む。
  3. TeraTermをシリアルモードにしてArduinoに接続する。
    シリアル設定:9600bps,8bit,パリティ無し,stop=1,フロー制御=none
    改行コードは送信・受信共にCRにする。
    また、「設定」→「その他設定」メニューの「コピーと貼り付け」タグを選び、「貼り付けの行間遅延」を50mS程度にしておく。
  4. 接続するとTeraTerm上に以下のメニューが表示される。
    r  <start address> <count>: read from PIC
    e : all erase
    w : write to PIC
    v : verify
  5. ここで12V電源をONにする。
  6. 必要に応じ’r'コマンドで現在書かれている内容を確認する。たとえば・・・
    r 0 0×100<CR>
    と入力すると、FLASHメモリの0番地から0FF番地の内容を表示する。
    消去済ならCODEエリア全ての内容がFFになっているはずである。
    (消去チェック機能はないので、どちらにしても次の消去コマンドを実行しておくべき)
  7. 消去済みでない場合はeコマンドで消去する。
    ALL Erase <y/n>?と効いてくるのでyを入力する。
    このコマンドはチップ全体を消去する。
  8. ‘w’コマンドで書込む。w <cr>を入力すると’Send me intelhex text’と表示されるので、ここでIntelHEXファイルを送る。この際、上に書いた理由でコピペで貼り付ける方法で送る。 たとえばブートローダのHEXファイルである’20M-18f2550.hex’をメモ帳等で開いて全域をコピーした後、Teratermの画面上に貼り付ける。
    (上に書いた様に「ファイル」→「ファイル転送」メニューからの送信だと取りこぼしが発生する)
  9. エラーなく書き込みが完了したら’v'コマンドでベリファイを行う。方法は’w'コマンドと同じで、v<cr>入力後IntelHEXテキストを貼付けるとFlashメモリを読出して比較する。  エラーが出なければ正常に書き込めた筈である。
  10. 12V電源をOFFにした後、TeraTermの接続を切りArduinoのUSBケーブルを抜く。

Arduinoのスケッチ
ブートローダ(千秋ゼミさんへのリンク)

※言うまでもないと思いますが、試される方は自己責任でお願いします。
(特に12Vを印加する端子を間違ったりすると・・・ああ)
※コマンド入力のエラーチェックはあまり詳しく行っていません。

 

http://www.hoihoido.com/rudder/index.html