動手製作一個智能小車教程未完成
能親手製作智能車、機器人,大概是我們每一位marker都想實現的事情,那麼今天我們就來看看如何製作一輛可以紅外、藍牙控制,並且可以用openmv攝像頭實時追蹤色塊的智能車吧。
文章目錄
1.小車功能設計
現在我們手上有一套智能車模型套件、紅外遙控器及傳感器、藍牙模塊、一塊OpenMV攝像頭模塊。
- 首先,要快速完成一輛小車的製作,我們可以選用智能車模型套件,直接拼裝成智能車,這可以節省我們不少設計的功夫,將精力放在功能實現上面。
- 其次,我們可以使用紅外遙控和紅外接收模塊,對小車進行紅外控制;
- 再次,我們可以通過藍牙模塊,通過手機app,藍牙遠程遙控智能車;
- 最後,車子要做到智能,那必不可少的就是圖像識別,我們可以使用OpenMV攝像頭對顏色進行實時識別和跟蹤。
那就讓我們開始實現以上的想法吧,JUST DO IT!
2.應用學到那些知識
做這個項目之前,你需要有:
- 一點基礎的編程語法知識(任何語言)
- 一顆耐心和創客的激情
做完這個項目,你可以掌握:
- 電機驅動板L298N的使用方法
- arduino的使用方法
- 紅外模塊的使用方法
- 藍牙模塊HC-05的調試方法
- 手機控制藍牙的方法
- OpenMV攝像頭模塊顏色識別的方法
- OpenMV與arduino板子通信的方法
3.材料準備
1.智能車部分:模型套件,如下圖
2.控制電路部分:如下表
材料 | 數量 |
---|---|
arduino模塊 | 1塊 |
L298N電機驅動模塊 | 1塊 |
紅外接收模塊 | 1塊 |
紅外遙控器 | 1件 |
藍牙模塊 | 1塊 |
USB轉TTL模塊(可選) | 1塊 |
OpenMV3 攝像頭模塊 | 1塊 |
9-12V電源 | 1件 |
杜邦線 | 若干 |
螺絲、螺母、銅柱 | 若干 |
熱熔膠槍 | 1把 |
螺絲刀套件 | 1套 |
L298N電機驅動模塊 | 1塊 |
焊烙鐵(可選) | 1件 |
剝線鉗(可選) | 1把 |
電壓表(可選) | 1件 |
android手機 | 1部 |
3.攝像頭部分:OpenMV攝像頭模塊,如下圖
4.組裝小車
按照說明書裝配小車模型。
TODO 待補充
5.製作紅外小車
- 如下如連接杜邦線
- 打開Arduino開發環境並添加庫文件,如未安裝,點擊這裏
- 上傳代碼
//紅外小車代碼及解釋
#include <IRremote.h>//打開IDE:項目→加載庫→添加→搜索IRremote→安裝IRredmote庫
int RECV_PIN = 11;//紅外接收端口
IRrecv irrecv(RECV_PIN);
decode_results results;//結構聲明
//==============================
int Left_motor_back=5; //左電機後退(IN1)
int Left_motor_go=6; //左電機前進(IN2)
int Right_motor_go=9; // 右電機前進(IN3)
int Right_motor_back=10; // 右電機後退(IN4)
void setup()
{
//初始化電機驅動IO爲輸出方式
pinMode(Left_motor_go,OUTPUT); // PIN 5 (PWM)
pinMode(Left_motor_back,OUTPUT); // PIN 6 (PWM)
pinMode(Right_motor_go,OUTPUT);// PIN 9 (PWM)
pinMode(Right_motor_back,OUTPUT);// PIN 10 (PWM)
pinMode(13, OUTPUT);////端口模式,輸出
Serial.begin(9600); //波特率9600
irrecv.enableIRIn(); // Start the receiver
}
void run() // 前進
{
digitalWrite(Right_motor_go,HIGH); // 右電機前進
digitalWrite(Right_motor_back,LOW);
digitalWrite(Left_motor_go,HIGH); // 左電機前進
digitalWrite(Left_motor_back,LOW);
}
void brake() //剎車,停車
{
digitalWrite(Right_motor_go,LOW);
digitalWrite(Right_motor_back,LOW);
digitalWrite(Left_motor_go,LOW);
digitalWrite(Left_motor_back,LOW);
}
void left() //左轉(左輪不動,右輪前進)
{
digitalWrite(Right_motor_go,HIGH); // 右電機前進
digitalWrite(Right_motor_back,LOW);
digitalWrite(Left_motor_go,LOW); //左輪不動
digitalWrite(Left_motor_back,LOW);
}
void spin_left() //左轉(左輪後退,右輪前進)
{
digitalWrite(Right_motor_go,HIGH); // 右電機前進
digitalWrite(Right_motor_back,LOW);
digitalWrite(Left_motor_go,LOW); //左輪後退
digitalWrite(Left_motor_back,HIGH);
}
void right() //右轉(右輪不動,左輪前進)
{
digitalWrite(Right_motor_go,LOW); //右電機不動
digitalWrite(Right_motor_back,LOW);
digitalWrite(Left_motor_go,HIGH);//左電機前進
digitalWrite(Left_motor_back,LOW);
}
void spin_right() //右轉(右輪後退,左輪前進)
{
digitalWrite(Right_motor_go,LOW); //右電機後退
digitalWrite(Right_motor_back,HIGH);
digitalWrite(Left_motor_go,HIGH);//左電機前進
digitalWrite(Left_motor_back,LOW);
}
void back() //後退
{
digitalWrite(Right_motor_go,LOW); //右輪後退
digitalWrite(Right_motor_back,HIGH);
digitalWrite(Left_motor_go,LOW); //左輪後退
digitalWrite(Left_motor_back,HIGH);
}
//=============================================================================
//讀取各個按鍵需要用到這段代碼
//=============================================================================
void read_key()
{
if(irrecv.decode(&results)){ //如果接收到信息
Serial.print("code:");
Serial.println(results.value,HEX);//results.value爲16進制,unsigned long
Serial.print("bits:");
Serial.println(results.bits);//輸出元位數
irrecv.resume();
}
}
void loop()
{
read_key();
if(irrecv.decode(&results)){ //如果接收到信息
switch(results.value){
case 0xFF18E7: //前,對應2
run();
break;
case 0xFF4AB5: //後,對應8
back();
break;
case 0xFF10EF: //左,對應4
left();
break;
case 0xFF5AA5: //右,對應6
right();
break;
case 0xFF38C7: //停止,對應5
brake();
break;
default:
break;
}
irrecv.resume();
}
}
- 測試成果
6.製作藍牙小車
- 如下如連接杜邦線
- 打開Arduino開發環境
- 上傳代碼
//藍牙小車代碼及解釋
#define IN1 6 // 7 6 右輪
#define IN2 7
#define IN3 4 // 5 4 左輪
#define IN4 5
#define LEFT '3' //左轉編碼
#define RIGHT '4'//右轉編碼
#define GO '1'//前進編碼
#define BACK '2'//後退編碼
#define STOP '0'//停止編碼
char left_code = '1';
void setup() {
// put your setup code here, to run once:
Serial.begin(9600);
pinMode(IN1,OUTPUT);
pinMode(IN2,OUTPUT);
pinMode(IN3,OUTPUT);
pinMode(IN4,OUTPUT);
initCar();
}
void loop() {
// put your main code here, to run repeatedly:
if(Serial.available()>0){
char ch = Serial.read();
if(ch == GO){
//前進
go();
}else if(ch == BACK){
//後退
back();
}else if(ch == LEFT){
//左轉
turnLeft();
}else if(ch == RIGHT){
//右轉
turnRight();
}else if(ch=='0'){
//停車
stopCar();
}
}
}
void initCar(){
//默認全是低電平 停止狀態
digitalWrite(IN1,LOW);
digitalWrite(IN2,LOW);
digitalWrite(IN3,LOW);
digitalWrite(IN4,LOW);
}
/**
* 左轉
*/
void turnLeft(){
digitalWrite(IN1,HIGH);
digitalWrite(IN2,LOW); //右輪前進
digitalWrite(IN3,LOW);
digitalWrite(IN4,LOW); //左輪不動
}
/**
* 右轉
*/
void turnRight(){
digitalWrite(IN1,LOW);
digitalWrite(IN2,LOW); //右輪不動
digitalWrite(IN3,HIGH);
digitalWrite(IN4,LOW); //左輪前進
}
/**
* 前進
*/
void go(){
digitalWrite(IN1,HIGH);
digitalWrite(IN2,LOW); //右輪前進
digitalWrite(IN3,HIGH);
digitalWrite(IN4,LOW); //左輪前進
}
/**
* 倒車
*/
void back(){
digitalWrite(IN1,LOW);
digitalWrite(IN2,HIGH); //右輪後退
digitalWrite(IN3,LOW);
digitalWrite(IN4,HIGH); //左輪後退
}
/**
* 停車
*/
void stopCar(){
initCar();
}
- 測試成果
7.製作追蹤顏色小車
- 如下如連接杜邦線
- 打開Arduino開發環境
- 上傳代碼
// OpenMV小車代碼及解釋
#include <Wire.h>
#define BAUD_RATE 19200
#define CHAR_BUF 128
void setup() {
Serial.begin(BAUD_RATE);
Wire.begin();
delay(1000); // 給OpenMV一個啓動的時間
}
void loop() {
int32_t temp = 0;
char buff[CHAR_BUF] = {0};
Wire.requestFrom(0x12, 2);
if (Wire.available() == 2) { // got length? 接收字符串
temp = Wire.read() | (Wire.read() << 8);
delay(1); // Give some setup time...
Wire.requestFrom(0x12, temp);
if (Wire.available() == temp) { // got full message?
temp = 0;
while (Wire.available()) buff[temp++] = Wire.read();
} else {
while (Wire.available()) Wire.read(); // Toss garbage bytes.
}
} else {
while (Wire.available()) Wire.read(); // Toss garbage bytes.
}
Serial.print(buff);
delay(1000); // Don't loop to quickly.
}
- 測試成果
8.將三個功能集成,製作智能小車
- 打開Arduino開發環境
- 上傳代碼
/*
* 藍牙串口指令規定
* 改變運行模式:紅外:I(默認)、藍牙:B、openmv:O
* 藍牙控制參數設置:前進:1、後退:2、左轉:3、右轉:4、停車:0、油門:5、剎車:6
*/
#include <IRremote.h>
#include <Wire.h>
#define BAUD_RATE 9600
#define CHAR_BUF 128
float left_speed = 1.1;
float right_speed = 1.1;
char buff[CHAR_BUF] = {0};
int RECV_PIN = 11;//紅外接收端口
IRrecv irrecv(RECV_PIN);
decode_results results;//結構聲明
char mode = 'I'; //設置小車運行模式,默認紅外模式
int Left_motor_back=3; //左電機後退(IN1)
int Left_motor_go=4; //左電機前進(IN2)
int Right_motor_go=9; // 右電機前進(IN3)
int Right_motor_back=10; // 右電機後退(IN4)
int ENA = 5; //PWM輸入A
int ENB = 6; //PWM輸入B
int speed_default = 100; //0-255之間,小車最低速度爲70,最佳速度爲100
char ch;
bool inverse_left=false;
bool inverse_right=false;
void setup()
{
//初始化電機驅動IO爲輸出方式
pinMode(Left_motor_go,OUTPUT); // PIN 5 (PWM)
pinMode(Left_motor_back,OUTPUT); // PIN 6 (PWM)
pinMode(Right_motor_go,OUTPUT);// PIN 9 (PWM)
pinMode(Right_motor_back,OUTPUT);// PIN 10 (PWM)
pinMode(ENA,OUTPUT);
pinMode(ENB,OUTPUT);
pinMode(13, OUTPUT);////端口模式,輸出
Serial.begin(BAUD_RATE); //波特率9600
irrecv.enableIRIn(); // Start the receiver
Wire.begin();
delay(1000); // 給OpenMV一個啓動的時間
}
void run() // 前進
{
digitalWrite(Right_motor_go,HIGH); // 右電機前進
digitalWrite(Right_motor_back,LOW);
digitalWrite(Left_motor_go,HIGH); // 左電機前進
digitalWrite(Left_motor_back,LOW);
analogWrite(ENA,speed_default);
analogWrite(ENB,speed_default);
}
void brake() //剎車,停車
{
digitalWrite(Right_motor_go,LOW);
digitalWrite(Right_motor_back,LOW);
digitalWrite(Left_motor_go,LOW);
digitalWrite(Left_motor_back,LOW);
analogWrite(ENA,speed_default);
analogWrite(ENB,speed_default);
}
void left() //左轉(左輪不動,右輪前進)
{
digitalWrite(Right_motor_go,HIGH); // 右電機前進
digitalWrite(Right_motor_back,LOW);
digitalWrite(Left_motor_go,LOW); //左輪不動
digitalWrite(Left_motor_back,LOW);
analogWrite(ENA,speed_default);
analogWrite(ENB,speed_default);
}
void spin_left() //左轉(左輪後退,右輪前進)
{
digitalWrite(Right_motor_go,HIGH); // 右電機前進
digitalWrite(Right_motor_back,LOW);
digitalWrite(Left_motor_go,LOW); //左輪後退
digitalWrite(Left_motor_back,HIGH);
analogWrite(ENA,speed_default);
analogWrite(ENB,speed_default);
}
void right() //右轉(右輪不動,左輪前進)
{
digitalWrite(Right_motor_go,LOW); //右電機不動
digitalWrite(Right_motor_back,LOW);
digitalWrite(Left_motor_go,HIGH);//左電機前進
digitalWrite(Left_motor_back,LOW);
analogWrite(ENA,speed_default);
analogWrite(ENB,speed_default);
}
void spin_right() //右轉(右輪後退,左輪前進)
{
digitalWrite(Right_motor_go,LOW); //右電機後退
digitalWrite(Right_motor_back,HIGH);
digitalWrite(Left_motor_go,HIGH);//左電機前進
digitalWrite(Left_motor_back,LOW);
analogWrite(ENA,speed_default);
analogWrite(ENB,speed_default);
}
void back() //後退
{
digitalWrite(Right_motor_go,LOW); //右輪後退
digitalWrite(Right_motor_back,HIGH);
digitalWrite(Left_motor_go,LOW); //左輪後退
digitalWrite(Left_motor_back,HIGH);
analogWrite(ENA,speed_default);
analogWrite(ENB,speed_default);
}
//=============================================================================
//讀取各個按鍵需要用到這段代碼
//=============================================================================
void read_key()
{
if(irrecv.decode(&results)){ //如果接收到信息
Serial.print("code:");
Serial.println(results.value,HEX);//results.value爲16進制,unsigned long
Serial.print("bits:");
Serial.println(results.bits);//輸出元位數
irrecv.resume();
}
}
//=============================================================================
//處理字符串buff
//============================================================================
void getCode(){ //buff經過傳輸,尾部有干擾,故用兩個空格分割
String temp1,temp2;
String string = String(buff);
int postion = string.indexOf(" ");
temp1 = string.substring(0,postion);
string = string.substring(postion+1,string.length());
postion = postion = string.indexOf(" ");
temp2 = string.substring(0,postion);
left_speed = temp1.toFloat();
right_speed = temp2.toFloat();
}
//=============================================================================
//PWM模式的小車運動
//============================================================================
void openmvrun(){
if(inverse_left)
left_speed=-left_speed;
if(inverse_right)
right_speed=-right_speed;
int l_speed = abs(left_speed);
int r_speed = abs(right_speed);
if(left_speed<0){
digitalWrite(Left_motor_go,LOW); //左輪後退
digitalWrite(Left_motor_back,HIGH);
}else{
digitalWrite(Left_motor_go,HIGH);//左電機前進
digitalWrite(Left_motor_back,LOW);
}
analogWrite(ENA,l_speed);
if(right_speed<0){
digitalWrite(Right_motor_go,LOW); //右輪後退
digitalWrite(Right_motor_back,HIGH);
}else{
digitalWrite(Right_motor_go,HIGH); // 右電機前進
digitalWrite(Right_motor_back,LOW);
}
analogWrite(ENB,r_speed);
Serial.print(l_speed);
Serial.print(" ");
Serial.print(r_speed);
}
void loop()
{
if(Serial.available()>0){
ch = Serial.read();
if(ch == 'I'){
//紅外模式
mode = 'I';
}else if(ch == 'B'){
//藍牙模式
mode = 'B';
}else if(ch == 'O'){
//openmv模式
mode = 'O';
}
}
if(mode == 'I'){ //紅外模式控制代碼
//Serial.println("紅外模式");
read_key();
if(irrecv.decode(&results)){ //如果接收到信息
Serial.println(results.value);
switch(results.value){
case 0xFF18E7: //前,對應2
run();
break;
case 0xFF4AB5: //後,對應8
back();
break;
case 0xFF10EF: //左,對應4
left();
break;
case 0xFF5AA5: //右,對應6
right();
break;
case 0xFF38C7: //停止,對應5
brake();
break;
default:
break;
}
irrecv.resume();
}
}
if(mode == 'B'){ //藍牙模式控制代碼
//Serial.println("藍牙模式");
char ch1 = '0';
if(ch == '1'){
//前進
run();
Serial.print("前進");
}else if(ch == '2'){
//後退
back();
Serial.print("後退");
}else if(ch == '3'){
//左轉
left();
Serial.print("左轉");
}else if(ch == '4'){
//右轉
right();
Serial.print("右轉");
}else if(ch=='0'){
//停車
brake();
Serial.print("停車");
}else if(ch=='5'){
speed_default +=5;
ch = ch1;
}else if(ch=='6'){
speed_default -=5;
ch = ch1;
}
ch1 = ch;
Serial.println(speed_default);
}
if(mode == 'O'){ //openmv模式控制代碼
//Serial.println("openmv模式");
int32_t temp = 0;
Wire.requestFrom(0x12, 2);
if (Wire.available() == 2) { // got length?
temp = Wire.read() | (Wire.read() << 8);
delay(1); // Give some setup time...
Wire.requestFrom(0x12, temp);
if (Wire.available() == temp) { // got full message?
temp = 0;
while (Wire.available()) buff[temp++] = Wire.read();
} else {
while (Wire.available()) Wire.read(); // Toss garbage bytes.
}
} else {
while (Wire.available()) Wire.read(); // Toss garbage bytes.
}
//Serial.println(buff);
getCode();
//Serial.println(left_speed+" "+"right_speed="+right_speed);
//Serial.print(left_speed);
//Serial.print(" ");
//Serial.print(right_speed);
openmvrun();
delay(1); // Don't loop to quickly.
}
}
9.項目總結