Project 17 多機能Bluetoothスマートカー

1.説明
これまでのプロジェクトでは、車は単一の機能のみを実行していました。しかし、このレッスンでは、Bluetoothを介してすべての機能を統合します。
2.フローチャート

3.配線図

1). 8×8 LEDボードのGND、VCC、SDA、SCLは拡張ボードのG(GND)、V(VCC)、A4、A5に接続します。
2). BluetoothモジュールのRXD、TXD、GND、VCCはそれぞれ8833モーターシールドのTX、RX、G、5Vに接続し、BluetoothモジュールのSTATEおよびBRKピンは接続不要です。
3). サーボはG、V、A3に接続します。茶色の線はGnd(G)、赤色の線は5V(V)、オレンジ色の線はA3に接続します。
4). ライントラッキングセンサーのG、V、S1、S2、S3はセンサー拡張ボードのG(GND)、V(VCC)、D11、D7、D8に接続します。
5). 超音波センサーのVCC、Trig、Echo、Gndはそれぞれ5V(V)、D12(S)、D13(S)、Gnd(G)に接続します。
6). 電源はBATポートに接続します。
4.テストコード
注意: テストコードをアップロードする前にBluetoothモジュールを取り外す必要があります。そうしないとコードのアップロードに失敗します。コードのアップロードが成功した後にBluetoothモジュールを接続してください。
//*******************************************************************************
/*
keyestudio 4wd BT Car
lesson 17
Bluetooth Multifunctional Car
http://www.keyestudio.com
*/
#define SCL_Pin A5 // クロックピンをA5に設定
#define SDA_Pin A4 // データピンをA4に設定
// パターンのデータを格納する配列。自分で計算するかモジュールツールから取得可能
unsigned char start01[] = {0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80,0x80,0x40,0x20,0x10,0x08,0x04,0x02,0x01};
unsigned char front[] = {0x00,0x00,0x00,0x00,0x00,0x24,0x12,0x09,0x12,0x24,0x00,0x00,0x00,0x00,0x00,0x00};
unsigned char back[] = {0x00,0x00,0x00,0x00,0x00,0x24,0x48,0x90,0x48,0x24,0x00,0x00,0x00,0x00,0x00,0x00};
unsigned char left[] = {0x00,0x00,0x00,0x00,0x00,0x00,0x44,0x28,0x10,0x44,0x28,0x10,0x44,0x28,0x10,0x00};
unsigned char right[] = {0x00,0x10,0x28,0x44,0x10,0x28,0x44,0x10,0x28,0x44,0x00,0x00,0x00,0x00,0x00,0x00};
unsigned char STOP01[] = {0x2E,0x2A,0x3A,0x00,0x02,0x3E,0x02,0x00,0x3E,0x22,0x3E,0x00,0x3E,0x0A,0x0E,0x00};
unsigned char clear[] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
unsigned char speed_a[] =
{0x00,0x40,0x20,0x10,0x08,0x04,0x02,0xff,0x02,0x04,0x08,0x10,0x20,0x40,0x00,0x00};
unsigned char speed_d[] =
{0x00,0x02,0x04,0x08,0x10,0x20,0x40,0xff,0x40,0x20,0x10,0x08,0x04,0x02,0x00,0x00};
int left_ctrl = 2; // グループBモーターの方向制御ピンを定義
int left_pwm = 5; // グループBモーターのPWM制御ピンを定義
int right_ctrl = 4; // グループAモーターの方向制御ピンを定義
int right_pwm = 6; // グループAモーターのPWM制御ピンを定義
int speeds = 150; // 初期速度を150に設定
const int servopin = A3; // サーボのピンをA3に設定
int L_pin = 11; // 左側トラッキングセンサーのピンをD11に定義
int M_pin = 7; // 中央トラッキングセンサーのピンをD7に定義
int R_pin = 8; // 右側トラッキングセンサーのピンをD8に定義
int L_val, M_val, R_val;
int trigPin = 12; // TRIGピンをD12に接続
int echoPin = 13; // ECHOピンをD13に接続
int distance, distance_l, distance_r;
char BLE_val;
void setup() {
Serial.begin(9600);//ボーレートを9600に設定
pinMode(left_ctrl,OUTPUT);//グループBモーターの方向制御ピンをOUTPUTに設定
pinMode(left_pwm,OUTPUT);//グループBモーターのPWM制御ピンをOUTPUTに設定
pinMode(right_ctrl,OUTPUT);//グループAモーターの方向制御ピンをOUTPUTに設定
pinMode(right_pwm,OUTPUT);//グループAモーターのPWM制御ピンをOUTPUTに設定
servopulse(servopin,90);//サーボの角度を90度に設定
delay(300);
pinMode(L_pin, INPUT); //トラッキングセンサーのピンを入力モードに設定
pinMode(M_pin, INPUT);
pinMode(R_pin, INPUT);
pinMode(trigPin, OUTPUT); //TRIGを出力モードに定義
pinMode(echoPin, INPUT); //ECHOを入力モードに定義
pinMode(SCL_Pin,OUTPUT);//クロックピンを出力に設定
pinMode(SDA_Pin,OUTPUT);//データピンを出力に設定
matrix_display(clear);
matrix_display(start01); //start01の表現パターンを表示
}
void loop() {
if(Serial.available()>0) {
BLE_val = Serial.read();
Serial.println(BLE_val);
}
switch(BLE_val)
{
case 'F' : car_front();
matrix_display(clear);
matrix_display(front);
break;
case 'B' : car_back();
matrix_display(clear);
matrix_display(back);
break;
case 'L' : car_left();
matrix_display(clear);
matrix_display(left);
break;
case 'R' : car_right();
matrix_display(clear);
matrix_display(right);
break;
case 'S' : car_Stop();
matrix_display(clear);
matrix_display(STOP01);
break;
case 'a' : speeds_a();
matrix_display(clear);
matrix_display(speed_a);
break;
case 'd' : speeds_d();
matrix_display(clear);
matrix_display(speed_d);
break;
case 'U': follow(); //‘U’を受信し、フォローモードに入る
break;
case 'Y': avoid(); //‘Y’を受信し、障害物回避モードに入る
break;
case 'G': confinement(); //‘G’を受信し、閉じ込めモードに入る
break;
case 'X': tracking(); //‘X’を受信し、トラッキングモードに入る
break;
}
}
void car_front()//前進状態を定義
{
digitalWrite(left_ctrl,HIGH);
analogWrite(left_pwm,(255-speeds));
digitalWrite(right_ctrl,HIGH);
analogWrite(right_pwm,(255-speeds));
}
void car_back()//後退状態を定義
{
digitalWrite(left_ctrl,LOW);
analogWrite(left_pwm,speeds);
digitalWrite(right_ctrl,LOW);
analogWrite(right_pwm,speeds);
}
void car_left()//左折状態を設定
{
digitalWrite(left_ctrl, LOW);
analogWrite(left_pwm, speeds);
digitalWrite(right_ctrl, HIGH);
analogWrite(right_pwm, (255-speeds));
}
void car_right()//右折状態を設定
{
digitalWrite(left_ctrl, HIGH);
analogWrite(left_pwm, (255-speeds));
digitalWrite(right_ctrl, LOW);
analogWrite(right_pwm, speeds);
}
void car_Stop()//停止状態を定義
{
digitalWrite(left_ctrl,LOW);
analogWrite(left_pwm,0);
digitalWrite(right_ctrl,LOW);
analogWrite(right_pwm,0);
}
void speeds_a() { //加速関数
while (1) {
Serial.println(speeds); //速度情報を表示
if (speeds < 255) { //最大255まで
matrix_display(clear);
matrix_display(speed_a);
speeds++;
delay(10); //成長速度を調整
}
BLE_val = Serial.read();
if (BLE_val == 'S') //‘S’を受信したら加速を停止
break;
}
}
void speeds_d() { //減速関数
while (1) {
Serial.println(speeds); //速度情報を表示
if (speeds > 0) { //0まで減速
matrix_display(clear);
matrix_display(speed_d);
speeds--;
delay(10); //減速速度を調整
}
BLE_val = Serial.read();
if (BLE_val == 'S') //‘S’を受信したら減速を停止
break;
}
}
int get_distance() {
int distance = 0;
digitalWrite(trigPin, LOW); // Trig/Pinを通じてパルスを送信し、HC-SR04の測距をトリガーするため、超音波信号インターフェースを2μsの低レベルに設定
delayMicroseconds(2);
digitalWrite(trigPin, HIGH); // 超音波信号インターフェースを10μsの高レベルに設定(ここでは少なくとも10μs)
delayMicroseconds(10);
digitalWrite(trigPin, LOW); // 超音波信号インターフェースを低レベルに維持
distance = pulseIn(echoPin, HIGH) / 58; // パルス時間を読み取り、距離(単位:cm)に変換
Serial.println(distance); // 距離値を出力
return distance;
}
void follow() {
servopulse(servopin,90);
delay(200);
int follow_flag = 1;
while (follow_flag) {
distance = get_distance(); // 測距関数を呼び出す
if (distance < 8 ) {// 距離が8未満の場合
car_back();// 車が後退する
matrix_display(clear);
matrix_display(back);
}
else if (distance >= 8 && distance < 13) { // 距離が8以上13未満の場合
car_Stop();// 停止
matrix_display(clear);
matrix_display(STOP01);
}
else if (distance >= 13 && distance <= 35 ) { // 距離が13以上35以下の場合
car_front();// 車が前進する
matrix_display(clear);
matrix_display(front);
}
else {// 上記のいずれにも該当しない場合
car_Stop();// 停止
matrix_display(clear);
matrix_display(STOP01);
}
BLE_val = Serial.read();
if (BLE_val == 'S') { // 'S'を受信した場合、車を停止する
follow_flag = 0;
car_Stop();
}
}
}
void avoid() {
int avoid_flag = 1;
while (avoid_flag) {
distance = get_distance(); // 測距関数を呼び出す
if (distance > 0 && distance < 20) { // 距離が0より大きく20未満の場合
car_Stop();// 停止
matrix_display(clear);
matrix_display(STOP01); // ドットマトリクスに停止パターンを表示
delay(1000);
servopulse(servopin,160); // サーボを180度以上に動かす
delay(500);
distance_l = get_distance(); // 左側の距離を取得
delay(100);
servopulse(servopin,20); // サーボを0度に回す
delay(500);
distance_r = get_distance(); // 右側の距離を取得
delay(100);
if (distance_l > distance_r) { // 距離を比較し、左の方が大きい場合
car_left(); // 車が左に曲がる
matrix_display(clear);
matrix_display(left); // ドットマトリクスに左パターンを表示
servopulse(servopin,90);// サーボを90度に戻す
delay(700);
matrix_display(clear);
matrix_display(front); // ドットマトリクスに前進パターンを表示
}
else { // それ以外(右の方が大きい場合)
car_right();// 車が右に曲がる
matrix_display(clear);
matrix_display(right); // ドットマトリクスに右パターンを表示
servopulse(servopin,90);// サーボを90度に戻す
delay(700);
matrix_display(clear);
matrix_display(front); // ドットマトリクスに前進パターンを表示
}
}
else { // 前方距離が20以上の場合
car_front();// 車が前進する
matrix_display(clear);
matrix_display(front); // ドットマトリクスに前進パターンを表示
}
BLE_val = Serial.read();
if (BLE_val == 'S') {// 'S'を受信した場合、車を停止する
avoid_flag = 0;
car_Stop();
}
}
}
void confinement() {
int confinement_flag = 1;
while (confinement_flag) {
L_val = digitalRead(L_pin); // 左センサーの値を読み取る
M_val = digitalRead(M_pin); // 中央センサーの値を読み取る
R_val = digitalRead(R_pin); // 右センサーの値を読み取る
if ( L_val == 0 && M_val == 0 && R_val == 0 ) { // 黒線が検出されない場合、車は前進する
car_front();
}
else { // それ以外の場合、いずれかのトラッキングセンサーが黒線を検出したら、車は後退してから左に曲がる
car_back();
delay(500);
car_left();
delay(800);
}
BLE_val = Serial.read();
if (BLE_val == 'S') { // 'S'を受信したら、車は停止する
confinement_flag = 0;
car_Stop();
}
}
}
void tracking() {
int track_flag = 1;
while (track_flag) {
L_val = digitalRead(L_pin); // 左センサーの値を読み取る
M_val = digitalRead(M_pin); // 中央センサーの値を読み取る
R_val = digitalRead(R_pin); // 右センサーの値を読み取る
if (M_val == 1) { // 中央で黒線を検出
if (L_val == 1 && R_val == 0) { // 左に黒線があり右にない場合、左に曲がる
car_left();
}
else if (L_val == 0 && R_val == 1) { // それ以外で右に黒線があり左にない場合、右に曲がる
car_right();
}
else { // それ以外は車は前進する
car_front();
}
}
else { // 中央で黒線が検出されない場合
if (L_val == 1 && R_val == 0) { // 左に黒線があり右にない場合、右に曲がる
car_right();
}
else if (L_val == 0 && R_val == 1) { // それ以外で右に黒線があり左にない場合、右に曲がる
car_right();;
}
else { // それ以外は停止する
car_Stop();
}
}
BLE_val = Serial.read();
if (BLE_val == 'S') { // 'S'を受信したら、車は停止する
track_flag = 0;
car_Stop();
}
}
}
void servopulse(int servopin,int myangle)// サーボモーターの動作角度
{
for(int i=0; i<30; i++)
{
int pulsewidth = (myangle*11)+500;
digitalWrite(servopin,HIGH);
delayMicroseconds(pulsewidth);
digitalWrite(servopin,LOW);
delay(20-pulsewidth/1000);
}
}
// この関数はドットマトリックス表示に使用される
void matrix_display(unsigned char matrix_value[])
{
IIC_start(); // データ転送開始条件を呼び出す関数
IIC_send(0xc0); // アドレスを選択する
for (int i = 0; i < 16; i++) //パターンデータは16バイトです
{
IIC_send(matrix_value[i]); //パターンのデータを送信します
}
IIC_end(); //パターンデータ送信終了
IIC_start();
IIC_send(0x8A); //表示制御、4/16パルス幅を選択
IIC_end();
}
//データ送信が開始される条件
void IIC_start()
{
digitalWrite(SDA_Pin, HIGH);
digitalWrite(SCL_Pin, HIGH);
delayMicroseconds(3);
digitalWrite(SDA_Pin, LOW);
delayMicroseconds(3);
digitalWrite(SCL_Pin, LOW);
}
//データ送信の終了を示す
void IIC_end()
{
digitalWrite(SCL_Pin, LOW);
digitalWrite(SDA_Pin, LOW);
delayMicroseconds(3);
digitalWrite(SCL_Pin, HIGH);
delayMicroseconds(3);
digitalWrite(SDA_Pin, HIGH);
delayMicroseconds(3);
}
//データ送信
void IIC_send(unsigned char send_data)
{
for (byte mask = 0x01; mask != 0; mask <<= 1) //各バイトは8ビットで、最下位からビットごとにチェックします
{
if (send_data & mask) { //バイトの各ビットが1か0かに応じてSDA_Pinの高低レベルを設定します
digitalWrite(SDA_Pin, HIGH);
} else {
digitalWrite(SDA_Pin, LOW);
}
delayMicroseconds(3);
digitalWrite(SCL_Pin, HIGH); //クロックピンSCL_Pinを高レベルにしてデータ送信を停止します
delayMicroseconds(3);
digitalWrite(SCL_Pin, LOW); //クロックピンSCL_Pinを低レベルにしてSDAの信号を変化させます
}
}
//*******************************************************************************
5.テスト結果
コードをV4.0ボードに正常にアップロードした後、配線図に従って配線を接続し、外部電源を入れてからDIPスイッチをONにします。
BluetoothモジュールがAPPに接続され、モバイルAPPがBluetoothに正常に接続されると、モバイルAPPでスマートカーを制御できます。モバイルAPPの対応するボタンを押すことで、対応する機能を実現できます。