2015年9月20日日曜日

Arduino: Pointer

ポインタというものがC言語(Arduino)では出てくる。これに関して分かりやすく説明しているページが見つけられなくてとってもこまった。
I couldn't find good explanations for a pointer function in C language on the Web and wasted my time.

今回行いたいのは,作成した関数から複数の戻り値(数値の配列)を得ること。MATLABだと超簡単なんだけど,C言語では基本的にはできないらしい。そこで使用するものが,ポインタというもの,らしい。
This time, I want to get an array of values as the return value of a function. In MATLAB it is very easy to write but C does not allow such a program. Instead, "pointer" enables us to achieve  almost the same thing.

結局,以下のように書いたら上手くいきました。MATLABでいうと,
In MATLAB, to get an array of values as the return value, you write

function main
pointer = testFunc;
disp(pointer)

function pointer = testFunc
for i = 1:6
   pointer(i)=i;
end

これで得られる配列を得るためには,Cだとこんな感じになる。
but in C, you write something like that.

void setup() {
  Serial.begin(115200);
}

void loop() {
  int pointer[] = {0, 0, 0, 0, 0, 0}; //(1)
  // the size of pointer is 6

  // Fucntion
  testFunc(pointer); //(2)

  // print on a serial monitor
  for (byte i = 0; i < 5; i++) {
    Serial.print(pointer[i]);
    Serial.print(',');
  }
  Serial.write(10); // new line character
  delay(1000);
}

void testFunc(int *a) { //(3)
  // put pointer as an argument
  for(byte i = 0; i<5; i++) {//(4)
    *a = i;
    ++a;  
    // the pointer proceeds from 0 to 5.
    // this maybe the same that a[0]=i ... a[5]=i.
  }
  
  // no "return", but the pointer is updated.
}


あまり説明が見つからなかったこともあり,ポインタについての理解は足りませんが,実用的な使い方としての解説をしてみます。


(1) int pointer[] = {0, 0, 0, 0, 0, 0};

で,ポインターと呼ばれるものをつくります。これは,ポインターとか言わずに,とりあえず欲しい配列入れるための変数を宣言すると考えましょう。今回はテストとして0を入れてますが,pointer[6];として,サイズだけ決めてもいいのかもしれません。
this made a pointer, and it is better to regard as just a variable which will contain an array of values. This time I write {0,0,0,0,0,0} but it maybe OK to state int pointer[6].


(2) testFunc(pointer); 

戻り値は書いてませんが,ポインターが勝手に更新されてくれるのでOKです。
this doesn't include the return value, but it's OK because the pointer gets the return value.

(3) void testFunc(int *a) {

引数を「*a」としているのがポインターとして使うというしるしです。きっと。
The asterisk maybe the sign to use an argument as a pointer. 

(4)for(byte i = 0; i<5; i++) {
     *a = i;
      ++a; 
   }

for文の中で,何やらポインターの数を増やしつつ,ポインターに値を代入しています。これがどういう仕組みかはわかりませんが,MATLABでいうと,for i=1:6; a(i)=x; end と一緒ということでしょう。もちろん,厳密な意味は違うのでしょうが,表層的にはこれでいいかと。
In the for loop, the value of the pointer increases and at the same time i is substituted for the pointer valuable. This may mean that for i=1:6; a(i)=x; end in the MATLAB language at least superficially.

とりあえず,これさえ理解できれば,戻り値に配列を設定するのは実装できるかな,と思います。根本的な間違いがあれば教えて下さい。

Arduino: function definition

初歩的ですが,関数を定義する時のルール。MATLABに慣れてるとわかんないだよ。
Cause I get used to MATLAB, even function definition is confusing to me...

void loop() {
   int a = myFunc(); // must be defined.
}

// must be defined as the type of the return value.
// if the function does not return any values, void is used.

int myFunc() {
  int x = 1+2;
  return x;
}

引数を使うときは,またあとで。


Arduino: Character to Integer

Serial通信はアスキー文字列としてデータを送受信します。つまり,20という数値を送ったとしても,それは数字で合って,数値ではありません。その後の処理を続けるには数値に変換したいわけです。
Serial communication send and receive data as ASCII characters not values.

そんなときは,atoiという関数を使います。
Use atoi (alphabet to integer) function.

void loop(){
   char * val =;   // * is important
   int a;

   // when 3-digits values are input
   for (int i =0;i<=3; i++){
     val[i] = Serial.read();   // [x] is important.
   }
   a = atoi(val); //wrong: a = atoi(val[x]);
}

255,255,255,255などのデータを送受信するときは,charではなくてとりあえずintで読んでから,カンマや改行文字などがくることをif文で判別,そうじゃないとき(数字のとき)には数字を“貯めて”から数値に変換,としたらとりあえず回りました。もっと簡単でいい方法もあるとは思いますが。
If you want to read data such as 255,255,255,255, you (1) read the data as int, (2) discriminate commas and newline characters using if statements, (3) "store"  the numeral characters, and (4) convert them into int values. It works but I guess better and simpler ways exist.

Arduino: MsTimer2, FlexiTimer2

Arduinoのタイマー機能についてです。
心理実験に使用することを目的としているので,一定の周波数でサンプリングしたいわけです。
I want analog data at a constant sampling rate to use an Arduino in psychological experiments.

Arduinoの時間関係の関数の簡単な奴としては,

millis()
 起動からの時間をミリ秒で返す,
micros()
 起動からの時間をマイクロ秒で返す
delay()
 次の処理までミリ秒単位で待つ

などの関数があります。

しかし,こいつらを使用して頑張ってみても,処理をしている間の遅れが蓄積していき,FB制御をしてもうまいこと一定間隔サンプリングができませんでした。この辺は私のプログラミング能力が不足しているためですが…。
I could not fulfill my purpose by using these functions.

ということで,時間割り込みとかなんとかいう関数を使用します。設定した間隔で処理を実行していくれる関数です。Arduino公式HPにて公開されているライブラリからダウンロードして下さい。
Then I used something time interruption functions. You need to download library files from the Arduino HP.
http://www.pjrc.com/teensy/td_libs_MsTimer2.html

MsTimer2
 ミリ秒単位の間隔で指定した処理を実行
FlexiTimer2
 マイクロ秒単位の間隔で指定した処理を実行

さて,実行してみましたが,一定間隔サンプリングは上手くいきませんでした。マジむかつきます。
I simply implemented it, but again I failed. Really annoying.

と思ったら,一定間隔で処理したい関数に

interrupts();

を入れることで問題が解消しました。これ見つけるのに半日使いました。
But congratulations, the problem was fixed after I put the above line into the function which I wanted to process at a constant intervals.

FlexiTimer2では,interrupts();を入れたらエラーが出て使えませんでした。FlexiTimer2を使いたいのですが,それ以上考えるのは面倒なので諦めました。誰か解決法教えてください。
ちなみに,dueでは両方の関数が使えず…。時間が立てば対応してくれるでしょうか?



アナログセンサーから一定間隔サンプリングをして,それをシリアルモニタに出力
A sketch which samples data from an analog port at a constant interval and outputs the data to a serial monitor.


#include <MsTimer2.h>

const int A0sensor = A0;

int sensorValue0;

void setup() {

  Serial.begin(115200);
  int a = 10;                    // 10ms intervals
  MsTimer2::set(a,sampling); 
  MsTimer2::start();
}

void loop() {

  // nothing
}

void sampling(){

   interrupts();
   sensorValue0 = analogRead(A0sensor);
   Serial.println(sensorValue0);
}

2015年9月18日金曜日

Arduino: SoftwareSerial

Arduinoのシリアル通信はくっついているUSBじゃないデジタルポートでも行える。
MEGAとかdueだと,メインのそれ以外の専用ポートもいくつかくっついているみたい。
Arduino can communicate to other devices by using digital ports.

Arduino UNOだと,デジタル0と1番以外を割り当てる。
0と1はもともとSoftwareSerialを使わずにシリアル通信をするときに使うものらしい。なので,最初からTXとRXという表示が付いている。今回は簡単なSoftwareSerialを使います。
In Arduino uno, we should use digital ports other than 0 and 1 when using SotwareSerial.


#include<SoftwareSerial.h>
SoftwareSerial Serial1(2,3); 
// You should define before void setup()
// The name of a software serial is arbitrary.
// eg., SoftwareSerial mySerial(2,3)

void setup() {

  Serial1.begin(115200);
}

void loop() {


  Serial1.println("hello");

  delay(500);


}


こんな感じ。

もうひとつSoftwareSerialポートを作成して,一台のArduinoで通信ごっこをして試すことが可能。
You can make another SoftwareSerial port and communicate to each other in the Arduino.

SoftwareSeria2 Serial1(4,5);// before voidsetup()

Serial2.begin(115200);// in void setup()

int SerialState = Serial2.read();// in void loop()

という感じ。

読み込んだものを確認するためには,シリアルモニタで確認したいので,そんな時には
to confirm the data, use the normal Serial and write the input data on a serial monitor.

// normal "Serial" is already defined by default.
// So you need not to define it.
Serial.begin(115200);// in void setup()

Serial.write(Serial2.read()); // in void loop()


こうすれば,シリアルモニタに,読み込んだものを出力できる。

charで読み込んだ場合は,writeではなくてprintを使う。
When you read data as char, you can use Serial.print to input them to the serial monitor.

char SerialState = Serial2.read();
Serial.println(Serial2.read());


ちなみに,
The case the types of variables are different,

Serial.println(Serial2.read());

では,違う表示になるので試してください。








2台のArduinoをつなぐ時にも,上のコードを適当に分けて書けばいい。
When you connect two Arduinos.

1台目TX-2台目RX,1台目RX-2台目TXを繋ぐのは当たり前で間違える人はいないだろうけど,1台目GRD-2台目GRDも繋がないと,電気的におかしなことになるので注意。
Note that you need to connect two GNDs.


また,プログラムを書き込む時には,2台を繋ぎながらだと書きこみエラーが出て,怖いので絶対にはずしましょう。

覚書はじめます。

あまりに物忘れが激しく,少し前に作ったものをことごとく忘れていくので,メモすることにしました。
過去のものも,遡って少しずつためるかもしれません。