2013/06/19

PWM・シリアル変換基板の作成

どうも3年のKです。

先輩のプログラムがどうしてもコンパイルできないので、設定の変更で使うためにPWM・シリアル変換基板を作成しました。

立ち上がり時にタイマー1を記録し、立ち下がり時に差分を計算し、その結果をPWM値と設定する。
一定間隔で値をシリアル信号で出力するといったものです。

パリティの計算は以前のサイトを参考に

parity = (data & 0x55) + ((data >> 1) & 0x55);
parity = (parity & 0x33) + ((parity >> 2) & 0x33);
parity = (parity & 0x0f) + ((parity >> 4) & 0x0f);
parity &= 0x01;

としてみました。 おそらくちょっとは速くなっていると思います。

XC8では256byteより大きい配列が扱えないので次のように分割しました。

switch(diff.high){
    case 0:
        g_pwm[i].value = COUNT_TO_PWM0[diff.low];
        break;
    case 1:
        g_pwm[i].value = COUNT_TO_PWM1[diff.low];
        break;
    case 2:
        g_pwm[i].value = COUNT_TO_PWM2[diff.low];
        break;
    case 3:
        g_pwm[i].value = COUNT_TO_PWM3[diff.low];
        break;
    case 4:
        g_pwm[i].value = COUNT_TO_PWM4[diff.low];
        break;
}

しかし問題はつきもの。どうもたまに変な値を取得したのか、変な挙動がします。
元のPWM信号に問題があるのか変換基板に問題があるのか。

元の出力信号の精度を上げるために
・PICのA/D変換
・PICのデジタル出力
をそれぞれ確認してみたところ、問題はありませんでした。(多少の改善はしましたが)

これは変換基板側でどうにかするしかありません。

 とりあえず変化+10以上では直接データを書き換えないで、もう一回の測定を待つようにしましたが、どうも細かい調整が出来ません。困ったなあ

2013/06/16

カメラがいい感じ

どうもKです。

秋月からカメラが届いたので早速映してみました。
中々いい画質で、操縦も楽になりそうです。
カメラの切り替え用の基板が欲しいところですね。 # 作らないと……

そういえば今日はI2Cに苦戦していましたのでそのメモでも書いておきますね。 # 低脳

* I2C動作しないメモ

SSP1IE = 0;
SSP1IF = 0;
SSP1CON2bits.SEN = 1; // スタートコンディションの発行
while(!SSP1IF); // 発行終了待ち←止まる

SSP1IFが1にならない。割り込みが起こってしまっているのでは? と思い、SSP1IFを割り込み内でクリアするようにしてもだめ。

“In Master mode, the SDAx
and SCKx pins must be configured as INPUT”
まじかよw 設定していなかったので再度設定し直すことに。

やっと次のステップに進めた。

続いてアドレスのマッチングは行われたようだが、送られてくるデータが違う。
IDを変更してIDが一致しないと動作しないことを確認した。

どうやら送られてきていたデータはIDだったようで、
IDが一致していればそのIDがそのままSSPBUFに格納される仕様だったようだ。 # 見落とし

そこでSSP1STATbits.D_nAを確認してみたらみごとに0(アドレス)が返ってきた。
1度空読みしてから再度SSP1IFをクリアすれば次の受信を待つそうだから、やってみることに。

……ずっとアドレスが送られ続ける。ボタンにチャタリング対策を施していないので、
紛らわしいため実装する。(ボタンを押したら待機するだけ)

どうやらデータの送信がうまくいっていないようだ。
> The MSSPx module generates an interrupt at
the end of the ninth clock cycle by setting the
SSPxIF bit.
初めのデータがかけていたのはスタートコンディション送信後に
SSP1IFをクリアして、その後アドレスを送信した後、何も待機せずにそのままデータを送ってしまったのが問題なようだ。

アドレスを送り終えたときにSSP1IFがセットされるため、そこまで待機する。
while(!SSP1IF);
を追加した。ついでにACKの確認も追加して、

SSP1IF = 0;
SSP1BUF = id << 1; // アドレス+W指定
while(!SSP1IF); // アドレス送信待ち

if(SSP1CON2bits.ACKSTAT){
    return; // 送信失敗
}
とした。

データの送信時も同様に、データを格納したらSSP1IFがセットされるまで待機し、それを繰り返すことに。
NO-ACKが返ってきたら再度データを送る仕様にした。

while(data < end_data){
    SSP1IF = 0;
    SSP1BUF = *data;
    while(!SSP1IF);
    if(SSP1CON2bits.ACKSTAT){
        continue; // 送信失敗
    }
    data++;
}

スレーブ側では、データの受信にアドレスかそうでないかで振り分けて判断した。
if(SSP1STATbits.D_nA){
    g_buffer[g_buffer_position++] = SSP1BUF;
}
else{
    data = SSP1BUF;
    g_buffer_position = 0;
}

ここで、空読みとして、適当なレジスタにSSP1BUFを読み込ませる処理があるが、これがないと受信されない。
なお、SSP1BUF = 0;のように適当な値を代入することでも動作が確認できたため、こちらを採用した。

また、SSP1CON3のストップコンディションの際の割り込みを有効にしていなかったため、
送信の終了判定が出来ず苦労していた。これも初期化時に有効にして、割り込み内でSSP1STATbits.Pをセンスして判定した。
結局次のようなプログラムになった。

if(SSP1STATbits.P){
    g_callback(g_buffer, g_buffer_position);
}
else{
    if(SSP1STATbits.D_nA){
        g_buffer[g_buffer_position++] = SSP1BUF;
    }
    else{
        SSP1BUF = 0;
        g_buffer_position = 0;
    }
}

ただしスレーブ受信のみに対応しており、送信の場合はR/Wフラグを確認して動作を割り振る必要がある。

スレーブが送信するプログラムはそのタイミングですでに送るデータが用意されているわけだから、
例えばマスターがデータをくれという命令を出して特定のデータを送信するといったデバイスが考えられる。

TPIP周辺回路では、TPIPから送られるシリアルデータをI2Cで各基板に送り届け、
入力が必要な基板では、必要なタイミングでデータを送るように命令し、取得する。

明日はスレーブ送信とマスタ受信を完成させる予定。
今現在としては、スレーブ送信要求が来たら予め設定した関数ポインタをコールバックし、
その内部で送信関数を使って送信するという流れを予定している。

結局次のようなヘッダファイルになりそうだ。

// マスターモード初期化
void I2C_initMasterMode(void);

// スレーブモード初期化(id)
void I2C_initSlaveMode(char id, void (*callback)(char *data, char size));

// マスターモード送信
void I2C_sendByMaster(char id, char *data, char size);

// マスターモード受信
void I2C_receiveToMaster(void);

// スレーブモード送信
void I2C_sendBySlave(char *data, char size);

// スレーブモード受信
void I2C_receiveToSlave(void);

* パケットにして送るメモ
ところでサーボの制御のためにデータをたくさん垂れ流していくわけだが、
シリアルデータを各基板に送らないといけないわけだから、そのシリアルデータには区切りが存在する。
その区切りを例えば0x7Eとする(フレームデリミタという)。

つまり、0x7E データ 0x7Eをひとかたまりのデータとして送りつける。
もしもデータ中に0x7Eがあった場合は混乱してしまうため、0x7Eを別のデータに変えて、
それが返られたことを示すエスケープオクテット0x7Dを前に挿入することにする。

0x7Eは上から3bit目を反転させて0x5Eとする。つまり、データ中の0x7Eは0x7D 0x5Eに置換される。
ところで0x7D 0x5Eが存在している場合、勝手に0x7Eに置換されてしまって困る。
そこでエスケープオクテット0x7Dもデータ中に存在している場合、
3bit目を反転させた0x5Dに置換して、その前に0x7Dを挿入することにする。
即ち0x7Dは0x7D 0x5Dに置換される。
するとデータ中には0x7Dがエスケープのためだけに存在することになる。
そして、0x7Eはフレームの開始と収量を表すためだけに存在することになる。

(例)
データ : 0x7E 0x7D 0x33 0x7D 0x7E
置換後 : 0x7D 0x5E 0x7D 0x5D 0x33 0x7D 0x5D 0x7D 0x5E

このような1フーレムのデータが来たら、それを適当に解釈して(例えば先頭がアドレス、とか)
他の基板にI2Cで転送する。もしもスレーブ側が送信を必要とする場合は、
そのような命令をフレーム内に記述して(例えばアドレスに送受信の要求を含めるとか)送り返して貰う。

あと明日こそバッテリー試験用基板も作ります;; # バイト終わるまでに出来るといいなー

とはいっても、
(1) PCからテスト要求をRS232Cで出す
(2) PICはそれを受信してテスト(サーボを上下に振り続ける)を開始する。
(3) PCから1秒おきにPICにデータ要求を出し、特定の値を取得する。
(4) PICはアナログ値を取得し、PCに送る。
(5) PCはその値がある値より小さくなったりしたときにテストを終了させる。
(6) PCは記録したデータをtext file等に出力して終了する。

まあできればグラフまで表示させればいいんですけどね。

2013/06/07

メモ

近藤のサーボのZHコネクタに使う圧着端子はオープンバレル型って言うみたいですね。
使える圧着ペンチはHOZANのP-706,P-707あたりですかね。適性のない圧着ペンチで結構無駄にしたみたいですし早めに買ったほうがいいかもしれません。

2013/06/06

深刻なドライバー不足

3年のKです。

今日はサークルの定例会で、諸担当を決めていました。
(i)主に決めたのはレスコンに提出する書類の担当です。
(ii)また、当日搬送しなければいけないのでドライバー(最初ソフトウェアのドライバーしか浮かびませんでしたが運転手ですね;)を募りました。
サークル内の人間はロボット製作にていっぱいなので先輩方にお願いのメールを送らせて頂きましたが結果はいかほど……。もう来られていないのに申し訳ないですが是非協力をお願いいたします……。
(iii)そして、新入生は工作機械を使うための講習を受けて頂きます。工作センターの職員の方々が開いて下さる毎年恒例の講習ですが、今年は去年より日程が遅いですね。
明日からと言う急な日程ですが参加のほどよろしくお願いします。4コマ終わりの4時20分に次世代工作センターに集合です。

そして機能のサーボを分解した結果、どうやらモーターがいかれている模様です。
これは買い直しかな……。

3個動かない件の実験結果は : 
・IDはそれぞれ1, 2, 6を使用した。
(1) 2個のサーボを連結させ、1つが通信の先端、もう1つは先端のサーボの2つめのコネクタに接続した。その結果、全ての組み合わせでサーボが動いた。
(2) 3個のサーボを連結させた結果、動いた。

どうやら私の送ったシリアルデータが問題だったようだ。
すかさずICSのUSBAdapterの送るデータ内容を検証。
 データに誤りなどはなさそうだ。

もう一度ブレッドボードにPICを戻して動かしてみる。
あれ、動くじゃないか。3つでも動くじゃないか。
送信間隔が短すぎると踏んでボタンで1つずつ送信するようにしてみても動くじゃないか。
 そのままのプログラム(とにかくデータを送りつけるタイプ)でも動くじゃないか。
どうやら基板に刺すと動かなくなるようだ。
 もう一度データが送れているか確認したところどうやら送れているようだ。

基板の出力ピンだけからシリアルデータを取り、電源は別のところからとっても動かない。(2つまでは動く)

どうやらシリアルデータ自体が、3つ以上サーボをつなぐと正常に出力できていない(信号電圧が足りない?)ようだ。
テスト用ブレッドボードに付いていなくて、基板に付いている信号ピンの先についていたものは……
(CMの後驚愕の事実が!!)


金赤黒茶の縞々模様が!!


受信端子に付けるはずの抵抗を謝って送信端子に付けていたみたいです。3個になって、出力インピーダンスの影響が出てきてしまい、送信できなかったようです。


あー申し訳ないテスト希望の皆さま。

これで安心して本機用の基板が作れます;;
RCサーボ用は低性能の16F648Aでも使おうかな☆

今後の予定☆
以下システム開発の予定を立てていきます

(1) メイン基板の作成
I2Cで各基板に送信する役目を果たす基板。CRCとか余り詳しくないのでその辺の実験も必要。
どれほどの伊豆が乗って遅延が発生するのか検証し、16F1827が使用できるか確認する。(おそらくスペック的には十分)
(2) メインプログラムの作成
現段階ではテスト用の入力・画面出力しか備わっていないので入力に応じて通信するプログラムを作成する。(これは前作ったチャットプログラムを流用することにする。ただしUDP版)
他の機体と通信できるように。各機体にはIDを付けて機体自体で管理できるようにする。
(i) サーバープログラムを立てる
(ii) 各機体のPCはTPIPと通信を確立する
(iii) 各機体のPCはサーバープログラムと通信を確立する
(iv) 各機体のPCはTPIPから送られる映像データを、他の機体へ要請があれば転送する。

この際、命令は
(i) 映像を取得したい機体のIDを一覧(サーバーに要請する)から選び、サーバーに命令を送る
(ii) サーバーはその機体に対して映像を送る命令を出す
(iii) その機体のPCはサーバーではなく直接他の機体と通信を確立し、映像を垂れ流す。

ところで設定関係のプログラムも作らなければならないが、
アームの画面表示等、CSVファイル(あるいはXMLファイル)だけでは表現しきれないことが発生する。
これに対応するためにスクリプト言語による小差の設定が出来るようにしたい。
(出来れば私の好きな言語Rubyにしたいが難しそう)

PCは、現在の状態を表示するためにTPIPからデータを受信し(或いはサーボモーターの場合は現在の指定値から算出できる)、1フレーム毎にスクリプトを呼び出し、計算させ、
その結果を描画する。

描画する関数を予め用意して、スクリプトに処理させるのが理想である。
(TPIPSystem::Drawから行うなど)

各設定は例えば、IPアドレスや機体ID、機体名を始め.
・コントローラー入力設定(どんな入力デバイス?, 出力デバイスは何を使う?, 出力デバイスへの挙動の割り当ては?, スクリプトは?)
例えばPWMによる出力デバイス(個のサークルではExtenderと呼ばれている)をPS2のアナログ入力から行うとしよう。
PS2のアナログ値をPCが取得し、その値を歩きたいのサーボモーターに伝達しなければならない。PCはアナログ値をメイン基板に転送する。その際必要となる情報は、
(i) どの基板に送るか
(ii) 基板上の何番ぴんから出力するか
(iii) 角度のデータ
であり、角度のデータは例えば0x00~0xffなどとするが、これは基板に依存する。
基板は個のデータを解釈して、例えば0x80をニュートラルなどと解釈する。
0x7fをミュートRaruと解釈する開発者も居るだろうし、符号付きの整数を用いる人も居るだろう。
即ち、PCは送るデータのフォーマットも含めて出力デバイスの詳細を知らなければならない。


ユーザーが入力する値(x1, x2, x3, ..., xn) → 出力ドライバー →基板上に送る値(y1, y2, y3, ..., yn)と変換してくれる出力ドライバーが居てくれると便利であり、
個の出力ドライバーはプログラム上ではなく別のファイルで定義できると便利である。
個のドライバーをスクリプト言語で記述できると大変汎用性のあるプログラムに仕上がる。

もしも出来ないときは残念ながら、既存のドライバーをプログラム内に記述し、
即ち、「一般PWM出力基板」などと決めて、コントローラの入力も選択 :
(i) アナログ
(ii) ステップ式のデジタル
するようにする。デジタルの場合は、ボタンを1回押すと角度が何度動くか、
同地押しは何秒間隔にするか、などのユーザーによる設定が必要になる。

さて、その設定は、1.各ボタン毎に割り振れるようにするべきであるか
(つまり○、△、□、×、……に対して割り振る形)、
それとも2.出力先のドライバーを選び、そのドライバーの出力に応じて割り振れるようにするべきか
(つまりPWM1~PWM8ピンに割り振る形)、
3.機能ごと追加していく形にするべきか
(つまり、カメラか移転用サーボ、駆動用DCモーター、など)
検討の余地がある。

1.の場合は、○と×を例えばPWMの+10, -10と設定した場合、関連性が分かりづらくなる。利点はボタンを操作する側に立てばどれを使おうか簡単に選べるという点である。
2.の場合は予め出力ドライバーを列挙し、そのドライバーのピンなどにボタンなどを割り振っていく形となる。何が使えるのが一目瞭然でわかりやすい。
3.の場合は「カメラ回転用サーボ1」 と登録し、その中でどのドライバーを使って何番ぴんから出力して、どんな入力形態で出力データに関する設定はどうして……というのを行う。

実際3が一番設定しやすいだろう。 やはりスクリプトが使えれば夢が広がる……

(3) 各基板の作成
今回シリアルサーボを導入するのでシリアル出力用基板を作りますが、単にシリアルデータを出力するだけです……。16F1827で性能で十分ですね。ただし100kbps以上の通信が必要なのでR8Cマイコンは使えませんね;

 ポテンショメーターの読み込み用の基板も作らないといけませんね。
こちらはアナログ入力をしてTPIPにデータを送る(メインマイコンにI2Cで送る)んですけど、
I2Cでスレーブ側が送信するプログラムを組んだことがないので実験します。
(これは来週かな……)

ポテンショメータの読み込み結果、画面に状態を表示しないといけません。
i. 数字で
ii. 画像で
出すんですが、iは簡単。ただし、場所・フォントを指定します。設定できるようにしたいな。
iiはやはり各機体ごと異なるので、プログラム中に指定するわけにはいきません。
但し解決策はあります。

アームの形状は――が組み合わさったものだと考えれば、
(i) 原点を用意する。回転平面を指定する(xy, yz, zx)。
(ii) 原点からr1の位置に支点(モーター)を作る。回転平面を指定する。
(iii) r1の位置からr2の位置に支点(モーター)を作る。……
と繰り返していけば、3Dで描画できます。

即ち、原点での回転方向と、rnと回転方向さえ分かれば描画できるのです。
これらを指定するのが設定ファイルの役目であり、部分的には解決します。
# ドライバーの件ではスクリプトファイルがとても有効なんですけどね……
# まあそんなにたくさんのドライバーは存在しないんですが。精々4種類

そのほかの基板は電源基板ですね。
電源は7.2V×2~3と10.8V×1~2の2種類。
i. コネクタはどうするか
ii. 緊急停止スイッチの仕組みはどうするか
iii. バッテリーへの振り分け回路や保護回路はどうするか
など問題があります。

iについては、基板にコネクタを付けて線をつなぐようにします。
その先は更にバッテリーとつなぐコネクタを用意します。
iiについては全ての電源はスイッチを通して電流が流れるようにします。
或いはリレーを使います。(ここは未定、スイッチの定格電流を再度調べておきます)
 iiiについては未検討です。バッテリーのショート防止用に何かあった方がいいと思いますが、そもそもシリアルサーボ自体電流を消費するのであまり保護できないんですよね;

バッテリーについても連続駆動時間の実験を調べる必要がありますし、
バッテリーの負担分配(電圧が違うと駆動モーターの左右で挙動が代わってまっすぐ進めない)も検討しなければなりません。

基板上には刺すピンが同電圧の電源として共通になっていて、
その電源への供給は、ICが制御してバッテリーを選択するという方法もありますが、
切り替え時のノイズが怖い。これも要実験あるいは見送り。

バッテリーの状態はPC上から分かった方がいいので、電源基板とメインボードとI2Cで通信して、逐一報告できるようにしたいですね。アナログ入力でいいでしょう。
10.8Vまでなので、抵抗で分圧して1/3とします。15Vだとしても5Vとなるので入力電圧には余裕があります。
ただしAD変換の精度は精々8bitとしておきますので、5/256 =  0.02[V]まあこれだけあれば。0.02×3 = 0.06Vの精度で計測できますから、バッテリーの有無程度の場合には支障がありません。0.1V精度でも十分ですからね。

するとバッテリーの設定も必要となります。
バッテリーの電圧低下による自動停止・ここのバッテリーの停止命令などがあった方がいいでしょう。
すると、バッテリーの停止に伴ってFETやリレーが必要となります。
どちらかや水泡を採用しますが、MOS-FETで十分な気がします……。電流や放熱の設計によってはリレーになるかもしれませんが。出来れば小さい方がいいよね。

……他に何かありますかね。明日1コマから授業なので今日はこの辺で……ハンバーグ作りたいしね

余談☆
今日M8ネジ買ってきました。あと防振用ゴム(そう書いてなかったけど)これでようやく買ったヘッドライトを装着できそうです。H4バルブ化したので前方も明るくなったかな。 なおライトユニットの中に入っていたコード類が外に飛び出してしまったため雨の対策が必要な模様……

2013/06/05

レスキュー1ヶ月前だというのに

3年のKです。

レスキュー1ヶ月前だというのにシリアルサーボをうまく制御できないで居ます……。
機体は完成してきているのに動かせないではどうしようもありません。
 1つ1つだと動かせるのに、数珠つなぎにすると3つ以上で動かなくなるようです。
これではシリアルサーボの利点がなくなってしまう!

送信間隔を短くしてみたり、IDを変えてみたり、配線を入れ替えてみたりしましたがどうやら3個以上は常にうまくいかない様子。

しばらく動かしていたらどうやら1番サーボがお亡くなりになっているようだ……
嘘だろ……ID書き込みとかその他は大丈夫なのにどうして……

明日になったら動くようになっていたりしてよね……