スタートゲート 基本プログラム公開(Arduino,Proccesing)
ArduinoとProccesingのプログラムが完成しました。
Arduinoはタイマー計測とセンサー等
Proccesingはパソコンに表示という役割を持っています。
動作はこんな感じです。
タイマー↓
タイマー計測とセンサー通過処理↓
パソコンにタイマー計測を表示↓
タイマー計測からセンサー処理、パソコンに表示までの一連の流れ(全体動作確認)↓
プログラム↓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:センチ秒読み込み
}
}
}