使用STM32 再实现循迹/跟随/摇头避障小车

news2024/7/4 4:50:13

循迹小车

硬件介绍和接线

TCRT5000

使用方法和原理见89C52时期的介绍。

循迹小车需要使用两个TCRT5000,左侧的DO接到PB3右侧的DO接到PB4

CubeMX

1. 在上节的基础上进行修改 + 配置两个传感器的GPIO

2. 惯例配置更新代码

Keil

注意,如果要使用PWM调速就必须全部是PWM调速,因为一旦使用PWM调速之后又使用其他motor.c中的前后左右,就会重置PB1和PB10的值,而如果要使用调速,PB1和PB10就必须一直为HIGH,使用PWM调速的优点是转弯平滑,缺点是电机很容易因为PWM波的有效电平持续时间过低而转不动。

如果不想用PWM调速,不仅不能调用PWM调速的函数,在main中也记得将PWM使能关闭,在Cube中要把PA1和PA2改回GPIO,不使用PWM调速的优点是电机动力充足,缺点是转弯不太平滑。

按照代码封装的方法,封装route_sensor.croute_sensor.h:

route_sensor.c:

#include "route_sensor.h"
#include "motor.h"
#include "gpio.h"



void route_sensor_mode()
{
	if((HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_3) == GPIO_PIN_RESET) && (HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_4) == GPIO_PIN_RESET)){ //此时左右都没有检测到黑线,说明在轨迹上,直走, 两个灯都亮
		move_forward();
		//speed_left(180); //speed就是CCRx的值,理论在0到199之间,实际最好大于130
		//speed_right(180);
	}
	if((HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_3) == GPIO_PIN_SET) && (HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_4) == GPIO_PIN_RESET)){ //此时左模块检测到黑线,说明车身偏右即将离开轨道,此时需要左转修正,只有右灯亮
		move_leftturn();
		//speed_left(160); //speed就是CCRx的值,理论在0到199之间,实际最好大于130
		//speed_right(199);
	}
	if((HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_3) == GPIO_PIN_RESET) && (HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_4) == GPIO_PIN_SET)){ //此时右模块检测到黑线,说明车身偏左即将离开轨道,此时需要右转修正,只有左灯亮
		move_rightturn();
		//speed_left(199); //speed就是CCRx的值,理论在0到199之间,实际最好大于130
		//speed_right(160);
	}
	if((HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_3) == GPIO_PIN_SET) && (HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_4) == GPIO_PIN_SET)){ //此时左右都检测到黑线,说明不在轨迹上了,停止,两个灯都灭
		move_stop();
		//speed_left(0); //speed就是CCRx的值,理论在0到199之间,实际最好大于130
		//speed_right(0);
	}
	
}

route_sensor.h:

#ifndef __route_sensor_H__ // "XXXX"就是h文件的名字
#define __route_sensor_H__
 
void route_sensor_mode(void);
 
#endif 

main.c:

#include "motor.h"
#include "route_sensor.h"

int main(void)
{
	//HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_1); //打开Timer2的1号Channel, 1号通道对应 左轮
	//HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_2); //打开Timer2的2号Channel, 2号通道对应 右轮

  while (1)
  {
		route_sensor_mode();
  }
}

实现效果

实现效果和89C52时一样,所以不重复展示了。

循迹小车

硬件介绍和接线

红外避障模块

使用方法和原理见89C52时期的介绍。

跟随小车需要使用两个红外避障模块,左侧的DO接到PB5右侧的DO接到PB6

CubeMX

1. 在上节的基础上进行修改 + 配置两个传感器的GPIO

2. 惯例配置更新代码

Keil

按照代码封装的方法,封装route_follow.croute_follow.h:

route_follow.c:

#include "route_follow.h"
#include "motor.h"
#include "gpio.h"

void route_follow_mode()
{
	if((HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_5) == GPIO_PIN_RESET) && (HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_6) == GPIO_PIN_RESET)){ //此时左右都没有检测到黑线,说明在轨迹上,直走, 两个灯都亮
		move_forward();
	}
	if((HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_5) == GPIO_PIN_SET) && (HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_6) == GPIO_PIN_RESET)){ //此时左模块检测到黑线,说明车身偏右即将离开轨道,此时需要左转修正,只有右灯亮
		move_rightturn();
	}
	if((HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_5) == GPIO_PIN_RESET) && (HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_6) == GPIO_PIN_SET)){ //此时右模块检测到黑线,说明车身偏左即将离开轨道,此时需要右转修正,只有左灯亮
		move_leftturn();
	}
	if((HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_5) == GPIO_PIN_SET) && (HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_6) == GPIO_PIN_SET)){ //此时左右都检测到黑线,说明不在轨迹上了,停止,两个灯都灭
		move_stop();
	}
	
}

route_follow.h:

#ifndef __route_follow_H__ // "XXXX"就是h文件的名字
#define __route_follow_H__
 
void route_follow_mode(void);
 
#endif 

main.c:

#include "motor.h"
#include "route_follow.h"

int main(void)
{
	//HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_1); //打开Timer2的1号Channel, 1号通道对应 左轮
	//HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_2); //打开Timer2的2号Channel, 2号通道对应 右轮

  while (1)
  {
		route_follow_mode();
  }
}

实现效果

实现效果和89C52时一样,所以不重复展示了。

摇头避障小车

硬件介绍和接线

SG90舵机(实现摇头)

HC-SR04超声波测距模块(实现避障) 

由于驱动舵机使用的PWM也是周期为20ms的,所以可以直接用TIM1的CH3,对应PA2 

HC-SR04的Trig接PA5;Echo接PA4

CubeMX

1. 在上节的基础上进行修改 + 配置Trig和Echo的GPIO:

 

2. 打开TIM2的CH3的PWM,由于PSC和ARR已经设置过了所以不用设置,有效电平为HIGH也不用设置:

3. 打开TIM3,用作HC-SR04的计时器,并且只用来作为计数功能,并软件控制何时停止计数,因此只需要设置TIM2的PSC而不需要设置ARR。

神奇的事情又发生了...在前几个项目里,同样是HC-SR04的初始化,使用的是微秒级的延时,但是在这个项目里,又变回了毫秒级的延时???唯一的区别是,上个项目使用的是TIM2,此处是TIM3...

4. 惯例配置更新代码

Keil

按照代码封装的方法,封装SG90.c, SG90.h, HC_SR04.c, HC_SR04.h:

SG90.c:

#include "SG90.h"
#include "tim.h"

int angle;

void head_right()
{
	angle = 0;
	__HAL_TIM_SetCompare(&htim2, TIM_CHANNEL_3, 5); //0度
}
 
void head_middle()
{
	angle = 1;
	__HAL_TIM_SetCompare(&htim2, TIM_CHANNEL_3, 15); //90度
}
	
void head_left()
{
	angle = 2;
	__HAL_TIM_SetCompare(&htim2, TIM_CHANNEL_3, 25); //180度
}

SG90.h:

#ifndef __SG90_H__ // "XXXX"就是h文件的名字
#define __SG90_H__
 
void head_right(void);
void head_middle(void);
void head_left(void);
 
 
#endif 

HC_SR04.c:

#include "HC_SR04.h"
#include "SG90.h"
#include "gpio.h"
#include "tim.h"
#include "motor.h"


double dist_middle;
double dist_left;
double dist_right;


 
void StartHC()
{
	HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_RESET); //Trig写0
	HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_SET); //Trig写1
	HAL_Delay(10);
	HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_RESET); //Trig写0
	
}
 
double get_dist()
{
	int cnt;
	double dist;
	
	StartHC();
	
	while((HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_4)) == GPIO_PIN_RESET); //等待Echo变高的一瞬间
	HAL_TIM_Base_Start(&htim3); //TIM3开始计时
	__HAL_TIM_SetCounter(&htim3,0); //将TIM3的计数器置0
	
	while((HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_4)) == GPIO_PIN_SET); //等待Echo变低的一瞬间	
	HAL_TIM_Base_Stop(&htim3); //TIM3停止计时
	
	cnt = __HAL_TIM_GetCounter(&htim3);//求出计了多少次,由于计数一次经过的时间是1us
	dist = cnt*340/2*0.000001*100;  //求出距离
	
	return dist;
}

void deal_dist()
{
	dist_middle = get_dist();
	if(dist_middle > 35){ //如果距离大于35cm就可以前进
		move_forward();//前进
	}else if((dist_middle > 10) && (dist_middle < 35)){ //距离小于35cm但大于10cm时
		move_stop();//先停下
		head_left();//将测距传感器通过SG90转到左边
		dist_left = get_dist();
		HAL_Delay(300);//根据实际情况
		
		head_right();//将测距传感器通过SG90转到右边
		dist_right = get_dist();
		HAL_Delay(300);//根据实际情况
		
		if(dist_right > dist_left){ //哪边距离大往哪边转
			move_rightturn();
			HAL_Delay(300);//根据实际情况
			move_stop();
		}else{
			move_leftturn();
			HAL_Delay(300);//根据实际情况
			move_stop();
		}
	}else{ //当距离已经小于10cm时
		move_backward();//此时距离已经危险了,需要后退一下
		HAL_Delay(300);//根据实际情况
		move_stop();
	}
}
	

HC_SR04.h:

#ifndef __HC_SR04_H__ // "XXXX"就是h文件的名字
#define __HC_SR04_H__
 
void deal_dist(void);
 
#endif 

main.c: 

#include "SG90.h"
#include "HC_SR04.h"

extern int angle;

int main(void)
{	
	//HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_1); //打开Timer2的1号Channel, 1号通道对应 左轮
	//HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_2); //打开Timer2的2号Channel, 2号通道对应 右轮
	HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_3); //打开Timer2的3号Channel, 控制SG90
	head_middle();

  while (1)
  {
		if(angle != 1){ //如果不在中间的话,回到中间
			head_middle();
			HAL_Delay(300);
		}

		deal_dist();
		HAL_Delay(50); //重要

  }
}

实现效果

实现效果和89C52时一样,所以不重复展示了。

 

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/777751.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Linux 学习记录54(ARM篇)

Linux 学习记录54(ARM篇) 本文目录 Linux 学习记录54(ARM篇)一、框图分析1. 芯片手册内部框图2. 操作GPIO过程 二、通过汇编完成GPIO操作1. 常用的汇编指令2. GPIO初始化流程3. 查找相关寄存器(1. RCC寄存器(2. GPIO寄存器>1. 模式配置寄存器>2. 输出模式配置寄存器>3…

【云原生】Prometheus之部署 Alertmanager 发送告警

前言 1. Alertmanager 发送告警的介绍 Prometheus 对指标的收集、存储与告警能力分属于 Prometheus Server 和 AlertManager 两个独立的组件&#xff0c;前者仅负责定义告警规则生成告警通知&#xff0c; 具体的告警操作则由后者完成。 Alertmanager 负责处理由 Prometheus…

wxchart 小程序 线条图不显示y轴的网格线 (分割线)

如下图&#xff1a;项目需求不显示包括x轴的6条灰色分割线。 分析&#xff1a; 看了一下源码已经写死了是5条分割线&#xff0c;加一条x轴刻度线。没给公开配置方法。 解决方案&#xff1a; 既然没有配置项目&#xff0c;可以转变思路&#xff0c;把这些线条配置成白色&…

一文掌握如何前后端分离?

随着科技的进步和发展&#xff0c;低代码开发产品拥有广阔的市场前景。前后端分离似乎早已经是发展趋势了&#xff0c;因为做好前后端分离对于前后端的工程师而言是非常有利的&#xff0c;这样也有利于提升办公协作效率。那么&#xff0c;如何前后端分离&#xff1f;分别都有哪…

CentOS 安装Mysql8

1.检查是否已经安装mysql&#xff0c;停止mysql服务&#xff0c;删除mysql ps -ef | grep -i mysql systemctl stop mysqld rpm -e mysql 2.配置仓库 更新秘钥 rpm --import https://repo.mysql.com/RPM-GPG-KEY-mysql-2022 安装mysql8的yum源 rpm -Uvh https://dev.mysql.…

基于linux下的高并发服务器开发(第二章)- 2.17 内存映射(1)

11 / 内存映射相关系统调用 #include <sys/mman.h> void* mmap(void *addr, size_t length, int prot, int flags,int fd, off_t offset); - 功能&#xff1a;将一个文件或者设备的数据映射到内存中 - 参数&#xff1a; - void* addr:NULL,由内核指定 - length:要映射的…

【OpenCV】常见问题及解决办法

文章目录 0 前言1 中文乱码问题2 非法路径问题 0 前言 本篇博客主要是总结OpenCV使用过程中遇到的一些问题&#xff0c;以及对应的解决办法&#xff0c;这里重点是关注OpenCV&#xff0c;既有基于C的&#xff0c;也有基于Python的&#xff0c;比较全面&#xff0c;而且也会随着…

【Python】数据分析+数据挖掘——变量列的相关操作

前言 在Python和Pandas中&#xff0c;变量列操作指的是对DataFrame中的列进行操作&#xff0c;包括但不限于选择列、重命名列、添加新列、删除列、修改列数据等操作。这些操作可以帮助我们处理数据、分析数据和进行特征工程等。 变量列的相关操作 概述 下面将会列出一些基本…

对github项目提PR 请求的保姆级教程——以修改casdoor项目的swagger文档为例,干货满满

Github入门教程可以在腾讯犀牛鸟开源人才培养计划里面学习。 PR简介 PR(Pull Request) 即拉取请求,是 GitHub 上进行协同开发的一种非常常用的方式。 它的基本流程是&#xff1a; 开发者fork一个开源项目的代码库,将其克隆到本地。在本地对代码进行修改、添加新功能等。将本…

基于ArcGIS、ENVI、InVEST、FRAGSTATS等多技术融合提升环境、生态、水文、土地、土壤、农业、大气等领域的数据分析能力与项目科研水平教程

详情点击链接&#xff1a;基于ArcGIS、ENVI、InVEST、FRAGSTATS等多技术融合提升环境、生态、水文、土地、土壤、农业、大气等领域的数据分析能力与项目科研水平 一&#xff0c;空间数据获取与制图 1.1 软件安装与应用 1.2 空间数据 1.3海量空间数据下载 1.4 ArcGIS软件快…

MySQL数据库(七)

目录 一、联合查询 1.1内连接 1.2外连接 1.3自连接 1.4子查询 1.5合并查询 一、联合查询 实际开发中往往数据来自不同的表&#xff0c;所以需要多表联合查询。多表查询是对多张表的数据取笛卡尔积&#xff1a; 下面进行多表查询的练习&#xff0c;对应的在表的设计与数据插入中…

练习时长两年半的网络安全防御“first”

1.网络安全常识及术语 下边基于这次攻击演示我们介绍一下网络安全的一些常识和术语。 资产 任何对组织业务具有价值的信息资产&#xff0c;包括计算机硬件、通信设施、 IT 环境、数据库、软件、文档资料、信息服务和人员等。 网络安全 网络安全是指网络系统的硬件、软件及…

Stable Diffusion - 扩展 Roop 换脸 (Face Swapping) 插件的配置与使用

欢迎关注我的CSDN&#xff1a;https://spike.blog.csdn.net/ 本文地址&#xff1a;https://spike.blog.csdn.net/article/details/131856141 官网&#xff1a;GitHub - roop&#xff0c;参考论文&#xff1a;RobustSwap: A Simple yet Robust Face Swapping Model against Attr…

kubesphere部署谷粒商城, nginx无法路由到网关服务

使用kubesphere部署谷粒商城&#xff0c;微服务和nginx均已部署成功&#xff0c;其中ingress-controller已安装。但是nginx无法路由到网关服务。使用域名gulimall.com访问谷粒商城&#xff0c;默认访问的是nginx首页&#xff0c;路由失败。 校对nginx的配置信息&#xff0c;上游…

MySQL数据库第十课-------join连接的再续------强强连锁

作者前言 欢迎小可爱们前来借鉴我的gtiee秦老大大 (qin-laoda) - Gitee.com __________________________________________________________ 目录 join连接 内连接 左连接 右连接 外连接 其他连接 ______________________________________________________________ 作…

Unity 实用插件篇 | Tutorial Master 2 游戏引导教程 快速上手

前言【Unity 实用插件篇】 | Tutorial Master 2 游戏引导教程 快速上手一、Tutorial Master 2 介绍1.1 基本概念1.2 相关链接1.3 效果展示二、搭建简易测试环境三、制作简易引导教程3.1 挂载一个Tutorial Master Manager脚本3.2 设置引导预制体3.3 创建一个引导教程3.4 添加引导…

SpringBoot系列--【如何集成prometheus?】

如何集成prometheus&#xff1f; 1.添加pom依赖 注意&#xff1a;prometheus的版本依赖springboot版本&#xff0c;示例使用的springboot版本的2.3.X. 2.配置文件添加配置 3.主启动类添加如下配置 4.验证端点 SpringBoot项目到这里就配置完成了&#xff0c;启动项目&#xff0c…

将请求参数数据推送至RabbitMQ队列中并且捕捉消息没有到达交换机的异常

1&#xff1a;自定义mq信息类&#xff08;我的交换这些信息都从nacos上直接取的&#xff0c;怎么从nacos取配置信息看上篇文章&#xff09;&#xff1a; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor;impo…

Windows10 + Mingw + Paho Mqtt C/C++编译使用

文章目录 1、前言2、按照Mingw环境3、编译paho c3.1、ssl验证大坑3.2、解决方法3.3、mingw32-make过程出现报错3.4、继续出错3.5、编译成功 4、编译paho c5、Qt使用paho mqtt库5.1、编码 1、前言 起初使用的是Cmake Visual Studio 2019进行编译&#xff0c;使用的时候出现ssl错…

《Java核心技术大会2023》——AIC松鼠活动第一期

共同深入探讨 Java 生态&#xff01;直播预约&#xff1a;视频号“IT阅读排行榜” 大会简介 人工智能在22年、23年的再次爆发让Python成为编程语言里最大的赢家&#xff1b;云原生的持续普及令Go、Rust等新生的语言有了进一步叫板传统技术体系的资本与底气。我们必须承认在近…