Hatena::ブログ(Diary)

熊工房 ohgumaの腹凹ませたい日記

2004 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2005 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2006 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2007 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2008 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2009 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2010 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2011 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2012 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2013 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2014 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2015 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2016 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2017 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |

2017-01-05

[]C-Style の変数の使い方の例

C-Style上では変数がA〜Zの26個使える。プログラム中のどこからでもアクセス可能グローバル変数として定義されていて、有効範囲スコープ)の概念がないのでプログラム時にはそれを作り手が意識する必要があるが、以下の3範囲ぐらいが意識できればよいのではないかと思う。(2,3の使い分けは曖昧だが)

  1. プログラムを通して有効
  2. 無条件ループ内で有効
  3. 一時的にのみ使用する

以下は動作確認していないサンプル。変数が足りなくなる場合は2進数フラグと同様に10進数を数桁毎に加算して使うなどのアイデアもある。こうすることで上の1用の変数を減らすこともできるし、下の例であればAとBの比較で前回と今回でCN1,2,3のいずれかが変化したことなどの確認も一度にできるなどのメリットもある。

f:id:ohguma:20170106040234p:image

  1. プログラムを通して有効変数:B
  2. 無条件ループ内で有効:A,C,D,E
  3. 一時的使用する:Z

2016-12-27

[]ロボットスピード

C-Styleのタイマープログラムの処理時間を図る方法は次の通り。

  1. タイマーをスタートさせる。
  2. 処理時間を図りたい処理を実行する。
  3. タイマーの値を変数にセットする。
  4. 変数の値をシリアルモニタに表示する。(センサモニターの見出し部分をダブルクリックしてからスタートスイッチを押す)

f:id:ohguma:20161228012258p:image

上のプログラムだと、砂時計1秒間の処理時間変数Aにセットされ、変数Aをシリアルモニタに表示している。変数Aの値は1000(単位ミリ秒)なので、処理時間は1秒であることが確認できる。

4行目のC-Codeは「printf("%ld", gV[VAR_A]);」と記述している。


f:id:ohguma:20161228012259p:image

直接タイマーの値を表示する場合は、3行目のC-Codeは「printf("%ld", gT[T1]);」と記述する。タイマー1の場合はT1、タイマー2の場合T2、以下同様にタイマー4まで利用できる。


上記の2つのプログラムには処理時間に差が無いように見えるが、ここで「printf」の処理時間も図ってみる。タイマーミリ単位でしか計測できず、1回の処理時間だと0ミリ秒になってしまったので、for文で100回繰り返した時間を図る。

f:id:ohguma:20161228012300p:image

変数Aの処理時間にはfor文の処理時間も含むので、中身のないfor文の時間も図って変数Bにセットする。AからBを引くことでprintfの100回文の処理時間が分かる。この例では「A-B = 42-0 = 42」なので、「printf("%ld", gV[VAR_A]);」の1回の処理時間は0.42ミリ秒となる。

より正確に測るなら、繰り返しももっと増やす。100x100=10000回の繰り返しで測った場合がこちら。

f:id:ohguma:20161228012301p:image

「A-B = 4221-34 = 4187」なので、「printf("%ld", gV[VAR_A]);」の1回の処理時間は0.4187ミリ秒となる。


変数Aにタイマー1の値を10000回セットする処理時間は、「A-B = 142-34 = 108」なので、「A=Timer1」の1回の処理時間は、0.0108ミリ秒となる。

f:id:ohguma:20161228012302p:image

printf」の処理は「A=Timer1」に比べ、0.3097ミリ秒遅く、一桁遅いことが分かる。最初の2つプロラムでは差が出なかったが、より正確な時間を図るならば、タイマーの値を直接表示せずに、一旦タイマーの値を変数にセットして変数を表示すべき、と判断できる。

また、printfの実行にも処理時間かかることが分かったので、printfの使用はデバッグ中に限定し、本番時には削除して全体の処理速度を上げるべき、となる。


C-Style上で1行分の処理でも、内容によって処理時間が異なることが分かった。その他の処理も同様に処理時間を図り、遅い処理をなるべく避け、プログラムスピードを上げる工夫をする。


なお、ここでの計測結果はあくまでも、手元にあるTJ3Bでの結果であり、他のTJ3Bでは結果が異なる可能性がある。また私が勘違いしている可能性もあるので、ここの数値を鵜呑みにせず、同様のテスト方法について考察し、自分なりに実験して結果を確認し、ロボットの性能upを図ってほしい。


個人的には、処理速度を上げたいならば、TJ3Bにはこだわらずに、より高速なCPUを使うマイコンボードを使うべきとは思うが、使う以上は性能を目一杯引き出してみたい。あくまで「ロボットの性能≒プログラムの性能」であり、「ロボットの性能≠CPUの性能」と考える。

2016-12-23

[]ロボットスピード

ロボットスピードと言えば移動速度が注目されているが、個人的にはプログラムの処理速度も注目するべきだ思う。


C-Styleでロボットを作る場合プログラム初期化後に「while:無条件ループ」〜「endwhile」で繰り返し処理を行うパターンが多いと考えるが、ここでは無条件ループの1周分の処理時間が異なる3つのプログラムがあると仮定する。

f:id:ohguma:20161223204227j:image

の無条件ループを処理できる場合、それぞれ1周の処理に要する時間

f:id:ohguma:20161223204952j:image

となる。

ロボットの移動速度が秒速1m(1m/秒)としたとき、1周の処理中に移動する距離

となる。

f:id:ohguma:20161223205541j:image

プログラム中で床に書かれた2cm幅のラインをチェックしようとしても、例えばAのプログラムであれば、ロボットが移動する20cmごとのチェックになるため、床センサの計測範囲が狭い場合は見逃す可能性が高く、見逃さないよう動かすには1度に20cmの範囲がチェックできる床センサを用意するか、移動速度を落とす必要がある。

しかし、Cのプログラムならば、移動5cmごとのチェックになるため、1度に5cmの範囲がチェックできる床センサがあれば見逃しは理論上はなくなる。

プログラムの処理速度が高ければ、狭い範囲しかチェックできないセンサでも見逃しをなくせる。特に同じ処理をするなら、どうすれば速く処理できるかを工夫することが大切になる。


C-Styleでは「Timer1:Start」とC-Code「printf("%ld", gT[T1]);」を使うことでシリアルモニタ上で経過時間ミリ単位確認できる。

printfの処理時間考慮すると「Timer1:Start」、「A=Timer1」、C-Code「printf("%ld", gV[VAR_A]);」が望ましいかも)

printfの出力結果は、センサーモニタの「センサーモニタ&出力チェック」の見出し部分をダブルクリックしてシリアルモニタが開いた状態で、プログラムをスタートさせて確認する(もしくは、TeraTermなどソフトでCOMポートを開いた状態でプログラムをスタートさせる)。

2016-12-19

[] ArduinoでI2Cする際のプルアップ抵抗について

TJ3BをMasterとし、SlaveのArduinoを2台I2Cで接続した際に、I2Cの通信不安定になり、いろいろ調べた結果、Arduino側の作りにマズい点があった。参考になったのは次のサイト


Arduioでの作例ではI2Cのプルアップ抵抗について特に言及されずに外部抵抗を使っているものがあるが、公式のWireライブラリを用いるとArduinoの内部でプルアップが行われるため、外部にプルアップ抵抗を別途設ける必要がない。

内部のプルアップ抵抗を使う場合、Atmega328PであればデータシートからSDA、 SCLがプルアップ抵抗Rpuの20KΩ(Min)〜50KΩ(Max)になるそうだが、プルアップ抵抗は適切な抵抗値を設定する必要がある。

プルアップ抵抗の決め方についは以下を参考に。


次の様な修正で、動作が安定した。

  • 構成
  • 修正前】
    • SlaveのArduinoで外部プルアップ抵抗(10KΩ)を付けていたが、内部プルアップも有効だった。
  • 修正点】
    • Wire.begin()の後に「pinMode(SDA, INPUT);pinMode(SCL, INPUT);」記述し、内部プルアップを無効化した。

2016-12-15

[] C-Styleでビット演算

しきい値を使ってセンサ計測値からセンサのON/OFFを判断する場合、各センサのON/OFF状態を2進数の各桁の0/1に置き換えると1つの変数複数センサ状態管理できる(以後、状態変数と呼ぶ)。


状態変数に値を代入していく過程では、1,2,4,8,16,..と倍々の値を足していけばよいので、C-Styleの変数ブロック状態変数を処理できるが、状態変数を使って何かを判断する場合などif文で変数チェックを使うと、ある1つの状態しか判断できずに不便になる。そのような場合、条件に「条件を記述」を使い、ビット演算できると一度に複数のON/OFF状態判断でき便利になる。


C-Styleだとこんな感じ。式の入力時の表記と、プログラムリスト中での表記が異なるので注意。

f:id:ohguma:20161216033221p:image


演算子優先順位には十分注意する。