当前位置:   article > 正文

使用STM32 再实现循迹/跟随/摇头避障小车_stm32小车不能走直线

stm32小车不能走直线

循迹小车

硬件介绍和接线

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:

  1. #include "route_sensor.h"
  2. #include "motor.h"
  3. #include "gpio.h"
  4. void route_sensor_mode()
  5. {
  6. if((HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_3) == GPIO_PIN_RESET) && (HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_4) == GPIO_PIN_RESET)){ //此时左右都没有检测到黑线,说明在轨迹上,直走, 两个灯都亮
  7. move_forward();
  8. //speed_left(180); //speed就是CCRx的值,理论在0到199之间,实际最好大于130
  9. //speed_right(180);
  10. }
  11. if((HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_3) == GPIO_PIN_SET) && (HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_4) == GPIO_PIN_RESET)){ //此时左模块检测到黑线,说明车身偏右即将离开轨道,此时需要左转修正,只有右灯亮
  12. move_leftturn();
  13. //speed_left(160); //speed就是CCRx的值,理论在0到199之间,实际最好大于130
  14. //speed_right(199);
  15. }
  16. if((HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_3) == GPIO_PIN_RESET) && (HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_4) == GPIO_PIN_SET)){ //此时右模块检测到黑线,说明车身偏左即将离开轨道,此时需要右转修正,只有左灯亮
  17. move_rightturn();
  18. //speed_left(199); //speed就是CCRx的值,理论在0到199之间,实际最好大于130
  19. //speed_right(160);
  20. }
  21. if((HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_3) == GPIO_PIN_SET) && (HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_4) == GPIO_PIN_SET)){ //此时左右都检测到黑线,说明不在轨迹上了,停止,两个灯都灭
  22. move_stop();
  23. //speed_left(0); //speed就是CCRx的值,理论在0到199之间,实际最好大于130
  24. //speed_right(0);
  25. }
  26. }
route_sensor.h:
  1. #ifndef __route_sensor_H__ // "XXXX"就是h文件的名字
  2. #define __route_sensor_H__
  3. void route_sensor_mode(void);
  4. #endif

main.c:

  1. #include "motor.h"
  2. #include "route_sensor.h"
  3. int main(void)
  4. {
  5. //HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_1); //打开Timer2的1号Channel, 1号通道对应 左轮
  6. //HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_2); //打开Timer2的2号Channel, 2号通道对应 右轮
  7. while (1)
  8. {
  9. route_sensor_mode();
  10. }
  11. }

实现效果

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

循迹小车

硬件介绍和接线

红外避障模块

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

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

CubeMX

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

2. 惯例配置更新代码

Keil

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

route_follow.c:
  1. #include "route_follow.h"
  2. #include "motor.h"
  3. #include "gpio.h"
  4. void route_follow_mode()
  5. {
  6. if((HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_5) == GPIO_PIN_RESET) && (HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_6) == GPIO_PIN_RESET)){ //此时左右都没有检测到黑线,说明在轨迹上,直走, 两个灯都亮
  7. move_forward();
  8. }
  9. if((HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_5) == GPIO_PIN_SET) && (HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_6) == GPIO_PIN_RESET)){ //此时左模块检测到黑线,说明车身偏右即将离开轨道,此时需要左转修正,只有右灯亮
  10. move_rightturn();
  11. }
  12. if((HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_5) == GPIO_PIN_RESET) && (HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_6) == GPIO_PIN_SET)){ //此时右模块检测到黑线,说明车身偏左即将离开轨道,此时需要右转修正,只有左灯亮
  13. move_leftturn();
  14. }
  15. if((HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_5) == GPIO_PIN_SET) && (HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_6) == GPIO_PIN_SET)){ //此时左右都检测到黑线,说明不在轨迹上了,停止,两个灯都灭
  16. move_stop();
  17. }
  18. }

route_follow.h:

  1. #ifndef __route_follow_H__ // "XXXX"就是h文件的名字
  2. #define __route_follow_H__
  3. void route_follow_mode(void);
  4. #endif
main.c:
  1. #include "motor.h"
  2. #include "route_follow.h"
  3. int main(void)
  4. {
  5. //HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_1); //打开Timer2的1号Channel, 1号通道对应 左轮
  6. //HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_2); //打开Timer2的2号Channel, 2号通道对应 右轮
  7. while (1)
  8. {
  9. route_follow_mode();
  10. }
  11. }

实现效果

实现效果和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:
  1. #include "SG90.h"
  2. #include "tim.h"
  3. int angle;
  4. void head_right()
  5. {
  6. angle = 0;
  7. __HAL_TIM_SetCompare(&htim2, TIM_CHANNEL_3, 5); //0度
  8. }
  9. void head_middle()
  10. {
  11. angle = 1;
  12. __HAL_TIM_SetCompare(&htim2, TIM_CHANNEL_3, 15); //90度
  13. }
  14. void head_left()
  15. {
  16. angle = 2;
  17. __HAL_TIM_SetCompare(&htim2, TIM_CHANNEL_3, 25); //180度
  18. }
SG90.h:
  1. #ifndef __SG90_H__ // "XXXX"就是h文件的名字
  2. #define __SG90_H__
  3. void head_right(void);
  4. void head_middle(void);
  5. void head_left(void);
  6. #endif
HC_SR04.c:
  1. #include "HC_SR04.h"
  2. #include "SG90.h"
  3. #include "gpio.h"
  4. #include "tim.h"
  5. #include "motor.h"
  6. double dist_middle;
  7. double dist_left;
  8. double dist_right;
  9. void StartHC()
  10. {
  11. HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_RESET); //Trig写0
  12. HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_SET); //Trig写1
  13. HAL_Delay(10);
  14. HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_RESET); //Trig写0
  15. }
  16. double get_dist()
  17. {
  18. int cnt;
  19. double dist;
  20. StartHC();
  21. while((HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_4)) == GPIO_PIN_RESET); //等待Echo变高的一瞬间
  22. HAL_TIM_Base_Start(&htim3); //TIM3开始计时
  23. __HAL_TIM_SetCounter(&htim3,0); //将TIM3的计数器置0
  24. while((HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_4)) == GPIO_PIN_SET); //等待Echo变低的一瞬间
  25. HAL_TIM_Base_Stop(&htim3); //TIM3停止计时
  26. cnt = __HAL_TIM_GetCounter(&htim3);//求出计了多少次,由于计数一次经过的时间是1us
  27. dist = cnt*340/2*0.000001*100; //求出距离
  28. return dist;
  29. }
  30. void deal_dist()
  31. {
  32. dist_middle = get_dist();
  33. if(dist_middle > 35){ //如果距离大于35cm就可以前进
  34. move_forward();//前进
  35. }else if((dist_middle > 10) && (dist_middle < 35)){ //距离小于35cm但大于10cm时
  36. move_stop();//先停下
  37. head_left();//将测距传感器通过SG90转到左边
  38. dist_left = get_dist();
  39. HAL_Delay(300);//根据实际情况
  40. head_right();//将测距传感器通过SG90转到右边
  41. dist_right = get_dist();
  42. HAL_Delay(300);//根据实际情况
  43. if(dist_right > dist_left){ //哪边距离大往哪边转
  44. move_rightturn();
  45. HAL_Delay(300);//根据实际情况
  46. move_stop();
  47. }else{
  48. move_leftturn();
  49. HAL_Delay(300);//根据实际情况
  50. move_stop();
  51. }
  52. }else{ //当距离已经小于10cm时
  53. move_backward();//此时距离已经危险了,需要后退一下
  54. HAL_Delay(300);//根据实际情况
  55. move_stop();
  56. }
  57. }
HC_SR04.h:
  1. #ifndef __HC_SR04_H__ // "XXXX"就是h文件的名字
  2. #define __HC_SR04_H__
  3. void deal_dist(void);
  4. #endif

main.c: 

  1. #include "SG90.h"
  2. #include "HC_SR04.h"
  3. extern int angle;
  4. int main(void)
  5. {
  6. //HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_1); //打开Timer2的1号Channel, 1号通道对应 左轮
  7. //HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_2); //打开Timer2的2号Channel, 2号通道对应 右轮
  8. HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_3); //打开Timer2的3号Channel, 控制SG90
  9. head_middle();
  10. while (1)
  11. {
  12. if(angle != 1){ //如果不在中间的话,回到中间
  13. head_middle();
  14. HAL_Delay(300);
  15. }
  16. deal_dist();
  17. HAL_Delay(50); //重要
  18. }
  19. }

实现效果

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

 

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/article/detail/46483
推荐阅读
相关标签
  

闽ICP备14008679号