当前位置:   article > 正文

基于STM32和激光雷达的路径规划_stm32小车路径规划

stm32小车路径规划

在上一篇文章中,我们可以用激光雷达得到精确的雷达数据了,根据这些数据,我们可以用程

序画个图验证一下。

可以发现,我们得到的点是非常准确的,噪点也很少。那么我们可以据此导航了。

关于算法目标,就是避开矩形障碍物,找到圆弧所在的角度。

在算法编写过程中,我也深刻的感受到32算力相当有限。接收雷达数据由串口中断接收,我一旦在主函数里面放入运算量比较大的任务,比如说解算,那么我收到的数据就很不准。或者说直接报错说内存不够了。

我的想法是,32算力不够,那我就只设置一个360个数据的数组,对应360个角度,存放各个角度的数据。

又得知测试所用的圆筒,半径135mm左右,那么,就可以根据这个半径,在雷达扫描到的点中,检索符合这个条件的弧形,具体代码如下可见

  1. #include "cmath"
  2. int map[360]={0};
  3. int x[360]={0};
  4. int y[360]={0};
  5. int center_x[360]={0};
  6. int center_y[360]={0};
  7. int score[360]={0};
  8. int re(void)//得到角度
  9. {
  10. int i=0,j=0;
  11. for(i=0;i<360;i++)//360个圆心
  12. {
  13. for(j=0;j<360;j++)//遍历360个点
  14. {
  15. if(x[j]!=0&&y[j]!=0)
  16. {
  17. if((pow(x[j]-center_x[i],2)+pow(y[j]-center_y[i],2))<17900&&(pow(x[j]-center_x[i],2)+pow(y[j]-center_y[i],2))>15900)
  18. {score[i]++;}
  19. }
  20. }
  21. }
  22. j=0;
  23. for(i=0;i<360;i++)
  24. {
  25. if(score[j]<score[i])
  26. {j=i;}
  27. }
  28. return j;
  29. }
  30. int quality(void)
  31. {
  32. int i=0,c=0;
  33. for(i=0;i<360;i++)
  34. {
  35. if(map[i]!=0)
  36. {c++;}
  37. }
  38. return c;
  39. }
  40. void change(void)
  41. {
  42. int i=0;float ceta=0.0;
  43. for(i=0;i<360;i++)
  44. {
  45. ceta=i*0.01745;
  46. x[i]=map[i]*cos(ceta);
  47. y[i]=map[i]*sin(ceta);
  48. }
  49. }
  50. void get_center(void)
  51. {
  52. int i=0;float ceta=0.0;
  53. for(i=0;i<360;i++)
  54. {
  55. ceta=i*0.01745;
  56. center_x[i]=(map[i]+132)*cos(ceta);
  57. center_y[i]=(map[i]+132)*sin(ceta);
  58. }
  59. }
  60. void zero(void)
  61. {
  62. int i=0;
  63. for(i=0;i<360;i++)
  64. {
  65. map[i]=0;x[i]=0;y[i]=0;center_x[i]=0;center_y[i]=0;score[i]=0;
  66. }
  67. }

 我这个解算大大减少了运算量,通过比较各个角度的的分值,确定最佳的角度。

由于我使用了两块STM32,所以我决定通过串口通讯连接上位机与下位机,由下位机将角度信息传给上位机,上位机比较角度信息与算法得到的目标角度,得到小车的运动状态,然后上位机将状态用串口传给下位机,实现小车的运行。

为了实现更好的效果,我设定在接收十万个点的数据后,进行一次解算,小车同时运动3秒左右,一点一点走,就可以比较好的逼近目标。

以下为上位机主函数

  1. while(1)
  2. {
  3. //LCD_ShowNum(50,50,Yaw,40,16);
  4. if(caokong==1)
  5. {
  6. while(1)
  7. {
  8. //delay_ms(50);
  9. delay(50);
  10. if(Yaw>direction+15)
  11. {
  12. UART1_TX(0x62);
  13. }
  14. else if(Yaw<direction-15)
  15. {
  16. UART1_TX(0x61);
  17. }
  18. else if(Yaw<direction+15&&Yaw>direction-15)
  19. {
  20. UART1_TX(0x63);
  21. }
  22. j++;
  23. if(j>60)
  24. {
  25. TIM_SetCompare2(TIM3,70);
  26. caokong=0;
  27. j=0;
  28. for(r=0;r<10;r++)
  29. {
  30. UART1_TX(0x64);
  31. delay_ms(10);
  32. }
  33. zero();
  34. break;
  35. }
  36. }
  37. }
  38. if(jyj)
  39. {
  40. hhh++;
  41. //printf("%c",m);
  42. if(flag==1)
  43. {
  44. RX_buffer[count]=m;
  45. count++;
  46. if(count==4)//开始解算数据
  47. {
  48. if(!(RX_buffer[0]&0x01))
  49. {
  50. flag=0;count=0;
  51. }
  52. //angle2=(RX_buffer[1]<<7|RX_buffer[0]>>1);
  53. angle2=(RX_buffer[1]<<7|RX_buffer[0]>>1);
  54. distance=(RX_buffer[3]<<6|RX_buffer[2]>>2);
  55. if(distance!=0&&count!=0)
  56. {
  57. //printf("distance=%d\n",RX_buffer[3]<<6|RX_buffer[2]>>2);
  58. //printf("\r\n");
  59. //printf("angle=%d\n",angle2);
  60. //printf("\r\n");
  61. if(map[angle2/64]!=0)
  62. {
  63. map[angle2/64]=(distance+map[angle2/64])/2;
  64. }
  65. else
  66. {
  67. map[angle2/64]=distance;
  68. }
  69. }
  70. flag=0;//点的检测标志归位
  71. count=0;//计数归0
  72. }
  73. }
  74. if(flag==0)//点的检测标志
  75. {
  76. if(m==0x3E)//检测到点
  77. {
  78. flag=1;
  79. }
  80. }
  81. jyj=0;
  82. }
  83. //if(quality()>350)
  84. if(hhh>100000)
  85. {
  86. change();
  87. get_center();
  88. direction=re();
  89. //UART1_TX(0xf1);
  90. //UART1_TX(direction>>8);//先发高位,再发低位
  91. //UART1_TX(direction);
  92. LCD_ShowNum(50,50,direction,40,16);
  93. caokong=1;
  94. hhh=0;
  95. TIM_SetCompare2(TIM3,98);
  96. }
  97. }

以下为下位机的主要函数,在中断中运行

每次新的解算开始时,mpu6050初始化一次,实现坐标的变换

  1. if(Yaw<0)
  2. {
  3. yy=-Yaw;
  4. usart2_send(0xff);
  5. usart2_send(yy>>8);//先发高位,再发低位
  6. usart2_send(yy);
  7. }
  8. else
  9. {
  10. yy=Yaw;
  11. usart2_send(0xfe);
  12. usart2_send(yy>>8);//先发高位,再发低位
  13. usart2_send(yy);
  14. }
  15. if(m==0x61)
  16. {
  17. Set_Pwm(1500,2000,0);
  18. }
  19. else if(m==0x62)
  20. {
  21. Set_Pwm(2000,1500,0);
  22. }
  23. else if(m==0x63)
  24. {
  25. Set_Pwm(1500,1500,0);
  26. mm=1;
  27. }
  28. else{Set_Pwm(0,0,0);mm=0;}
  29. if(m==0x64)
  30. {
  31. MPU6050_initialize(); //=====MPU6050初始化
  32. DMP_Init(); //=====初始化DMP
  33. }
  34. if(mm==1)
  35. {
  36. Set_Pwm(1500,1500,0);
  37. }
  38. }

在测试后,也是发现识别圆弧效果比较好,但是还有一个避障的问题。

于是,通过更改每次运动旋转、直走的角度,虽然不能每次都通过测试,但也实现了一定的成功率。

总结来看,本次项目,嵌入式部分,是一个“字节跳动”的感觉,激光雷达超级快的发送字节,让精准接收数据成了很困难的挑战。32的任务分配,任务调度,外设的配置,如何更好的配合算法。在调试过程中,也涉及到很多字节、数据类型方面的知识,比如说串口发送、解算浮点数据。意识到,在计算机的世界中,二进制,十六进制,字节,这种基本的语言是如何实现操作寄存器,机器与机器之间互相沟通的。

算法部分,我认为最大的困难就是,用尽可能少的运算,实现想要的功能。小组中也有同学写过更高识别能力的算法,但是都因为内存占用过多,而无法部署到32上,这就很考验算法能力。

在这次项目中,也认识到自己对32还不够熟悉,代码很不美观,任务调度也非常简陋。没有很好利用32的能力。路漫漫其修远兮,诸君共勉。

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

闽ICP备14008679号