湘南工科大学ロボット研究部

湘南工科大学ロボット研究部です。

スタートゲート 基本プログラム公開(Arduino,Proccesing)

ArduinoとProccesingのプログラムが完成しました。

Arduinoはタイマー計測とセンサー等

Proccesingはパソコンに表示という役割を持っています。

動作はこんな感じです。

タイマー↓

www.youtube.com

タイマー計測とセンサー通過処理↓

www.youtube.com

パソコンにタイマー計測を表示↓

www.youtube.com

タイマー計測からセンサー処理、パソコンに表示までの一連の流れ(全体動作確認)↓

www.youtube.com

プログラム↓Arduino側(赤文字部分)

/*****************************************
スタートゲート制御基板用スケッチ
LCD Keypad Shield使用
*****************************************/

#include <LiquidCrystal.h> //LCDライブラリ
#include <Boards.h> //LCDライブラリ
#include <Servo.h> //サーボライブラリ

/*select the pins used on the LCD panel
 lcdの使っているピン番号
LiquidCrystal(rs, enable, d4, d5, d6, d7)
rs: LCDのRSピンに接続するArduino側のピン番号
rw: LCDのRWピンに接続するArduino側のピン番号
enable: LCDのenableピンに接続するArduino側のピン番号
d0~d7: LCDのdataピンに接続するArduino側のピン番号

d0~d3はオプションで、省略すると4本のデータライン(d4~d7)だけで制御します。 */
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);

// define some values used by the panel and buttons
//timer2
int pushbutton;
//パターン
int INTimepattern = 4;
int OUTTimepattern = 4;
int pattern;
int gate1pattern = 0;
int gate2pattern = 0;
/*I = IN
O = OUT
cnts = second
cntm = minute*/
// 分秒表示
int Icnts = 0;
int Icntm = 0;
int Ocnts = 0;
int Ocntm = 0;
//センサーカウント
int sensorINcnt = 0;
int sensorOUTcnt = 0;
//時間計算
unsigned long Itimemillis = 0;
unsigned long Itimemicros = 0;
unsigned long Otimemillis = 0;
unsigned long Otimemicros = 0;
unsigned long Itime1 = 0;
int Itime2 = 0;
unsigned long Itime3 = 0;
unsigned long Otime1 = 0;
int Otime2 = 0;
unsigned long Otime3 = 0;
//時間
unsigned long micros();
//時間その他
int IcntIN = 0;
int OcntOUT = 0;
//定義
#define LEFT 0
#define UP 1
#define DOWN 2
#define RIGHT 3
#define SELECT 4
#define NONE 5

#define analogswitch A0

//sensor2 ゲート1IN ゲート2OUT
#define sensor1 15 //ゲート1 回路が少ないほう(出口)
#define sensor2 16 //ゲート1 回路が多いほう(入口)
#define sensor3 17 //ゲート2 回路が少ないほう(出口)
#define sensor4 18 //ゲート2 回路が多いほう(入口)
int sensorin1;
int sensorin2;
int sensorin3;
int sensorin4;
int INsensorpattern = 0;
int OUTsensorpattern = 0;
int Isensor = 0;
int Osensor = 0;
//A0~A5→D14~D19 変換可能

//servo2
Servo myservo1;
Servo myservo2;

//proccesing変数宣言
int outTime_m = 12; // OUTコース:分
int outTime_s = 34; // OUTコース:秒
int outTime_c = 56; // OUTコース:センチ秒
int inTime_m = 01; // INコース:分
int inTime_s = 23; // INコース:秒
int inTime_c = 45; // INコース:センチ秒


// read the buttons
int button() {
pushbutton = (analogRead(analogswitch) / 4);
if (pushbutton > 240) return NONE;
if (pushbutton < 10) return RIGHT;
if (pushbutton < 50) return UP;
if (pushbutton < 100) return DOWN;
if (pushbutton < 150) return LEFT;
if (pushbutton < 200) return SELECT;
// return NONE;
}


void timerOUT() {
sensorOUTpattern();
pattern = button();
switch (OUTTimepattern) {
case 0:
//ミリ秒基準
Otimemillis = millis();
Otime2 = Otimemillis - Otime1;
if (Otime2 >= 1000) {
Otime1 = Otimemillis;
Ocnts += 1;
}
if (Ocnts >= 60) {
Ocnts = 0;
Ocntm += 1;
}
OcntOUT = 0;
if (OUTsensorpattern == 5) {
OUTTimepattern == 2;
}
break;

case 2:
if (pattern == 0) {
OUTTimepattern = 4;
}
break;

case 4:
Otimemillis = millis();
Otime1 = Otimemillis;
Otime2 = Otimemillis - Otime1;
Ocnts = 0;
Ocntm = 0;
break;
}

}
void timerIN() {
pattern = button();
sensorINpattern();
switch (INTimepattern) {
case 0:
Itimemillis = millis();
Itime2 = Itimemillis - Itime1;
if (Itime2 >= 1000) {
Itime1 = Itimemillis;
Icnts += 1;
}
if (Icnts >= 60) {
Icnts = 0;
Icntm += 1;
}
if (INsensorpattern == 5) {
INTimepattern == 2;
}

break;

case 2:
if (pattern == 0) {
INTimepattern = 4;
}
break;

case 4:
Itimemillis = millis();
Itime1 = Itimemillis;
Itime2 = Itimemillis - Itime1;
Icnts = 0;
Icntm = 0;
break;
}
}

void LCD() {
timerIN();
timerOUT();
lcd.setCursor(5, 1);
lcd.print(Ocntm);
lcd.print(" ");
lcd.print(Ocnts);
lcd.print(" ");
lcd.print(Otime2);
lcd.print(" ");
lcd.setCursor(5, 0);
lcd.print(Icntm);
lcd.print(" ");
lcd.print(Icnts);
lcd.print(" ");
lcd.print(Itime2);
lcd.print(" ");
}

void proccesing() {
timerIN();
timerOUT();
outTime_m = Icntm; // OUTコース:分
outTime_s = Icnts; // OUTコース:秒
outTime_c = Itime2; // OUTコース:ミリ秒
inTime_m = Ocntm; // INコース:分
inTime_s = Ocnts; // INコース:秒
inTime_c = Otime2; // INコース:ミリ秒
Serial.print("H"); // ヘッダ送信(先頭を示す文字)
Serial.write(highByte(outTime_c));// OUTコース;センチ秒データ送信
Serial.write(lowByte(outTime_c));// OUTコース;センチ秒データ送信
Serial.write(highByte(inTime_c)); // INコースミリ秒データ送信
Serial.write(lowByte(inTime_c)); // INコースミリ秒データ送信
Serial.write(outTime_m);// OUTコース;分データ送信
Serial.write(outTime_s);// OUTコース;秒データ送信
Serial.write(inTime_m); // INコース;分データ送信
Serial.write(inTime_s); // INコース;秒データ送信
Serial.print('\n');
}

void sensori() {
{ if (digitalRead(sensor1) == LOW) {
sensorin1 = 1;
}
else {
sensorin1 = 0;
}
}
{ if (digitalRead(sensor2) == LOW) {
sensorin2 = 1;
}
else {
sensorin2 = 0;
}
}

}

void sensoro() {
{ if (digitalRead(sensor3) == LOW) {
sensorin3 = 1;
}
else {
sensorin3 = 0;
}
}
{ if (digitalRead(sensor4) == LOW) {
sensorin4 = 1;
}
else {
sensorin4 = 0;
}
}
}
void sensorOUT() {
sensoro();
if (sensorin4 == 0 && sensorin3 == 1) {
Osensor = 1;
}
else {
Osensor = 0;
}
}

void sensorIN() {
sensori();
if (sensorin2 == 1 && sensorin1 == 0) {
Isensor = 1;
}
else {
Isensor = 0;
}
}
void sensorOUTpattern() {
sensorOUT();
pattern = button();
switch (OUTsensorpattern) {
case 0:
sensorOUTcnt = 0;
if ( pattern == 0 ) {
gate2pattern = 1;
OUTsensorpattern = 2;
}
break;

case 1:
sensorOUTcnt = 0;
if (Osensor == 1) {
OUTsensorpattern = 2;
}
break;
case 2://1回目通過
sensorOUTcnt++;
OUTTimepattern = 0;
if (sensorOUTcnt > 1000) {
sensorOUTcnt = 0;
OUTsensorpattern = 3;
}
break;

case 3://通過前クラッシュしたらスイッチを押して通過判断
if (Osensor == 1 || pattern == 3) {
sensorOUTcnt = 0;
OUTsensorpattern = 4;
}

break;

case 4://3回目通過(ゴール)
sensorOUTcnt++;
if (sensorOUTcnt > 500 ) {
if (Osensor == 1 || pattern == 3) {
sensorOUTcnt = 0;
OUTTimepattern = 2;
OUTsensorpattern = 5;
}
}
break;

case 5://ゴール後
sensorOUTcnt++;
if (sensorOUTcnt > 1000 && pattern == 0) {
sensorOUTcnt = 0;
gate2pattern = 0;
OUTsensorpattern = 6;
}
break;

case 6:
sensorOUTcnt++;
if (sensorOUTcnt > 300) {
OUTsensorpattern = 0;
}
}
}

void sensorINpattern() {
sensorIN();
pattern = button();
switch (INsensorpattern) {
case 0:
sensorINcnt = 0;
if ( pattern == 0 ) {
gate1pattern = 1;
INsensorpattern = 2;//1にすればゲート通過から測定が可能
}
break;

case 1:
sensorINcnt = 0;
if (Isensor == 1) {
INsensorpattern = 2;
}
break;

case 2://1回目通過
sensorINcnt++;
INTimepattern = 0;
if (sensorINcnt > 1000) {
sensorINcnt = 0;
INsensorpattern = 3;
}
break;

case 3://通過前クラッシュしたらスイッチを押して通過判断
if (Isensor == 1 || pattern == 4) {
sensorINcnt = 0;
INsensorpattern = 4;
}

break;

case 4://3回目通過(ゴール)
sensorINcnt++;
if (sensorINcnt > 500 ) {
if (Isensor == 1 || pattern == 4) {
sensorINcnt = 0;
INTimepattern = 2;
INsensorpattern = 5;
}
}
break;

case 5://ゴール後
sensorINcnt++;
if (sensorINcnt > 1000 && pattern == 0) {
sensorINcnt = 0;
gate1pattern = 0;
INsensorpattern = 6;
}
break;

case 6:
sensorINcnt++;
if (sensorINcnt > 300) {
INsensorpattern = 0;
}
}
}
void servoOUT() {
sensorOUTpattern();
switch (gate2pattern) {
case 0:
myservo2.write(90);
break;

case 1:
myservo2.write(0);
break;
}
}

void servoIN() {
sensorINpattern();
switch (gate1pattern) {
case 0:
myservo1.write(90);
break;

case 1:
myservo1.write(0);
break;
}
}

void setup() {
Serial.begin(250000);
pinMode(sensor1, INPUT_PULLUP);
pinMode(sensor2, INPUT_PULLUP);
pinMode(sensor3, INPUT_PULLUP);
pinMode(sensor4, INPUT_PULLUP);
myservo1.attach(3);
myservo2.attach(11);
lcd.begin(16, 2); // start the library
lcd.setCursor(0, 0);
lcd.print("2OUT"); // print a simple message
lcd.setCursor(0, 1); // move to the begining of the second line
lcd.print("1IN");
}

void loop() {
servoIN();
servoOUT();
timerIN(); //INコース
timerOUT(); //OUTコース
proccesing(); //proccesingに送信
LCD(); //LCDに表示

}

 

void timeprinter() {
timerIN();
timerOUT();
Serial.print("IN");
Serial.print(" ");
Serial.print(Icntm);
Serial.print(" ");
Serial.print(Icnts);
Serial.print(" ");
Serial.print(Itime2);
Serial.print(" ");
Serial.print("OUT");
Serial.print(" ");
Serial.print(Ocntm);
Serial.print(" ");
Serial.print(Ocnts);
Serial.print(" ");
Serial.print(Otime2);
Serial.print(" ");
Serial.print(INTimepattern);
Serial.print(" ");
Serial.print(pattern);
Serial.print(" ");
Serial.println(IcntIN);
}

void sensorprinter() {
sensori();
sensoro();
Serial.print("sensor1");
Serial.print(sensorin1);
Serial.print(" ");
Serial.print("sensor2");
Serial.print(sensorin2 );
Serial.print(" ");
Serial.print("sensor3");
Serial.print(sensorin3 );
Serial.print(" ");
Serial.print("sensor4");
Serial.println(sensorin4 );
}

void patternkakunin() {
Serial.print(pattern);
Serial.print(INTimepattern);
Serial.println(OUTTimepattern);
}
void sensorkakunin() {
sensoro();
sensori();
sensorIN();
sensorOUT();
Serial.print(sensorin1);
Serial.print(sensorin2);
Serial.print(sensorin3);
Serial.print(sensorin4);
Serial.print(INsensorpattern);
Serial.println(OUTsensorpattern);
}
void sensortimekakunin() {
sensorINpattern();
sensorOUTpattern();
Serial.print(Isensor);
Serial.print(INTimepattern);
Serial.print(INsensorpattern);
Serial.print(" ");
Serial.print(Osensor);
Serial.print(OUTTimepattern);
Serial.println(OUTsensorpattern);
}
void servokakunin() {
servoIN();
servoOUT();
Serial.print(gate1pattern);
Serial.println(gate2pattern);
}

 

プログラム↓Proccesing(緑文字部分)COMは自分で変えてください。デバイスとプリンターかArduino IDEで確認できます。

/*
* MCR Gate System シリアル通信
* Processing側サンプル
* 開発環境Ver3.3
*/

// シリアルライブラリを取り入れる
import processing.serial.*;

// myPort(任意名)というインスタンスを用意
Serial myPort;

/*================== 変数宣言 ==================*/
int x; //図形のX座標の変数を用意
int NUM = 6; //センサーの数
int[] receivedData = new int[NUM]; //センサーの値を格納する配列
int outTime_m = 12; // OUTコース:分
int outTime_s = 34; // OUTコース:秒
int outTime_c = 56; // OUTコース:センチ秒
int inTime_m = 01; // INコース:分
int inTime_s = 23; // INコース:秒
int inTime_c = 45; // INコース:センチ秒

/*================== 初期設定 ==================*/
void setup(){
// 画面サイズ
size(1080, 780); // 1024 x 768だと下が切れる
textFont(createFont("x", 15)); // 日本語を表示用。バージョンアップで不要?
//frameRate(10); // 1秒間に10回 draw()実行(使うかもしれないので残す)

// シリアルポートの設定
// Arduinoが接続されているシリアルポートにあわせて書き換える
myPort = new Serial(this, "COM3", 250000);
}

/*================ 描画ループ ================*/
void draw(){

// 受信バッファから描画用変数に格納
outTime_m = receivedData[2];
outTime_s = receivedData[3];
outTime_c = receivedData[0];
inTime_m = receivedData[4];
inTime_s = receivedData[5];
inTime_c = receivedData[1];

// 分,秒,センチ秒のバラバラのデータを時計形式に結合
String outTime = nf(outTime_m, 2)+":"+nf(outTime_s, 2)+":"+nf(outTime_c, 3);
String inTime = nf(inTime_m, 2)+":"+nf(inTime_s, 2)+":"+nf(inTime_c, 3);
println(outTime); // デバッグ用に出力
println(inTime); // デバッグ用に出力

background(255); // 背景を指定色:白で塗りつぶす

//===OUTコースタイム表示===
textSize(90); // 文字サイズ
fill(0, 0, 255); // 文字色:BLUE
text("OUT", 30, height*15/100); // 表示するテキスト, x座標, y座標

textSize(220); // 文字サイズ
fill(0, 0, 255); // 文字色:BLUE
text(outTime, 80, height*40/100);


//===INコースタイム表示===
textSize(90); // 文字サイズ
fill(255, 0, 0); // 文字色:RED
text("IN", 30, height*65/100); // 表示するテキスト, x座標, y座標

textSize(220); // 文字サイズ
fill(255, 0, 0); // 文字色:RED
text(inTime, 80, height*90/100);

}

void serialEvent(Serial p){
if ( myPort.available() >= 9 ) { // ヘッダ + 時間データ で合計7バイト
if ( myPort.read() == 'H' ) { // ヘッダ文字を見つけたところから読み取る
/* receivedData[0] = myPort.read(); // OUT:分読み込み
receivedData[1] = myPort.read(); // OUT:秒読み込み
receivedData[2] = myPort.read(); // OUT:センチ秒読み込み
receivedData[3] = myPort.read(); // IN:分読み込み
receivedData[4] = myPort.read(); // IN:秒読み込み
receivedData[5] = myPort.read(); // IN:センチ秒読み込み*/
int high1 = myPort.read();
int low1 = myPort.read();
int high2 = myPort.read();
int low2 = myPort.read();
receivedData[0] = high1*256 + low1; // OUT:分読み込み
receivedData[1] = high2*256 + low2; // OUT:秒読み込み
receivedData[2] = myPort.read();// OUT:センチ秒読み込み
receivedData[3] = myPort.read(); // IN:分読み込み
receivedData[4] = myPort.read(); // IN:秒読み込み
receivedData[5] = myPort.read(); // IN:センチ秒読み込み
}
}

}