1.HW-096 4路循迹模块(红外发射器和红外接收器)
输出信号:TTL电平(可直接连接单片机I/0号,感应到传感器反射回来的红外光时,红指示灯亮,输出低电平;没有红外光时,指示灯不亮,输出高电平。)
2.L298N电机驱动模块双继电器驱动4线2相电机
1:驱动步进电机
驱动普通4线2相电机 接法如图所示
使能ENA ENB 之后
从IN1–IN4输入如下驱动时序,即可控制步进电机的转速和方向
3.arduino uno开发板
成品
1.循迹的原理
我们做的四驱小车前轮是不能转向的,那么怎么样才可以左右转呢?其实就是通过左右轮的差速就可以转弯,想要小车左转的话,那么 右轮的速度就要大于左轮的速度,想要小车向左转90°的话,差速就行不通了,这时候怎么办呢?当然也是有解决办法的啦!可以让左轮反转,右轮正转,小车就可以原地大幅度转弯了,反转和正转的数值越大,小车转弯的幅度也就越大。
2.判断情况
循迹模块的主要情况,其中0表示检测到白线,1表示检测到黑线
其中中间两路巡线是一直在黑线上,小车会直行,当任意一个出来,则小车会自动纠正,如果最外面的检测到黑线,则小车以更大速度纠正到正确黑线上面
以上为处理直线、小弯、直角、锐角的传感器状态分析。
3.调速代码
Left1_Speed、Left2_Speed控制左轮的速度,Right1_Speed、Right2_Speed控制右轮的速度,
4.循迹代码
当里面的两个循迹模块,有一个检测到黑线(0-1-0-0或0-0-1-0),说明小车轻微偏离轨道,这时候我们可以用差速,让小车小转弯,这样小车就摆正回来了
/**
* @par Copyright (C): 2010-2019, Shenzhen Yahboom Tech
* @file tracking.c
* @author Danny
* @version V1.0
* @date 2017.07.26
* @brief 巡线实验
* @details
* @par History 见如下说明
*
*/
int Left_motor_go = 8; //左电机前进 AIN1
int Left_motor_back = 7; //左电机后退 AIN2
int Right_motor_go = 2; //右电机前进 BIN1
int Right_motor_back = 4; //右电机后退 BIN2
int Left_motor_pwm = 6; //左电机控速 PWMA
int Right_motor_pwm = 5; //右电机控速 PWMB
int key = A0; //定义按键为arduino的模拟口A0
//循迹红外引脚定义
//TrackSensorLeftPin1 TrackSensorLeftPin2 TrackSensorRightPin1 TrackSensorRightPin2
// A2 A1 A3 A4
const int TrackSensorLeftPin1 = A2; //定义左边第一个循迹红外传感器引脚为A2
const int TrackSensorLeftPin2 = A1; //定义左边第二个循迹红外传感器引脚为A1
const int TrackSensorRightPin1 = A3; //定义右边第一个循迹红外传感器引脚为A3
const int TrackSensorRightPin2 = A4; //定义右边第二个循迹红外传感器引脚为A4
//定义各个循迹红外引脚采集的数据的变量
int TrackSensorLeftValue1;
int TrackSensorLeftValue2;
int TrackSensorRightValue1;
int TrackSensorRightValue2;
/**
* Function setup
* @author Danny
* @date 2017.07.25
* @brief 初始化配置
* @param[in] void
* @retval void
* @par History 无
*/
void setup()
{
//初始化电机驱动IO口为输出方式
pinMode(Left_motor_go, OUTPUT);
pinMode(Left_motor_back, OUTPUT);
pinMode(Right_motor_go, OUTPUT);
pinMode(Right_motor_back, OUTPUT);
//定义按键接口为输入接口
pinMode(key, INPUT);
//定义四路循迹红外传感器为输入接口
pinMode(TrackSensorLeftPin1, INPUT);
pinMode(TrackSensorLeftPin2, INPUT);
pinMode(TrackSensorRightPin1, INPUT);
pinMode(TrackSensorRightPin2, INPUT);
//按键初始化为高电平
digitalWrite(key, HIGH);
//四路循迹红外传感器初始化为高电平
digitalWrite(TrackSensorLeftPin1, HIGH);
digitalWrite(TrackSensorLeftPin2, HIGH);
digitalWrite(TrackSensorRightPin1, HIGH);
digitalWrite(TrackSensorRightPin2, HIGH);
//调用按键扫描函数
key_scan();
}
/**
* Function run
* @author Danny
* @date 2017.07.26
* @brief 小车前进
* @param[in1] left_speed:左轮速度
* @param[in2] right_speed:右轮速度
* @param[out] void
* @retval void
* @par History 无
*/
void run(int left_speed, int right_speed)
{
//左电机前进
digitalWrite(Left_motor_go, HIGH); //左电机前进使能
digitalWrite(Left_motor_back, LOW); //左电机后退禁止
analogWrite(Left_motor_pwm, left_speed );
//右电机前进
digitalWrite(Right_motor_go, HIGH); //右电机前进使能
digitalWrite(Right_motor_back, LOW); //右电机后退禁止
analogWrite(Right_motor_pwm, right_speed);
}
/**
* Function brake
* @author Danny
* @date 2017.07.25
* @brief 小车刹车
* @param[in] time:延时时间
* @param[out] void
* @retval void
* @par History 无
*/
void brake(int time)
{
digitalWrite(Left_motor_go, LOW);
digitalWrite(Left_motor_back, LOW);
digitalWrite(Right_motor_go, LOW);
digitalWrite(Right_motor_back, LOW);
delay(time * 100);
}
/**
* Function left
* @author Danny
* @date 2017.07.25
* @brief 小车左转(左轮不动,右轮前进)
* @param[in1] left_speed:左轮速度
* @param[in2] right_speed:右轮速度
* @param[out] void
* @retval void
* @par History 无
*/
void left(int left_speed, int right_speed)
{
//左电机停止
digitalWrite(Left_motor_go, LOW); //左电机前进禁止
digitalWrite(Left_motor_back, LOW); //左电机后退禁止
analogWrite(Left_motor_pwm, left_speed);
//右电机前进
digitalWrite(Right_motor_go, HIGH); //右电机前进使能
digitalWrite(Right_motor_back, LOW); //右电机后退禁止
analogWrite(Right_motor_pwm, right_speed);
}
/**
* Function right
* @author Danny
* @date 2017.07.25
* @brief 小车右转(右轮不动,左轮前进)
* @param[in1] left_speed:左轮速度
* @param[in2] right_speed:右轮速度
* @param[out] void
* @retval void
* @par History 无
*/
void right(int left_speed, int right_speed)
{
//左电机前进
digitalWrite(Left_motor_go, HIGH); //左电机前进使能
digitalWrite(Left_motor_back, LOW); //左电机后退禁止
analogWrite(Left_motor_pwm, left_speed);
//右电机停止
digitalWrite(Right_motor_go, LOW); //右电机前进禁止
digitalWrite(Right_motor_back, LOW); //右电机后退禁止
analogWrite(Right_motor_pwm, right_speed);
}
/**
* Function spin_left
* @author Danny
* @date 2017.07.25
* @brief 小车原地左转(左轮后退,右轮前进)
* @param[in1] left_speed:左轮速度
* @param[in2] right_speed:右轮速度
* @param[out] void
* @retval void
* @par History 无
*/
void spin_left(int left_speed, int right_speed)
{
//左电机后退
digitalWrite(Left_motor_go, LOW); //左电机前进禁止
digitalWrite(Left_motor_back, HIGH); //左电机后退使能
analogWrite(Left_motor_pwm, left_speed);
//右电机前进
digitalWrite(Right_motor_go, HIGH); //右电机前进使能
digitalWrite(Right_motor_back, LOW); //右电机后退禁止
analogWrite(Right_motor_pwm, right_speed);
}
/**
* Function spin_right
* @author Danny
* @date 2017.07.25
* @brief 小车原地右转(右轮后退,左轮前进)
* @param[in1] left_speed:左轮速度
* @param[in2] right_speed:右轮速度
* @param[out] void
* @retval void
* @par History 无
*/
void spin_right(int left_speed, int right_speed)
{
//左电机前进
digitalWrite(Left_motor_go, HIGH); //左电机前进使能
digitalWrite(Left_motor_back, LOW); //左电机后退禁止
analogWrite(Left_motor_pwm, left_speed);
//右电机后退
digitalWrite(Right_motor_go, LOW); //右电机前进禁止
digitalWrite(Right_motor_back, HIGH); //右电机后退使能
analogWrite(Right_motor_pwm, right_speed);
}
/**
* Function back
* @author Danny
* @date 2017.07.25
* @brief 小车后退
* @param[in] time:延时时间
* @param[out] void
* @retval void
* @par History 无
*/
void back(int time)
{
//左电机后退
digitalWrite(Left_motor_go, LOW); //左电机前进禁止
digitalWrite(Left_motor_back, HIGH); //左电机后退使能
analogWrite(Left_motor_pwm, 40);
//右电机后退
digitalWrite(Right_motor_go, LOW); //右电机前进禁止
digitalWrite(Right_motor_back, HIGH); //右电机后退使能
analogWrite(Right_motor_pwm, 40);
delay(time );
}
/**
* Function key_scan
* @author Danny
* @date 2017.07.25
* @brief 按键检测(包含软件按键去抖)
* @param[in] void
* @param[out] void
* @retval void
* @par History 无
*/
void key_scan()
{
while (digitalRead(key)); //当按键没有被按下一直循环
while (!digitalRead(key)) //当按键被按下时
{
delay(10); //延时10ms
if (digitalRead(key) == LOW)//第二次判断按键是否被按下
{
delay(100);
while (!digitalRead(key)); //判断按键是否被松开
}
}
}
/**
* Function loop
* @author Danny
* @date 2017.07.25
* @brief 先调用setup初始化配置里面的按键扫描函数,
* 循迹模式开启
* @param[in] void
* @retval void
* @par History 无
*/
void loop()
{
//检测到黑线时循迹模块相应的指示灯亮,端口电平为LOW
//未检测到黑线时循迹模块相应的指示灯灭,端口电平为HIGH
TrackSensorLeftValue1 = digitalRead(TrackSensorLeftPin1);
TrackSensorLeftValue2 = digitalRead(TrackSensorLeftPin2);
TrackSensorRightValue1 = digitalRead(TrackSensorRightPin1);
TrackSensorRightValue2 = digitalRead(TrackSensorRightPin2);
//四路循迹引脚电平状态
// 0 0 X 0
// 1 0 X 0
// 0 1 X 0
//以上6种电平状态时小车原地右转,速度为250,延时80ms
//处理右锐角和右直角的转动
if ( (TrackSensorLeftValue1 == LOW || TrackSensorLeftValue2 == LOW) && TrackSensorRightValue2 == LOW)
{
spin_right(250, 250);
delay(80);
}
//四路循迹引脚电平状态
// 0 X 0 0
// 0 X 0 1
// 0 X 1 0
//处理左锐角和左直角的转动
else if ( TrackSensorLeftValue1 == LOW && (TrackSensorRightValue1 == LOW || TrackSensorRightValue2 == LOW))
{
spin_left(250, 250);
delay(80);
}
// 0 X X X
//最左边检测到
else if ( TrackSensorLeftValue1 == LOW)
{
spin_left(150, 150);
//delay(2);
}
// X X X 0
//最右边检测到
else if ( TrackSensorRightValue2 == LOW )
{
spin_right(150, 150);
//delay(2);
}
//四路循迹引脚电平状态
// X 0 1 X
//处理左小弯
else if ( TrackSensorLeftValue2 == LOW && TrackSensorRightValue1 == HIGH)
{
left(0, 220);
}
//四路循迹引脚电平状态
// X 1 0 X
//处理右小弯
else if (TrackSensorLeftValue2 == HIGH && TrackSensorRightValue1 == LOW)
{
right(220, 0);
}
//四路循迹引脚电平状态
// X 0 0 X
//处理直线
else if (TrackSensorLeftValue2 == LOW && TrackSensorRightValue1 == LOW)
{
run(255, 255);
}
//当为1 1 1 1时小车保持上一个小车运行状态
}
/**
* @par Copyright (C): 2010-2019, Shenzhen Yahboom Tech
* @file tracking.c
* @author Danny
* @version V1.0
* @date 2017.07.26
* @brief 巡线实验
* @details
* @par History 见如下说明
*
*/
int Left_motor_go = 8; //左电机前进 AIN1
int Left_motor_back = 7; //左电机后退 AIN2
int Right_motor_go = 2; //右电机前进 BIN1
int Right_motor_back = 4; //右电机后退 BIN2
int Left_motor_pwm = 6; //左电机控速 PWMA
int Right_motor_pwm = 5; //右电机控速 PWMB
int key = A0; //定义按键为arduino的模拟口A0
//循迹红外引脚定义
//TrackSensorLeftPin1 TrackSensorLeftPin2 TrackSensorRightPin1 TrackSensorRightPin2
// A2 A1 A3 A4
const int TrackSensorLeftPin1 = A2; //定义左边第一个循迹红外传感器引脚为A2
const int TrackSensorLeftPin2 = A1; //定义左边第二个循迹红外传感器引脚为A1
const int TrackSensorRightPin1 = A3; //定义右边第一个循迹红外传感器引脚为A3
const int TrackSensorRightPin2 = A4; //定义右边第二个循迹红外传感器引脚为A4
//定义各个循迹红外引脚采集的数据的变量
int TrackSensorLeftValue1;
int TrackSensorLeftValue2;
int TrackSensorRightValue1;
int TrackSensorRightValue2;
/**
* Function setup
* @author Danny
* @date 2017.07.25
* @brief 初始化配置
* @param[in] void
* @retval void
* @par History 无
*/
void setup()
{
//初始化电机驱动IO口为输出方式
pinMode(Left_motor_go, OUTPUT);
pinMode(Left_motor_back, OUTPUT);
pinMode(Right_motor_go, OUTPUT);
pinMode(Right_motor_back, OUTPUT);
//定义按键接口为输入接口
pinMode(key, INPUT);
//定义四路循迹红外传感器为输入接口
pinMode(TrackSensorLeftPin1, INPUT);
pinMode(TrackSensorLeftPin2, INPUT);
pinMode(TrackSensorRightPin1, INPUT);
pinMode(TrackSensorRightPin2, INPUT);
//按键初始化为高电平
digitalWrite(key, HIGH);
//四路循迹红外传感器初始化为高电平
digitalWrite(TrackSensorLeftPin1, HIGH);
digitalWrite(TrackSensorLeftPin2, HIGH);
digitalWrite(TrackSensorRightPin1, HIGH);
digitalWrite(TrackSensorRightPin2, HIGH);
//调用按键扫描函数
key_scan();
}
/**
* Function run
* @author Danny
* @date 2017.07.26
* @brief 小车前进
* @param[in1] left_speed:左轮速度
* @param[in2] right_speed:右轮速度
* @param[out] void
* @retval void
* @par History 无
*/
void run(int left_speed, int right_speed)
{
//左电机前进
digitalWrite(Left_motor_go, HIGH); //左电机前进使能
digitalWrite(Left_motor_back, LOW); //左电机后退禁止
analogWrite(Left_motor_pwm, left_speed );
//右电机前进
digitalWrite(Right_motor_go, HIGH); //右电机前进使能
digitalWrite(Right_motor_back, LOW); //右电机后退禁止
analogWrite(Right_motor_pwm, right_speed);
}
/**
* Function brake
* @author Danny
* @date 2017.07.25
* @brief 小车刹车
* @param[in] time:延时时间
* @param[out] void
* @retval void
* @par History 无
*/
void brake(int time)
{
digitalWrite(Left_motor_go, LOW);
digitalWrite(Left_motor_back, LOW);
digitalWrite(Right_motor_go, LOW);
digitalWrite(Right_motor_back, LOW);
delay(time * 100);
}
/**
* Function left
* @author Danny
* @date 2017.07.25
* @brief 小车左转(左轮不动,右轮前进)
* @param[in1] left_speed:左轮速度
* @param[in2] right_speed:右轮速度
* @param[out] void
* @retval void
* @par History 无
*/
void left(int left_speed, int right_speed)
{
//左电机停止
digitalWrite(Left_motor_go, LOW); //左电机前进禁止
digitalWrite(Left_motor_back, LOW); //左电机后退禁止
analogWrite(Left_motor_pwm, left_speed);
//右电机前进
digitalWrite(Right_motor_go, HIGH); //右电机前进使能
digitalWrite(Right_motor_back, LOW); //右电机后退禁止
analogWrite(Right_motor_pwm, right_speed);
}
/**
* Function right
* @author Danny
* @date 2017.07.25
* @brief 小车右转(右轮不动,左轮前进)
* @param[in1] left_speed:左轮速度
* @param[in2] right_speed:右轮速度
* @param[out] void
* @retval void
* @par History 无
*/
void right(int left_speed, int right_speed)
{
//左电机前进
digitalWrite(Left_motor_go, HIGH); //左电机前进使能
digitalWrite(Left_motor_back, LOW); //左电机后退禁止
analogWrite(Left_motor_pwm, left_speed);
//右电机停止
digitalWrite(Right_motor_go, LOW); //右电机前进禁止
digitalWrite(Right_motor_back, LOW); //右电机后退禁止
analogWrite(Right_motor_pwm, right_speed);
}
/**
* Function spin_left
* @author Danny
* @date 2017.07.25
* @brief 小车原地左转(左轮后退,右轮前进)
* @param[in1] left_speed:左轮速度
* @param[in2] right_speed:右轮速度
* @param[out] void
* @retval void
* @par History 无
*/
void spin_left(int left_speed, int right_speed)
{
//左电机后退
digitalWrite(Left_motor_go, LOW); //左电机前进禁止
digitalWrite(Left_motor_back, HIGH); //左电机后退使能
analogWrite(Left_motor_pwm, left_speed);
//右电机前进
digitalWrite(Right_motor_go, HIGH); //右电机前进使能
digitalWrite(Right_motor_back, LOW); //右电机后退禁止
analogWrite(Right_motor_pwm, right_speed);
}
/**
* Function spin_right
* @author Danny
* @date 2017.07.25
* @brief 小车原地右转(右轮后退,左轮前进)
* @param[in1] left_speed:左轮速度
* @param[in2] right_speed:右轮速度
* @param[out] void
* @retval void
* @par History 无
*/
void spin_right(int left_speed, int right_speed)
{
//左电机前进
digitalWrite(Left_motor_go, HIGH); //左电机前进使能
digitalWrite(Left_motor_back, LOW); //左电机后退禁止
analogWrite(Left_motor_pwm, left_speed);
//右电机后退
digitalWrite(Right_motor_go, LOW); //右电机前进禁止
digitalWrite(Right_motor_back, HIGH); //右电机后退使能
analogWrite(Right_motor_pwm, right_speed);
}
/**
* Function back
* @author Danny
* @date 2017.07.25
* @brief 小车后退
* @param[in] time:延时时间
* @param[out] void
* @retval void
* @par History 无
*/
void back(int time)
{
//左电机后退
digitalWrite(Left_motor_go, LOW); //左电机前进禁止
digitalWrite(Left_motor_back, HIGH); //左电机后退使能
analogWrite(Left_motor_pwm, 40);
//右电机后退
digitalWrite(Right_motor_go, LOW); //右电机前进禁止
digitalWrite(Right_motor_back, HIGH); //右电机后退使能
analogWrite(Right_motor_pwm, 40);
delay(time );
}
/**
* Function key_scan
* @author Danny
* @date 2017.07.25
* @brief 按键检测(包含软件按键去抖)
* @param[in] void
* @param[out] void
* @retval void
* @par History 无
*/
void key_scan()
{
while (digitalRead(key)); //当按键没有被按下一直循环
while (!digitalRead(key)) //当按键被按下时
{
delay(10); //延时10ms
if (digitalRead(key) == LOW)//第二次判断按键是否被按下
{
delay(100);
while (!digitalRead(key)); //判断按键是否被松开
}
}
}
/**
* Function loop
* @author Danny
* @date 2017.07.25
* @brief 先调用setup初始化配置里面的按键扫描函数,
* 循迹模式开启
* @param[in] void
* @retval void
* @par History 无
*/
void loop()
{
//检测到黑线时循迹模块相应的指示灯亮,端口电平为LOW
//未检测到黑线时循迹模块相应的指示灯灭,端口电平为HIGH
TrackSensorLeftValue1 = digitalRead(TrackSensorLeftPin1);
TrackSensorLeftValue2 = digitalRead(TrackSensorLeftPin2);
TrackSensorRightValue1 = digitalRead(TrackSensorRightPin1);
TrackSensorRightValue2 = digitalRead(TrackSensorRightPin2);
//四路循迹引脚电平状态
// 0 0 X 0
// 1 0 X 0
// 0 1 X 0
//以上6种电平状态时小车原地右转,速度为250,延时80ms
//处理右锐角和右直角的转动
if ( (TrackSensorLeftValue1 == LOW || TrackSensorLeftValue2 == LOW) && TrackSensorRightValue2 == LOW)
{
spin_right(250, 250);
delay(80);
}
//四路循迹引脚电平状态
// 0 X 0 0
// 0 X 0 1
// 0 X 1 0
//处理左锐角和左直角的转动
else if ( TrackSensorLeftValue1 == LOW && (TrackSensorRightValue1 == LOW || TrackSensorRightValue2 == LOW))
{
spin_left(250, 250);
delay(80);
}
// 0 X X X
//最左边检测到
else if ( TrackSensorLeftValue1 == LOW)
{
spin_left(150, 150);
//delay(2);
}
// X X X 0
//最右边检测到
else if ( TrackSensorRightValue2 == LOW )
{
spin_right(150, 150);
//delay(2);
}
//四路循迹引脚电平状态
// X 0 1 X
//处理左小弯
else if ( TrackSensorLeftValue2 == LOW && TrackSensorRightValue1 == HIGH)
{
left(0, 220);
}
//四路循迹引脚电平状态
// X 1 0 X
//处理右小弯
else if (TrackSensorLeftValue2 == HIGH && TrackSensorRightValue1 == LOW)
{
right(220, 0);
}
//四路循迹引脚电平状态
// X 0 0 X
//处理直线
else if (TrackSensorLeftValue2 == LOW && TrackSensorRightValue1 == LOW)
{
run(255, 255);
}
//当为1 1 1 1时小车保持上一个小车运行状态
}
转自:
https://blog.csdn.net/m0_47525528/article/details/129271458