技术专栏 | 基于Arduino开发的智能小车

一、概述

1. 设计内容

(1)智能小车自动运行(前后走,左右转)

(2)蓝牙控制、遥控器控制、无线手柄控制

(3)循迹、避障

(4)视觉

(5)装饰:音乐播放器

2.材料清单

3.掌握的内容

  (1)Arduino控制板引脚、连线及编程

  (2)电机驱动板L298N连线及编程

  (3)传感器模块的连线及使用,包括红外避障、红外循迹、超声波避障、数码管速度显示、OPENMV视觉捕捉、语音识别模块、音乐播放、

  (4)无线通信及遥控:蓝牙模块、WiFi模块、红外遥控、无线手柄、GPS定位。

二、小车组装

  小车实物图如图1所示,按照图示连接安装 

图1 实物连接图

三、控制元件搭建

1.电机驱动板L298N连线

图2 L298N电路板图


  图中,通道A和通道B分别连接电机的两端(两端无方向性,关乎电机正反转);电源正负极分别接到图示主电源正负极(≤5V接到5V输入,≥5V接到12V);A、B相使能端靠外接线端接入3、5、6、9、10、11等任意两个接线端带~的接线端,此处接到D10 D11,靠内一侧的两个引脚悬空或接5V连线端;1,2,3,4输入端分别接入数字端口D4 D5 D6 D7。

2.电源连线

  电池盒放入两节2×3.4V的可充电锂电池,将正极线(红色)连接到开关一端,另一端连入面包板正极列,正极列连入图2电源正极端(12V或5V)和Arduino的VIN端;GND接到面包板负极,电源负极端连入面包板负极的同一列。

图3 电源连接线

3.传感器件连线

(1)超声波接线端

图4 超声波实物图


  VCC接5V,GND接GND,TRIG接2 ECHO接3

(2)蓝牙模块连线


  VCC接5V,GND接GND,TX接RX,RX接TX

(3)红外遥控连线



  -接GND,+接5V,S接信号端,此处接D8

(4)红外循迹模块


  四路循迹分别接到循迹主控板上,VCC接主控板5V,GND接主控板GND,OUT1~OUT4分别接到A0-A3

  调节方式:将循迹模块置于轨迹上,令四路模块依次检测轨迹与非轨迹部分,并通过调节所在位置的电位器,使得指示灯在检测到轨迹时灭,未检测到轨迹时亮即可,然后通过串口通信端读取值,替换到程序中。

(5)舵机云台

  棕色接GND,红色接5V,橙色接信号线,此处接D9

(6)OPENMV


   P4接A4,P5接A5,VCC接5V,GND接GND

(7)蜂鸣器


   VCC接5V,GND接GND,I/O接D12

四、编程实现

 1. 蓝牙AT模式设置

  按住蓝牙模块黑色按钮,然后再接通电源,蓝牙以一秒间隔闪灭

  将下面程序串烧到Arduino中,打开串口监视器,观察串口输出,显示OK即为成功设置

  断电,再次上电,当蓝牙不断闪烁时,开始正常工作

void setup() {

// put your setup code here, to run once:

Serial.begin(38400);

}

void sendcmd()

{

Serial.println("AT");

while(Serial.available())

{

char ch;

ch = Serial.read();

Serial.print(ch);

} // Get response: OK

delay(1000); // wait for printing

Serial.println("AT+NAME=Sonny");

while(Serial.available())

{

char ch;

ch = Serial.read();

Serial.print(ch);

}

delay(1000);

Serial.println("AT+ADDR?");

while(Serial.available())

{

char ch;

ch = Serial.read();

Serial.print(ch);

}

delay(1000);

Serial.println("AT+PSWD=2113");

while(Serial.available())

{

char ch;

ch = Serial.read();

Serial.print(ch);

}

delay(1000);

/*Serial.println("AT+PSWD?");

while(Serial.available())

{

char ch;

ch = Serial.read();

Serial.print(ch);

}

delay(1000);*/

}

void loop() {

sendcmd();

}

2. 电机PWM驱动程序

int Left_motor_back=4;    //左电机后退(IN1)

int Left_motor_go=5;    //左电机前进(IN2)

int Right_motor_go=6;    // 右电机前进(IN3)

int Right_motor_back=7;    // 右电机后退(IN4)

int ENA=10;

int ENB=11;int i;

void setup()

{

//初始化电机驱动IO为输出方式

pinMode(Left_motor_go,OUTPUT); // PIN 4 (PWM)

pinMode(Left_motor_back,OUTPUT); // PIN 5 (PWM)

pinMode(Right_motor_go,OUTPUT);// PIN 6 (PWM)

pinMode(Right_motor_back,OUTPUT);// PIN 7 (PWM)

pinMode(ENA,OUTPUT);

pinMode(ENB,OUTPUT);

}

void Run()    // 前进

{

digitalWrite(Right_motor_go,HIGH);  // 右电机前进

digitalWrite(Right_motor_back,LOW);

digitalWrite(Left_motor_go,HIGH);  // 左电机前进

digitalWrite(Left_motor_back,LOW);

digitalWrite(ENA,HIGH);

digitalWrite(ENB,HIGH);

}

void Break()        //刹车,停车

{

digitalWrite(Right_motor_go,LOW);

digitalWrite(Right_motor_back,LOW);

digitalWrite(Left_motor_go,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 loop(

Run();

}

3.红外遥控程序

#include

int RECV_PIN = 8;

IRrecv irrecv(RECV_PIN);

decode_results results;//结构声明

//==============================

int Left_motor_back=4;    //左电机后退(IN1)

int Left_motor_go=5;    //左电机前进(IN2)

int Right_motor_go=6;    // 右电机前进(IN3)

int Right_motor_back=7;    // 右电机后退(IN4)

int ENA=10;

int ENB=11;

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);////端口模式,输出

Serial.begin(9600);  //波特率9600

irrecv.enableIRIn(); // Start the receiver

}

void back()    // 前进

{

digitalWrite(Right_motor_go,LOW);  // 右电机前进

digitalWrite(Right_motor_back,HIGH);

digitalWrite(Left_motor_go,HIGH);  // 左电机前进

digitalWrite(Left_motor_back,LOW);

digitalWrite(ENA,HIGH);

digitalWrite(ENB,HIGH);

}

void brake()        //刹车,停车

{

digitalWrite(Right_motor_go,LOW);

digitalWrite(Right_motor_back,LOW);

digitalWrite(Left_motor_go,LOW);

digitalWrite(Left_motor_back,LOW);

}

void right()        //左转(左轮不动,右轮前进)

{

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 left()        //右转(右轮不动,左轮前进)

{

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 run()          //后退

{

digitalWrite(Right_motor_go,HIGH);  //右轮后退

digitalWrite(Right_motor_back,LOW);

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();

}

}

 4.蓝牙控制

#include //红外遥控库函数

#define BAUD_RATE 9600

int RECV_PIN = 8;//红外接收端口

IRrecv irrecv(RECV_PIN);

decode_results results;//结构声明

char mode = 'I';  //设置小车运行模式,默认红外模式

int Left_motor_back=4;    //左电机后退(IN1)

int Left_motor_go=5;    //左电机前进(IN2)

int Right_motor_go=6;    // 右电机前进(IN3)

int Right_motor_back=7;    // 右电机后退(IN4)

int ENA = 10;      //PWM输入A

int ENB = 11;      //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 7 (PWM)

pinMode(Right_motor_back,OUTPUT);// PIN 8 (PWM)

pinMode(ENA,OUTPUT);

pinMode(ENB,OUTPUT);

Serial.begin(BAUD_RATE);  //波特率9600

irrecv.enableIRIn(); // Start the receiver

delay(1000); // 给OpenMV一个启动的时间

}

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 back()    // 前进

{

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 Break()        //刹车,停车

{

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 right()        //左转(左轮不动,右轮前进)

{

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 left()        //右转(右轮不动,左轮前进)

{

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 Run()          //后退

{

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 loop()

{

if(Serial.available()>0){

char ch = Serial.read();

Serial.println(ch);

if(ch == '1'){

//前进

Run();

Serial.print("forward");

}else if(ch == '2'){

//后退

back();

Serial.print("backward");

}else if(ch == '3'){

//左转

left();

Serial.print("turnLeft");

}else if(ch == '4'){

//右转

right();

Serial.print("turnRight");

}else if(ch=='0'){

//停车

Break();

Serial.print("stop");

}

}

}

5.蓝牙与红外遥控的切换

#include //红外遥控库函数

#define BAUD_RATE 9600

int RECV_PIN = 8;//红外接收端口

IRrecv irrecv(RECV_PIN);

decode_results results;//结构声明

char mode = 'I';  //设置小车运行模式,默认红外模式

int Left_motor_back=4;    //左电机后退(IN1)

int Left_motor_go=5;    //左电机前进(IN2)

int Right_motor_go=6;    // 右电机前进(IN3)

int Right_motor_back=7;    // 右电机后退(IN4)

int ENA = 10;      //PWM输入A

int ENB = 11;      //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 7 (PWM)

pinMode(Right_motor_back,OUTPUT);// PIN 8 (PWM)

pinMode(ENA,OUTPUT);

pinMode(ENB,OUTPUT);

Serial.begin(BAUD_RATE);  //波特率9600

irrecv.enableIRIn(); // Start the receiver

delay(1000); // 给OpenMV一个启动的时间

}

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 back()    // 前进

{

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 Break()        //刹车,停车

{

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 right()        //左转(左轮不动,右轮前进)

{

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 left()        //右转(右轮不动,左轮前进)

{

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 Run()          //后退

{

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 loop()

{

if(Serial.available()>0){

ch = Serial.read();

Serial.println(ch);

if(ch == 'I'){

//红外模式

mode = 'I';

}

if(ch == 'B'){

//蓝牙模式

mode = 'B';

}

}

if(mode == 'I'){    //红外模式控制代码

Serial.println("IRremote Mode");

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

Break();

break;

default:

break;

}

irrecv.resume();

}

}

if(mode == 'B'){  //蓝牙模式控制代码

Serial.println("Blue Mode");

char ch1 = '0';

if(ch == '1'){

//前进

Run();

Serial.print("forward");

}else if(ch == '2'){

//后退

back();

Serial.print("backward");

}else if(ch == '3'){

//左转

left();

Serial.print("turnLeft");

}else if(ch == '4'){

//右转

right();

Serial.print("turnRight");

}else if(ch=='0'){

//停车

Break();

Serial.print("stop");

}}

6.红外循迹

#define L1 A0

#define L2 A1

#define L3 A2

#define L4 A3

int Left_motor_back=4;    //左电机后退(IN1)

int Left_motor_go=5;    //左电机前进(IN2)

int Right_motor_go=6;    // 右电机前进(IN3)

int Right_motor_back=7;    // 右电机后退(IN4)

int ENA = 10;      //PWM输入A

int ENB = 11;      //PWM输入B

int speed_default = 100;    //0-255之间,小车最低速度为70,最佳速度为100

char ch;

bool inverse_left=false;

bool inverse_right=false;

int a;

int b;

int c;

int d;

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 7 (PWM)

pinMode(Right_motor_back,OUTPUT);// PIN 8 (PWM)

pinMode(ENA,OUTPUT);

pinMode(ENB,OUTPUT);

pinMode(L1,OUTPUT);

pinMode(L2,OUTPUT);

pinMode(L3,OUTPUT);

pinMode(L4,OUTPUT);

Serial.begin(9600);  //波特率9600

delay(1000); // 给OpenMV一个启动的时间

}

void back()    // 前进

{

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 Break()        //刹车,停车

{

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 right()        //左转(左轮不动,右轮前进)

{

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 left()        //右转(右轮不动,左轮前进)

{

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 Run()          //后退

{

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 loop()

{

Serial.print("one");

Serial.println(analogRead(L1));

Serial.print("two");

Serial.println(analogRead(L2));

Serial.print("three");

Serial.println(analogRead(L3));

Serial.print("four");

Serial.println(analogRead(L4));

a=analogRead(L1);

b=analogRead(L2);

c=analogRead(L3);

d=analogRead(L4);

if(a==1000&&b==1000&&c==1000&&d==1000)

{

Run();

}

if(a==0&&b==0&&c==0&&d==0)

{

Break();

}

if(a<1000&&b<1000&&c>1000&&d>1000)

{

left();

}

if(a>1000&&b>1000&&c<1000&&d<1000)

{

right();

}

}

7.超声波避障


#include

int Left_motor_back=4;    //左电机后退(IN1)

int Left_motor_go=5;    //左电机前进(IN2)

int Right_motor_go=6;    // 右电机前进(IN3)

int Right_motor_back=7;    // 右电机后退(IN4)

int ENA=10;

int ENB=11;

Servo myServo;  //舵机

int inputPin=3;  // 定义超声波信号接收接口

int outputPin=2;  // 定义超声波信号发出接口

void setup() {

// put your setup code here, to run once:

//串口初始化

Serial.begin(9600);

//舵机引脚初始化

myServo.attach(9);

//初始化电机驱动IO为输出方式

pinMode(Left_motor_go,OUTPUT); // PIN 4 (PWM)

pinMode(Left_motor_back,OUTPUT); // PIN 5 (PWM)

pinMode(Right_motor_go,OUTPUT);// PIN 6 (PWM)

pinMode(Right_motor_back,OUTPUT);// PIN 7 (PWM)

pinMode(ENA,OUTPUT);

pinMode(ENB,OUTPUT);

//超声波控制引脚初始化

pinMode(inputPin, INPUT);

pinMode(outputPin, OUTPUT);

}

int getDistance()

{

digitalWrite(outputPin, LOW); // 使发出发出超声波信号接口低电平2μs

delayMicroseconds(2);

digitalWrite(outputPin, HIGH); // 使发出发出超声波信号接口高电平10μs,这里是至少10μs

delayMicroseconds(10);

digitalWrite(outputPin, LOW); // 保持发出超声波信号接口低电平

int distance = pulseIn(inputPin, HIGH); // 读出脉冲时间

distance= distance/58; // 将脉冲时间转化为距离(单位:厘米)

Serial.println(distance); //输出距离值

if (distance >=50)

{

//如果距离小于50厘米返回数据

return 50;

}//如果距离小于50厘米小灯熄灭

else

return distance;

}

void Run()    // 前进

{

digitalWrite(Right_motor_go,HIGH);  // 右电机前进

digitalWrite(Right_motor_back,LOW);

digitalWrite(Left_motor_go,HIGH);  // 左电机前进

digitalWrite(Left_motor_back,LOW);

}

void Break()        //刹车,停车

{

digitalWrite(Right_motor_go,LOW);

digitalWrite(Right_motor_back,LOW);

digitalWrite(Left_motor_go,LOW);

digitalWrite(Left_motor_go,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 loop() {

// put your main code here, to run repeatedly:

avoidance();

}

void avoidance()

{

int pos;

int dis[3];//距离

Run();

myServo.write(90);

dis[1]=getDistance(); //中间

digitalWrite(ENA,HIGH);

digitalWrite(ENB,HIGH);

if(dis[1]<30)

{

Break();

for (pos = 90; pos <= 150; pos += 1)

{

myServo.write(pos);              // tell servo to go to position in variable 'pos'

delay(15);                      // waits 15ms for the servo to reach the position

}

dis[2]=getDistance(); //左边

for (pos = 150; pos >= 30; pos -= 1)

{

myServo.write(pos);              // tell servo to go to position in variable 'pos'

delay(15);                      // waits 15ms for the servo to reach the position

if(pos==90)

dis[1]=getDistance(); //中间

}

dis[0]=getDistance();  //右边

for (pos = 30; pos <= 90; pos += 1)

{

myServo.write(pos);              // tell servo to go to position in variable 'pos'

delay(15);                      // waits 15ms for the servo to reach the position

}

if(dis[0]

{

//左转

left();

delay(500);

}

else  //右边距离障碍的距离比左边远

{

//右转

right();

delay(500);

}

}

}

 8 OpenMV模块程序

(1)OpenMv IDE代码:

#car.py

# Arduino 作为I2C主设备, OpenMV作为I2C从设备。

#

# 请把OpenMV和Arduino按照下面连线:

#

# OpenMV Cam Master I2C Data  (P5) - Arduino Uno Data  (A4)

# OpenMV Cam Master I2C Clock (P4) - Arduino Uno Clock (A5)

# OpenMV Cam Ground                - Arduino Ground

import pyb, ustruct

import ujson

from pyb import Pin, Timer

text = "Hello World!\n"

data = ustruct.pack("<%ds" % len(text), text)

# 使用 "ustruct" 来生成需要发送的数据包

# "<" 把数据以小端序放进struct中

# "%ds" 把字符串放进数据流,比如:"13s" 对应的 "Hello World!\n" (13 chars).

# 详见 https://docs.python.org/3/library/struct.html

# READ ME!!!

#

# 请理解,当您的OpenMV摄像头不是I2C主设备,所以不管是使用中断回调,

# 还是下方的轮循,都可能会错过响应发送数据给主机。当这种情况发生时,

# Arduino会获得NAK,并且不得不从OpenMV再次读数据。请注意,

# OpenMV和Arduino都不擅长解决I2C的错误。在OpenMV和Arduino中,

# 你可以通过释放I2C外设,再重新初始化外设,来恢复功能。

# OpenMV上的硬件I2C总线都是2

bus = pyb.I2C(2, pyb.I2C.SLAVE, addr=0x12)

bus.deinit() # 完全关闭设备

bus = pyb.I2C(2, pyb.I2C.SLAVE, addr=0x12)

print("Waiting for Arduino...")

# 请注意,为了正常同步工作,OpenMV Cam必须 在Arduino轮询数据之前运行此脚本。

# 否则,I2C字节帧会变得乱七八糟。所以,保持Arduino在reset状态,

# 直到OpenMV显示“Waiting for Arduino...”。

def run(left_speed, right_speed):

data = str(left_speed)+" "+str(right_speed)+" "

try:

#print(data)

bus.send(ustruct.pack("

try:

bus.send(data, timeout=10000) # 然后发送数据

print("Sent Data!") # 没有遇到错误时,会显示

except OSError as err:

pass # 不用担心遇到错误,会跳过

# 请注意,有3个可能的错误。超时错误(timeout error),

# 通用错误(general purpose error)或繁忙错误

#(busy error)。“err.arg[0]”的错误代码分别

# 为116,5,16。

except OSError as err:

pass # 不用担心遇到错误,会跳过

# 请注意,有3个可能的错误。超时错误(timeout error),

# 通用错误(general purpose error)或繁忙错误

#(busy error)。“err.arg[0]”的错误代码分别

# 为116,5,16。

#pid.py

from pyb import millis

from math import pi, isnan

class PID:

_kp = _ki = _kd = _integrator = _imax = 0

_last_error = _last_derivative = _last_t = 0

_RC = 1/(2 * pi * 20)

def __init__(self, p=0, i=0, d=0, imax=0):

self._kp = float(p)

self._ki = float(i)

self._kd = float(d)

self._imax = abs(imax)

self._last_derivative = float('nan')

def get_pid(self, error, scaler):

tnow = millis()

dt = tnow - self._last_t

output = 0

if self._last_t == 0 or dt > 1000:

dt = 0

self.reset_I()

self._last_t = tnow

delta_time = float(dt) / float(1000)

output += error * self._kp

if abs(self._kd) > 0 and dt > 0:

if isnan(self._last_derivative):

derivative = 0

self._last_derivative = 0

else:

derivative = (error - self._last_error) / delta_time

derivative = self._last_derivative + \

((delta_time / (self._RC + delta_time)) * \

(derivative - self._last_derivative))

self._last_error = error

self._last_derivative = derivative

output += self._kd * derivative

output *= scaler

if abs(self._ki) > 0 and dt > 0:

self._integrator += (error * self._ki) * scaler * delta_time

if self._integrator < -self._imax: self._integrator = -self._imax

elif self._integrator > self._imax: self._integrator = self._imax

output += self._integrator

return output

def reset_I(self):

self._integrator = 0

self._last_derivative = float('nan')

#main.py

# Blob Detection Example

#

# This example shows off how to use the find_blobs function to find color

# blobs in the image. This example in particular looks for dark green objects.

import sensor, image, time

import car

from pid import PID

# You may need to tweak the above settings for tracking green things...

# Select an area in the Framebuffer to copy the color settings.

sensor.reset() # Initialize the camera sensor.

sensor.set_pixformat(sensor.RGB565) # use RGB565.

sensor.set_framesize(sensor.QQVGA) # use QQVGA for speed.

sensor.skip_frames(10) # Let new settings take affect.

sensor.set_auto_whitebal(False) # turn this off.

clock = time.clock() # Tracks FPS.

# For color tracking to work really well you should ideally be in a very, very,

# very, controlled enviroment where the lighting is constant...

green_threshold  = (42, 80, 28, 127, -22, 55)  # 颜色阈值,不同物体需要修改

size_threshold = 2000              #小球距离

x_pid = PID(p=0.1, i=0.2, imax=30)    # 方向参数p

h_pid = PID(p=0.01, i=0.1, imax=100)    # 速度参数p

def find_max(blobs):                #找到视野中最大的色块,即最大的小球

max_size=0

for blob in blobs:

if blob[2]*blob[3] > max_size:

max_blob=blob

max_size = blob[2]*blob[3]

return max_blob

while(True):

clock.tick() # Track elapsed milliseconds between snapshots().

img = sensor.snapshot() # Take a picture and return the image.

blobs = img.find_blobs([green_threshold])

if blobs:

max_blob = find_max(blobs)

x_error = max_blob[5]-img.width()/2    #色块的外框的中心x坐标blob[5]

h_error = max_blob[2]*max_blob[3]-size_threshold

#色块的外框的宽度blob[2],色块的外框的高度blob[3]

print("x error: ", x_error)  #打印 x 轴误差  用于转弯

print("h error: ", h_error)  #打印 距离误差  用于速度

'''

for b in blobs:

# Draw a rect around the blob.

img.draw_rectangle(b[0:4]) # rect

img.draw_cross(b[5], b[6]) # cx, cy

'''

img.draw_rectangle(max_blob[0:4]) # rect

img.draw_cross(max_blob[5], max_blob[6]) # cx, cy

x_output=x_pid.get_pid(x_error,1)

h_output=h_pid.get_pid(h_error,1)    #h_error调整后的值

print("x_output",x_output)

print("h_output",h_output)

car.run(-h_output-x_output,-h_output+x_output)

print(-h_output-x_output,-h_output+x_output)

else:

car.run(0,0)

(2)Arduino程序

#include

#include

#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 = 8;//红外接收端口

IRrecv irrecv(RECV_PIN);

decode_results results;//结构声明

char mode = 'I';  //设置小车运行模式,默认红外模式

int Left_motor_back=4;    //左电机后退(IN1)

int Left_motor_go=5;    //左电机前进(IN2)

int Right_motor_go=6;    // 右电机前进(IN3)

int Right_motor_back=7;    // 右电机后退(IN4)

int ENA = 10;      //PWM输入A

int ENB = 11;      //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 7 (PWM)

pinMode(Right_motor_back,OUTPUT);// PIN 8 (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 back()    // 前进

{

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 Break()        //刹车,停车

{

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 right()        //左转(左轮不动,右轮前进)

{

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 left()        //右转(右轮不动,左轮前进)

{

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 Run()          //后退

{

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

Break();

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'){

//停车

Break();

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.音乐播放——歌曲《小宇》

#define Do 495

#define Re 556

#define Mi 624

#define Fa 661

#define Sol 742

#define La 833

#define Si 935

#define hDo 990

#define hRe 1112

#define hMi 1178

#define hFa 1322

#define hSol 1484

#define hLa 1665

#define hSi 1869

#define dDo 248

#define dRe 278

#define dMi 294

#define dFa 330

#define dSol 371

#define dLa 416

#define dSi 467

int pin=12; //自行选择作为输出的接口

int scale[]={Do,Re,Mi,Fa,Sol,La,Si,dDo,dRe,dMi,dFa,dSol,dLa,dSi,hDo,hRe,hMi,hFa,hSol,hLa,hSi};

int pu[100]={1,3,5,6,5,5,5,5,1,1,3,3,100,100,1,3,4,6,5,5,5,5,4,4,3,3,100,100,1,3,5,6,5,5,5,5,4,4,3,3,2,2,1,1,100,1,1,1,1,2,3,2,2,100,100};

void setup(){

pinMode(pin,OUTPUT);

}

void loop(){

for(int i=0;i<61;i++){

if(pu[i]!=100)

{

tone(pin,scale[pu[i]-1]);

}

else

noTone(pin);

delay(200);

noTone(pin);

delay(100);

}

delay(5000);

}

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,056评论 5 474
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,842评论 2 378
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 148,938评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,296评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,292评论 5 363
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,413评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,824评论 3 393
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,493评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,686评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,502评论 2 318
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,553评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,281评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,820评论 3 305
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,873评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,109评论 1 258
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,699评论 2 348
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,257评论 2 341

推荐阅读更多精彩内容