IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 嵌入式 -> 基于红外感应的智能跟随小车 -> 正文阅读

[嵌入式]基于红外感应的智能跟随小车

跟随原理

下面介绍红外感应的跟随小车的自动跟随部分。

基本原理:在小车上安装一个红外接收器(能测量红外入射角的感应器),人手持一个红外发射模块。

根据不同的入射角,调整小车前进方向。若入射角在右边,就控制小车右转,若入射角在左边,就控制小车左转。

?效果展示

?百度网盘链接:https://pan.baidu.com/s/1PGTwDxvUbdksDmyfcXAMOw?pwd=vddg

提取码:vddg

代码

以ESP32芯片(Arduino开发环境)为例。

void loop() {

if (millis() - Run_Time > 200) {
    Run_Time = millis();
    LeftSpeed = 0; RightSpeed = 0;
    PineMotorRun(0);
  }

GetIRData(&Angle, &Distance);

if (Distance > 30 && Angle > 0 && Angle < 180) {
      LeftSpeed = 50 - (Angle - 90) * 0.5;
      RightSpeed = 50 + (Angle - 90) * 0.5;
      PineMotor_Run(LeftSpeed, RightSpeed);
      Run_Time = millis();
      OutStr = "L/R speed:" + String(LeftSpeed) + "," + String(RightSpeed);
     

 }

}

?红外感应代码?"IRSensor.h"

#ifndef __IRSENSOR_H__
#define __IRSENSOR_H__

#define IRPINCOUNT 7
#define MaxIRShotCount  300
#define MaxHistoryCount 10
#define InValidAngle -360.0

struct IRSENSOR_DATA{
  uint16_t IRCount[IRPINCOUNT];//红外感应器接受的脉冲数
  uint16_t IRValidCount[IRPINCOUNT];//红外感应器接受的有效脉冲数(脉冲间隔时间满足一定的范围)
  int IRTimeHistory[IRPINCOUNT][MaxIRShotCount];//红外感应器接受到脉冲时的时刻,单位为微秒
  long FirstTime[IRPINCOUNT];//单个感应器的首次脉冲时刻,单位为微秒
  long LastTime[IRPINCOUNT];  //单个感应器的最后脉冲时刻,单位为微秒
  long IRFirstTime, IREndTime;//整组感应器的首次,最后脉冲时刻,单位为微秒

  uint8_t ValidPinCount;//接受到有效信息的红外感应器个数
  double IRZone;
  double IRDistance;  
};

//红外感应器初始化
void iniIR();
static void IRPinCallBack(uint8_t i);
void DisableIRInterrupt();
void ResetIRSensorData();
void ResetIRData();

void ResetIRSensorData();
long GetFirstIRTime_ms();
long GetFinalIRTime_ms();
double CalculateAngleMovingMean(uint8_t LastCount);

void SumIRDataLoop();
void GetIRDataFromPin();//NotConfirmTime
double GetIRAngle();
void GetIRData(double *angle, int *distance);
String GetIRSignalStatus();


uint8_t GetHighLevelPinCount(uint16_t IRCount[], uint16_t LL);
void AnalysisIRValues_OneSide(IRSENSOR_DATA* mData, uint8_t Angle[]);



void RecordIRData(double Currentdata);

void GetValidCount(IRSENSOR_DATA* mData);

void Record_DoubleArray(double DArray[], double mydata, uint8_t * index, uint8_t Length);
void Push_DoubleArray(double History[], int Length);
void Reset_Array16(uint16_t IRCount[], int Length);


#endif

?红外感应代码 “IRSensor.cpp”

#include <Arduino.h>

#include "IRSensor.h"

struct IRSENSOR_DATA mIRData;

int  LineCount, Count2 = 0;
bool IsIniIRPin = false, IsReceivedIRData = false;

char strIR[140], Head[] = {"Angle:"};

//IR, Pin从左到右,角度从大到小
uint8_t IRPin[] = {33, 32, 34, 35, 23, 21, 19}; //
uint8_t Angle_Pin[] = {165, 140, 115, 90, 65, 40, 15};

bool IsHaveIRData = false, IsInNearArea = false;

double IRAngleHistory[MaxHistoryCount];
uint8_t IRRecordIndex = MaxHistoryCount - 1;

char IRs[256];
String IRStatus, AngleStatus, IRResponseTime_String, IRTimeStatus;

long LastTime_AnalysisData;
bool IsFinishAnalysis;
long SimulatedTime;



//

static void IRPinCallBack(uint8_t i) {
  long CurrentTime = micros();

  if (!IsHaveIRData) {
    mIRData.IRFirstTime = CurrentTime;

  }

  if (IsFinishAnalysis) {
    IsFinishAnalysis = false;
  }

  mIRData.IREndTime = CurrentTime;

  if (mIRData.IRCount[i] < MaxIRShotCount) {

    if (mIRData.IRCount[i] == 0) {
      mIRData.FirstTime[i] = CurrentTime;
      mIRData.IRTimeHistory[i][mIRData.IRCount[i]] = 0;
      mIRData.LastTime[i] = CurrentTime;
    } else {
      mIRData.IRTimeHistory[i][mIRData.IRCount[i]] = CurrentTime - mIRData.LastTime[i];
    }
    mIRData.LastTime[i] = CurrentTime;

    mIRData.IRCount[i]++;
  } else {
    mIRData.IRCount[i] = 0;
  }

  IsHaveIRData = true;
}
//


///
void IRAM_ATTR IntCallbackIR0() {
  uint8_t i = 0;
  IRPinCallBack(i);
}

void IRAM_ATTR IntCallbackIR1() {
  uint8_t i = 1;
  IRPinCallBack(i);
}

void IRAM_ATTR IntCallbackIR2() {
  uint8_t i = 2;
  IRPinCallBack(i);
}

void IRAM_ATTR IntCallbackIR3() {
  uint8_t i = 3;
  IRPinCallBack(i);
}

void IRAM_ATTR IntCallbackIR4() {
  uint8_t i = 4;
  IRPinCallBack(i);
}

void IRAM_ATTR IntCallbackIR5() {
  uint8_t i = 5;
  IRPinCallBack(i);
}

void IRAM_ATTR IntCallbackIR6() {
  uint8_t i = 6;
  IRPinCallBack(i);
}
///

void SumIRDataLoop() {

  if (IsHaveIRData && !IsFinishAnalysis && (millis() - GetFirstIRTime_ms() > 30)) {
    //一个发射周期是200毫秒,一个脉冲105*2微妙,共25个脉冲,共5.26毫秒。 在30毫秒后分析数据
    LastTime_AnalysisData = millis();
    GetIRDataFromPin();
    IsFinishAnalysis = true;
  }

  if (millis() - LastTime_AnalysisData > 200) {
    ResetIRData();
  }

}


void GetIRDataFromPin() {
  String IRstr = "";
  IRStatus = "";

  //SimulateIRData();

  if ( GetHighLevelPinCount(mIRData.IRCount, MaxHistoryCount) >= 6) {
    IsInNearArea = true;
    //Serial.printf("近距离\n");
  }

  AnalysisIRValues_OneSide(&mIRData, Angle_Pin);

  char SS[256];
  sprintf(SS, "Angle:%.2f\r\n", mIRData.IRZone);
  IRstr = String(SS);

  if (IsInNearArea) {
    IRstr += "IRD:30\r\n";
    mIRData.IRDistance = 30;
  } else {
    IRstr += "IRD:500\r\n";
    mIRData.IRDistance = 500;
  }

  IRstr += IRStatus;

  //Serial.print(IRstr);

  ResetIRSensorData();
}



double CalculateAngleMovingMean(uint8_t LastCount) {
  double sum = 0, validcount = 0;
  uint8_t i;

  if (LastCount > MaxHistoryCount) LastCount = MaxHistoryCount;


  for (i = 1; i <= LastCount; i++) {
    if (0 <= IRAngleHistory[MaxHistoryCount - i] && IRAngleHistory[MaxHistoryCount - i] <= 180 ) {
      sum += IRAngleHistory[MaxHistoryCount - i];
      validcount++;
    }
  }

  if (validcount > 1) {
    return sum / validcount;
  } else {
    return -1;
  }


}

String GetIRSignalStatus() {
  return IRStatus;
}

String GetIRResponseTime() {
  return IRResponseTime_String;
}

double GetIRAngle() {
  return mIRData.IRZone;
}

void GetIRData(double *angle, int *distance) {
  *angle =  mIRData.IRZone;
  *distance =  mIRData.IRDistance;
}

void ResetIRData() {

  mIRData.IRZone = InValidAngle;
  mIRData.IRDistance = 0;
  IRStatus = "";
  IRResponseTime_String = "";
  IsReceivedIRData = false;
}

void ResetIRSensorData() {
  uint8_t i;


  for (i = 0; i < IRPINCOUNT; i++) {
    mIRData.IRCount[i] = 0;
  }

  long TempTime;
  TempTime = micros();
  for (i = 0; i < IRPINCOUNT; i++) {
    mIRData.IRTimeHistory[i][0] = 0;

    uint16_t j;
    for (j = 0; j < MaxIRShotCount; j++) {
      mIRData.IRTimeHistory[i][j] = 0;
    }

    mIRData.LastTime[i] = TempTime + 20 * 1000;
    mIRData.FirstTime[i] = TempTime + 20 * 1000;

  }
  mIRData.ValidPinCount = 0;

  IsHaveIRData = false;
  IsInNearArea = false;
}


uint8_t GetHighLevelPinCount(uint16_t IRCount[], uint16_t LL) {

  uint8_t i, Count = 0;
  for (i = 0; i < IRPINCOUNT; i++) {
    if (IRCount[i] > LL) {
      Count++;
    }
  }
  return Count;
}




void AnalysisIRValues_OneSide(IRSENSOR_DATA *mData, uint8_t Angle[]) {

  uint16_t i, j;
  boolean IsAbnormal = false;
  double AngleMean = InValidAngle, AngleSum = 0.0;  //arduino无float型数据
  int CountSum = 0, ValidCountSum = 0;
  String IRStr = "", SideStr = "";

  SideStr = "IR:";
  IRStr = SideStr;


  for (i = 0; i < IRPINCOUNT; i++) {
    IRStr += String(mData->IRCount[i]) + ",";
    CountSum += mData->IRCount[i];
  }

  IRStr += "Valid:";
  if (CountSum <= 4) {  //偶尔几个脉冲,无需理会
    for (i = 0; i < IRPINCOUNT; i++) {
      mData->IRValidCount[i] = 0;
      IRStr +=  "0,";

    }
    IRStr += "\r\n";
    IRStatus += IRStr;
    //Serial.println(IRStatus);
    mData->IRZone = InValidAngle;
    //Serial.println("No IR Signal.");
    return;
  }

  //  Serial.printf("Signal Count: %d \n", CountSum);
  boolean isCheckPulseTime = false;
  String strOut;

  if (isCheckPulseTime) {
    GetValidCount(mData);
  } else {
    for (i = 0; i < IRPINCOUNT; i++) {
      mData->IRValidCount[i] = mData->IRCount[i];
    }
  }

  ValidCountSum = 1;//相除时,不会是0
  for (i = 0; i < IRPINCOUNT; i++) {
    IRStr += String(mData->IRValidCount[i]) + ",";
    ValidCountSum += mData->IRValidCount[i];
  }
  IRStr += "\r\n";

  IRStatus += IRStr;

  //  Serial.println(IRStr);

  for (i = 0; i < IRPINCOUNT; i++) {
    if ( mData->IRCount[i] > 100) {  //脉冲太多,是干扰信号
      IsAbnormal = true;
      mData->IRZone = InValidAngle;
      break;
    }
  }

  if (CountSum / ValidCountSum >= 3) {  //少于33%的有效脉冲,极有可能是干扰信号
    IsAbnormal = true;
    mData->IRZone = InValidAngle;
  }

  if (IsAbnormal) {
    Reset_Array16(mData->IRCount, IRPINCOUNT);

    //Serial.printf("abnormal\n");
    return;
  }


  //加权平均

  //  Serial.println("");

  AngleMean = 0;    AngleSum = 0;
  mData->ValidPinCount = 0;
  ValidCountSum = 0;

  for (i = 0; i < IRPINCOUNT; i++) {
    if (mData->IRValidCount[i] < 1) {    //脉冲数量少,认为是干扰,就置0
      mData->IRValidCount[i] = 0;
    } else {
      (mData->ValidPinCount)++;
    }

    AngleSum += Angle[i]  * mData->IRValidCount[i];
    ValidCountSum += mData->IRValidCount[i];
  }

  if (ValidCountSum > 0) {
    AngleMean = AngleSum / ValidCountSum;
  } else {
    AngleMean = InValidAngle;
  }

  sprintf(IRs, " Zone: %.2f Valid Signal Count: %d \n", AngleMean, ValidCountSum);

  strOut = SideStr + String(IRs);

  AngleStatus += strOut;

  mData->IRZone = AngleMean;
  Record_DoubleArray(IRAngleHistory, AngleMean, &IRRecordIndex, MaxHistoryCount);

}

void GetValidCount(IRSENSOR_DATA *mData) {
  int CL = 500; uint8_t Error = 50;
  int IRTime;
  uint16_t i, j;


  //用于调试程序
  String IRStr = "", strOut;
  for (j = 0; j < IRPINCOUNT; j++) {
    IRStr = String(j) + ":";
    for (i = 0; i < mData->IRCount[j]; i++) {
      IRStr += String(mData->IRTimeHistory[j][i]) + " ";
    }
    //    Serial.println(IRStr);
  }



  for (j = 0; j < IRPINCOUNT; j++) {
    mData->IRValidCount[j] = 0;
    for (i = 0; i < MaxIRShotCount; i++) {

      IRTime = (mData->IRTimeHistory[j][i] + CL / 2) % CL + CL / 2;
      if (CL - Error < mData->IRTimeHistory[j][i] && CL - Error < IRTime  &&  IRTime < CL + Error) {
        mData->IRValidCount[i]++;
      }
    }

  }

}



long GetFirstIRTime_ms() {
  return mIRData.IRFirstTime / 1000;
}

long GetFirstIRTime_us() {
  return mIRData.IRFirstTime;
}

long GetFinalIRTime_ms() {
  return mIRData.IREndTime / 1000;
}

//


//
void iniIR() {
  uint8_t i;
  uint8_t Model = FALLING; //CHANGE

  if (!IsIniIRPin) {

    for (i = 0; i < IRPINCOUNT; i++) {
      pinMode(IRPin[i], INPUT_PULLUP);
    }

    i = 0;
    attachInterrupt(digitalPinToInterrupt(IRPin[i]), IntCallbackIR0, Model);//FALLING

    i++;
    attachInterrupt(digitalPinToInterrupt(IRPin[i]), IntCallbackIR1, Model);

    i++;
    attachInterrupt(digitalPinToInterrupt(IRPin[i]), IntCallbackIR2, Model);

    i++;
    attachInterrupt(digitalPinToInterrupt(IRPin[i]), IntCallbackIR3, Model);

    i++;
    attachInterrupt(digitalPinToInterrupt(IRPin[i]), IntCallbackIR4, Model);

    i++;
    attachInterrupt(digitalPinToInterrupt(IRPin[i]), IntCallbackIR5, Model);

    i++;
    attachInterrupt(digitalPinToInterrupt(IRPin[i]), IntCallbackIR6, Model);


    ResetIRSensorData();
    IRStatus = "";
    AngleStatus = "";
    IRResponseTime_String = "";
    IRTimeStatus = "";
    IsIniIRPin = true;
  }

}

void DisableIRInterrupt() {
  uint8_t i;
  for (i = 0; i < IRPINCOUNT; i++) {
    detachInterrupt(digitalPinToInterrupt(IRPin[i]));

  }
  IsIniIRPin = false;
}


//
void Reset_Array16(uint16_t IRCount[], int Length) {
  int i;
  for (i = 0; i < Length; i++) {
    IRCount[i] = 0;
  }

}


void Record_DoubleArray(double DArray[], double mydata, uint8_t * index, uint8_t Length) {

  DArray[*index] = mydata;
  (*index)++;
  if ((*index) >= Length) {
    Push_DoubleArray(DArray, Length);
    *index = Length - 1;
  }

}


void Push_DoubleArray(double History[], int Length) {
  int i;
  for (i = 0; i < Length - 1; i++) {
    History[i] = History[i + 1];
  }

}

//

?采购清单

序号

物品

数量

备注

1

小车底座(含1块亚克力板,2个马达,2个车轮,1个万向轮,1个电池盒)

1

2

电路板

1

3

ESP32芯片

1

4

Mico-USB线

1

5

红外感应器

1

https://item.taobao.com/item.htm?spm=a2oq0.12575281.0.0.50111debsOkWHG&ft=t&id=674576373037

6

马达驱动板(L298N)

1

7

充电板

1

8

18650锂电池

1

9

红外发射器

1

  嵌入式 最新文章
基于高精度单片机开发红外测温仪方案
89C51单片机与DAC0832
基于51单片机宠物自动投料喂食器控制系统仿
《痞子衡嵌入式半月刊》 第 68 期
多思计组实验实验七 简单模型机实验
CSC7720
启明智显分享| ESP32学习笔记参考--PWM(脉冲
STM32初探
STM32 总结
【STM32】CubeMX例程四---定时器中断(附工
上一篇文章      下一篇文章      查看所有文章
加:2022-05-21 19:08:40  更:2022-05-21 19:09:46 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/22 7:55:59-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码