Arduino传感器(L298N、超声波传感器、舵机、光电传感器、灰度传感器、蓝牙模块)

本文介绍了如何使用L298N驱动电机,并配合超声波、舵机、光电和灰度传感器进行交互,提供Arduino代码示例。通过串口通信展示传感器数据和实时操作控制。
本文为作者学习笔记
欢迎交流讨论,喜欢的话点个赞吧

欢迎去看我的主页: NicholasYe’s Hompage.


L298N电机驱动

const int negR=4;//右负极
const int posR=5;//右正极
const int negL=6;//左负极
const int posL=7;//左正极
const int pwmR=9;//右轮pwm
const int pwmL=10;//左轮pwm


//设置初值
void setup()
{
  pinMode(posR,OUTPUT);//引脚4
  pinMode(negR,OUTPUT);//引脚5
  pinMode(posL,OUTPUT);//引脚6
  pinMode(negL,OUTPUT);//引脚7
  pinMode(pwmR,OUTPUT);//引脚9
  pinMode(negL,OUTPUT);//引脚10
}

//主循环
void loop()
{
  forward(200,200);
  delay(2000);
  pause(0,0);
  delay(2000);
  back(200,200);
  delay(2000);
  pause(0,0);
  delay(2000);
}

//前进函数
void forward(byte RmotorSpeed,byte LmotorSpeed)
{
  analogWrite(pwmR,RmotorSpeed);//右轮转速
  analogWrite(pwmL,LmotorSpeed);//左轮转速
  digitalWrite(posR,HIGH);//右轮正转
  digitalWrite(negR,LOW);
  digitalWrite(posL,LOW);//左轮反转
  digitalWrite(negL,HIGH);
}

//后退函数
void back(byte RmotorSpeed,byte LmotorSpeed)
{
  analogWrite(pwmR,RmotorSpeed);//右轮转速
  analogWrite(pwmL,LmotorSpeed);//左轮转速
  digitalWrite(posR,LOW);//右轮反转
  digitalWrite(negR,HIGH);
  digitalWrite(posL,HIGH);//左轮正转
  digitalWrite(negL,LOW);
}

//停止函数
void pause(byte RmotorSpeed,byte LmotorSpeed)
{
  analogWrite(pwmR,RmotorSpeed);//右轮转速
  analogWrite(pwmL,LmotorSpeed);//左轮转速
  digitalWrite(posR,LOW);//右轮停止
  digitalWrite(negR,LOW);
  digitalWrite(posL,LOW);//左轮停止
  digitalWrite(negL,LOW);
}

//右转
void right(byte RmotorSpeed,byte LmotorSpeed)
{
  analogWrite(pwmR,RmotorSpeed);//右轮转速
  analogWrite(pwmL,LmotorSpeed);//左轮转速
  digitalWrite(posR,LOW);//右轮停止
  digitalWrite(negR,LOW);
  digitalWrite(posL,LOW);//左轮反转
  digitalWrite(negL,HIGH);
}

//左转
void left(byte RmotorSpeed,byte LmotorSpeed)
{
  analogWrite(pwmR,RmotorSpeed);//右轮转速
  analogWrite(pwmL,LmotorSpeed);//左轮转速
  digitalWrite(posR,HIGH);//右轮正转
  digitalWrite(negR,LOW);
  digitalWrite(posL,LOW);//左轮停止
  digitalWrite(negL,LOW);
}

超声波传感器

const int trig =4;//引脚
const int echo =5;

float distance;//返回数值

void setup()
{
  Serial.begin(9600);//串口调试
  
  pinMode(trig,OUTPUT);//针脚输出
  pinMode(echo,INPUT);//针脚输入
  
}

void loop()
{
  //向引脚发送10us的高电平
  digitalWrite(trig,LOW);
  delayMicroseconds(2);
  digitalWrite(trig,HIGH);
  delayMicroseconds(10);
  digitalWrite(trig,LOW);

  //测算距离
  distance = (pulseIn(echo,HIGH)/58.00);
  
  //串口打印
  Serial.print(distance);
  Serial.print("cm");
  Serial.println();
  
  //延迟1000ms
  delay(1000);
}

舵机

#include <Servo.h>

Servo myservo;  // 定义Servo对象来控制
int pos = 0;    // 角度存储变量

void setup() 
{
    myservo.attach(9);  // 控制线连接数字9
}

void loop() 
{
    for (pos = 0; pos <= 180; pos++) { // 0°到180°
      // in steps of 1 degree
        myservo.write(pos);              // 舵机角度写入
        delay(5);                       // 等待转动到指定角度
    }
    for (pos = 180; pos >= 0; pos--) { // 从180°到0°
        myservo.write(pos);              // 舵机角度写入
        delay(5);                       // 等待转动到指定角度
    }
}

舵机红色线接开发板5V,棕色线接开发板GND,橙色信号线接开发板数字引脚

#include <Servo.h>

Servo myservo;  // 定义Servo对象来控制
int pos = 180;    // 角度存储变量

void setup() 
{
    myservo.attach(7);  // 控制线连接数字7
    myservo.write(90);
    delay(2000);
}

void loop() 
{
  pos=pos-180;
  myservo.write(pos);
  delay(3000);
  pos=pos+360;
  myservo.write(pos);
  delay(3000);
  pos=pos-180;
  myservo.write(pos);
  delay(3000);
}

image

#include <Servo.h>

Servo myservo;  // 定义Servo对象来控制
int pos = 180;    // 角度存储变量

void setup() 
{
    myservo.attach(9);  // 控制线连接数字7
    myservo.write(0);
    delay(2000);
}

void loop() 
{
  myservo.write(0);
  delay(1500);
  myservo.write(200);
  delay(1500);
  myservo.write(0);
  delay(1500);
  myservo.write(200);
  delay(1500);
  myservo.write(0);
  delay(1500);
}

image


光电传感器

int light1=3;//光电传感器
int v_light1;//光电传感器返回数值

void setup()
{
  pinMode(LED_BUILTIN, OUTPUT);//LED闪烁 
  Serial.begin(9600);
}

//主循环
void loop()
{
  light_test();
}

//传感器检测
void light_test()
{
  //读取光电传感器数值
  int value=0;
  v_light1=digitalRead(light1);
  value=v_light1;
  Serial.print(value);
  Serial.println();
  //条件判断
  if(value==0)
  {
      digitalWrite(LED_BUILTIN, HIGH);   // turn the LED on (HIGH is the voltage level)
  }
  else
  {
      digitalWrite(LED_BUILTIN, LOW);   // turn the LED on (HIGH is the voltage level)
  }
}

棕色正极蓝色负极黑色信号输出

灯亮(距离近)时digital.read()为0(LOW)

灯灭(距离远)时digital.read()为1(HIGH)

HIGH和LOW是系统常量,定义分别是1(高)0(低),还有,=是赋值,==是判断


灰度传感器


const int gray1 = A1;//灰度传感器GR1
int graynum1;//灰度传感器返回数值
int* level = NULL;//灰度传感器数值的指针

// the setup function runs once when you press reset or power the board
void setup()
{
	Serial.begin(9600);//开启9600端口
	Serial.println("Senesor:");
	pinMode(gray1, INPUT);//灰度传感器GR4

}

// the loop function runs over and over again until power down or reset
void loop() 
{
	Gray();
	Serial.print(*level);
	Serial.println();
}

//灰度传感器Gray(指针写法) 
int Gray()
{
	graynum4 = analogRead(4);
	level = &graynum4;
}

灰度传感器连续快速返回数值,因此,在不是很稳定的情况下,建议配合快速排序函数取中值一同使用

const int gray1 = A0;//灰度传感器GR1(车左前)
int graynum1;//灰度传感器返回数值
int* level1 = NULL;//存储灰度传感器数值graynum的指针

void setup()
{
  Serial.begin(9600);
  pinMode(gray1, INPUT);//灰度传感器GR1
  pinMode(LED_BUILTIN, OUTPUT);//LED闪烁 
}


void loop()
{
  int gray_level1[21] = {0};
  for (int m = 0; m < 21; m++)
    {
        Gray1();
        gray_level1[m] = *level1;
    }
  int median1 = quickSort(gray_level1, 0, 20);
  Serial.print(median1);
  Serial.println();
  
}


//取中值函数
int quickSortPartition(int s[], int l, int r) {
    //Swap(s[l], s[(l + r) / 2]); //若以中间数为基准,则先将中间的这个数和第一个数交换即可
    int i = l, j = r, x = s[l]; //将最左元素记录到x中
    while (i < j)
    {
        // 从右向左找第一个<x的数
        // 无需考虑下标越界
        while (i < j && s[j] >= x)
            j--;
        if (i < j)
            s[i++] = s[j]; //直接替换掉最左元素(已在x中存有备份)

        // 从左向右找第一个>x的数
        while (i < j && s[i] <= x)
            i++;
        if (i < j)
            //替换掉最右元素(已在最左元素中有备份)
            //最左元素一定被覆盖过,若没有,则表明右侧所有元素都>x,那么算法将终止
            s[j--] = s[i];
    }
    s[i] = x;  //i的位置放了x,所以其左侧都小于x,右侧y都大于x
    return i;
}

int quickSort(int s[], int l, int r)
{
    //数组左界<右界才有意义,否则说明都已排好,直接返回即可
    if (l >= r) {
        return s[10];
    }

    // 划分,返回基准点位置
    int i = quickSortPartition(s, l, r);

    // 递归处理左右两部分,i处为分界点,不用管i了
    quickSort(s, l, i - 1);
    quickSort(s, i + 1, r);

    return s[10];
}

//灰度传感器Gray1
int Gray1()
{
    graynum1 = analogRead(0);
    level1 = &graynum1;
    return graynum1;
}


红外ToF传感器


/*
This example takes range measurements with the VL53L1X and displays additional 
details (status and signal/ambient rates) for each measurement, which can help
you determine whether the sensor is operating normally and the reported range is
valid. The range is in units of mm, and the rates are in units of MCPS (mega 
counts per second).
*/

#include <Wire.h>
#include <VL53L1X.h>

VL53L1X sensor;

void setup()
{
  Serial.begin(115200);
  Wire.begin();
  Wire.setClock(400000); // use 400 kHz I2C

  sensor.setTimeout(500);
  if (!sensor.init())
  {
    Serial.println("Failed to detect and initialize sensor!");
    while (1);
  }
  
  // Use long distance mode and allow up to 50000 us (50 ms) for a measurement.
  // You can change these settings to adjust the performance of the sensor, but
  // the minimum timing budget is 20 ms for short distance mode and 33 ms for
  // medium and long distance modes. See the VL53L1X datasheet for more
  // information on range and timing limits.
  sensor.setDistanceMode(VL53L1X::Long);
  sensor.setMeasurementTimingBudget(50000);

  // Start continuous readings at a rate of one measurement every 50 ms (the
  // inter-measurement period). This period should be at least as long as the
  // timing budget.
  sensor.startContinuous(50);
}

void loop()
{
  sensor.read();
  
  Serial.print("range: ");
  Serial.print(sensor.ranging_data.range_mm);
  Serial.print("\tstatus: ");
  Serial.print(VL53L1X::rangeStatusToString(sensor.ranging_data.range_status));
  Serial.print("\tpeak signal: ");
  Serial.print(sensor.ranging_data.peak_signal_count_rate_MCPS);
  Serial.print("\tambient: ");
  Serial.print(sensor.ranging_data.ambient_count_rate_MCPS);
  
  Serial.println();
}

串口函数

void setup()
{
	Serial.begin(9600);
	Serial.println("Senesor:");
}

void loop() 
{
	Serial.print();
	Serial.println();
}

若有需要同时输出多个数值:

//以灰度传感器为例
Serial.print(XHEADER + analogRead(xpin) + TAB);
Serial.print(YHEADER + analogRead(ypin) + TAB);
Serial.print(ZHEADER + analogRead(zpin));
Serial.println();
delay(200);

或者

Serial.print(((float)x - zero_G)/scale);
Serial.print("\t");
Serial.print(((float)y - zero_G)/scale);
Serial.print("\t");
Serial.print(((float)z - zero_G)/scale);
Serial.print("\n"); 

蓝牙模块

#include <SoftwareSerial.h>

SoftwareSerial mySerial(10, 11); //定义RX和TX接口

void setup() {
  //开启USB连线的串口通信
  Serial.begin(57600);
  Serial.println("Goodnight moon!");

  //开启蓝牙模块的串口通信
  mySerial.begin(4800);
  mySerial.println("Hello, world?");
}

void loop() { 
  //mySerial.available()检测蓝牙模块是否正常工作
  //mySerial.read()读取蓝牙模块传回的数据
  if (mySerial.available()) 
  {
    //将蓝牙模块传回的数值打印在USB连接的电脑串口上
    Serial.write(mySerial.read());
  }
}



请在转载文章过程中明确标注文章出处!尊重原创,尊重知识产权,谢谢!

<think>好的,我需要帮助用户了解如何使用灰度传感器实现循迹停车功能。首先,我得回顾用户提供的引用内容,看看有没有相关的信息。引用[1]提到PID算法在循迹小车中的应用,包括硬件选型和代码实现。引用[2]讨论了结合BANGBANG算法和积分分离PI控制,以及舵机的PD控制,这对速度和方向的控制可能有参考价值。引用[3]介绍了灰度传感器的工作原理和电源需求。引用[4]则详细讲解了PID循迹算法的实际应用案例。 首先,用户的问题涉及循迹和停车两个部分。循迹部分需要使用灰度传感器检测路径,通常采用PID算法来控制方向,如引用[1]和[4]所述。停车功能可能需要检测特定的标记或距离,比如使用传感器识别停车线或通过编码器计算距离。 接下来,我需要整合这些信息。硬件方面,需要灰度传感器阵列、电机驱动、微控制器(如Arduino或STM32),可能还需要编码器或超声波传感器来检测停车点。软件部分,PID算法用于循迹,停车可能需要条件判断,比如当所有传感器都检测到黑色时停车,或者通过编码器累积脉冲数达到预定值时停止电机。 还需要考虑停车时的控制策略,比如减速停止或立即刹车,这可能涉及到电机的PID参数调整,如引用[2]中的积分分离PI控制。此外,滤波处理也很重要,避免传感器噪声误触发停车,引用[1]提到过增加滤波处理。 可能遇到的问题包括如何准确检测停车线,尤其是在弯道时误识别。解决方法可能是结合多传感器数据,或者使用状态机控制,如引用[2]中的分段控制思想,区分循迹和停车状态。 最后,生成相关问题时要覆盖硬件、算法、优化和应用场景等方面,确保用户能全面理解实现方法。</think>### 如何用灰度传感器实现循迹停车功能? #### 一、实现原理 1. **循迹基础** 灰度传感器通过检测地面反射光的强度差异(如黑色停车线与浅色地面)生成电信号,反馈机器人当前位置与路径的偏差[^3]。 常用多传感器阵列(例如5个传感器一字排列)提高检测精度,结合PID算法实现方向控制[^1][^4]。 2. **停车触发条件** 停车功能可通过以下方式实现: - **特殊标记检测**:在停车点设置高对比度标记(如宽黑线),当所有传感器同时检测到黑色时触发停车[^3]。 - **距离测量**:结合编码器或超声波传感器,在循迹过程中累计移动距离,达到设定值后停车。 #### 二、实现步骤 1. **硬件搭建** - **传感器布局**:一字排列5-7个灰度传感器,覆盖路径宽度(参考引用[2]的传感器阵列方案)。 - **驱动模块**:电机驱动模块(如L298N)控制车轮,舵机控制转向(可选)。 - **控制器**:Arduino或STM32作为核心,处理传感器数据并输出控制信号[^1][^2]。 2. **控制算法设计** **循迹部分** 采用PID算法计算转向修正量,公式如下: $$u(t) = K_p e(t) + K_i \int_{0}^{t} e(\tau) d\tau + K_d \frac{de(t)}{dt}$$ 其中$e(t)$为位置偏差,通过传感器阵列的读数加权计算得到。 **停车部分** ```python # 伪代码示例 if all_sensors_detect_black(): # 检测到停车线 stop_motors() activate_brake() # 可选电子刹车 ``` 3. **参数调试** - **PID调参**:先调$K_p$确保快速响应,再引入$K_d$抑制震荡,最后加$K_i$消除静态误差。 - **停车灵敏度**:通过阈值滤波避免误触发,例如连续检测到停车标记3次后执行停车。 #### 三、优化方法 1. **抗干扰设计** - 在传感器读数环节加入移动平均滤波,减少环境光突变的影响[^1]。 - 使用状态机区分“循迹”和“停车”阶段,避免路径中途误触发。 2. **停车平顺性** 采用分段减速策略: $$v(t) = \begin{cases} v_{\text{max}} & \text{当 } d > 20\text{cm} \\ v_{\text{max}} \cdot \frac{d}{20} & \text{当 } d \leq 20\text{cm} \end{cases}$$ 其中$d$为到停车点的剩余距离(通过编码器计算)。 --- ###
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值