找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 2896|回复: 1
打印 上一主题 下一主题
收起左侧

STM32安卓蓝牙遥控二轮自平衡小车全套设计资料(APP及源码PCB)

[复制链接]
跳转到指定楼层
楼主
Altium Designer画的二轮自平衡小车电路原理图和PCB图如下:(51hei附件中可下载工程文件)



上层和中层亚克力3D图及CAD图


安卓蓝牙遥控器APK及源码



整体BOM表格



02 - 姿态解算MCU源代码(STM32F103C8T6)
  1. /* main.c file
  2. 编写者:lisn3188
  3. 编译环境:MDK-Lite  Version: 4.23
  4. 测试: 本程序已在第七实验室的mini IMU上完成测试
  5. 功能:
  6. 1.初始化各个传感器,
  7. 2.运行姿态解算和高度测量
  8. 3.将解算的姿态和各个传感器的输出上传到 MiniIMU AHRS 测试软件
  9. 4.响应 PC发送的命令
  10. ------------------------------------*/

  11. /*----------------------------------------------------------------
  12. 修改备忘:(2014.08.28 by flotox)
  13. 1/去掉气压传感器数据接口
  14. 2/保持帧格式
  15. 3/数据输出频率调整为20hz
  16. 4/调整机头方向
  17. 5/保留陀螺仪标零偏
  18. 6/去掉UART1数据输出
  19. 7/只输出姿态数据结算帧
  20. 8/在数据融合时去掉磁力计的影响
  21. 9/上电数据即可用,不用等待
  22. ----------------------------------------------------------------*/

  23. #include "common.h"  //包含所有的驱动 头文件

  24. //上传数据的状态机
  25. #define REIMU  0x01 //上传解算的姿态数据
  26. #define REMOV  0x02        //上传传感器的输出
  27. #define REHMC  0x03        //上传磁力计的标定值

  28. #define Upload_Speed  100   //数据上传速度  单位 Hz
  29. #define upload_time (1000000/Upload_Speed)  //计算上传的时间。单位为us

  30. int16_t ax, ay, az;        
  31. int16_t gx, gy, gz;
  32. int16_t hx, hy, hz;
  33. int32_t Temperature = 0, Pressure = 0, Altitude = 0;
  34. uint32_t system_micrsecond;
  35. int16_t hmcvalue[3];
  36. u8 state= REIMU;  //发送特定帧 的状态机
  37. /**************************实现函数********************************************
  38. *函数原型:                int main(void)
  39. *功  能:                主程序
  40. *******************************************************************************/
  41. int main(void)
  42. {
  43.         int16_t Math_hz=0;
  44.         unsigned char PC_comm; //PC 命令关键字节         
  45.         float ypr[3]; // yaw pitch roll
  46.         /* 配置系统时钟为72M 使用外部8M晶体+PLL*/      
  47.     //SystemInit();
  48.         delay_init(72);                //延时初始化
  49.     Initial_LED_GPIO();        //初始化STM32-SDK板子上的LED接口
  50.         Initial_PWMLED();
  51.         Initial_UART2(115200L);
  52.         load_config();  //从flash中读取配置信息 -->eeprom.c
  53.         IIC_Init();         //初始化I2C接口
  54.         delay_ms(300);        //等待器件上电
  55.         //UART1_Put_String("Initialize...\r\n");
  56.         IMU_init(); //初始化IMU和传感器
  57.         system_micrsecond=micros();
  58.         while(1){        //主循环
  59.                
  60.         //delay_ms(1); //延时,不要算那么快。
  61.         IMU_getYawPitchRoll(ypr); //姿态更新
  62.         Math_hz++; //解算次数 ++

  63. //-------------上位机------------------------------
  64.         //是否到了更新 上位机的时间了?
  65.         if((micros()-system_micrsecond)>upload_time){
  66.         switch(state){
  67.         case REIMU:
  68.         UART2_ReportIMU((int16_t)(ypr[0]*10.0),(int16_t)(ypr[1]*10.0),
  69.         (int16_t)(ypr[2]*10.0),Altitude/10,Temperature,Pressure/10,Math_hz*Upload_Speed);
  70.         Math_hz=0;
  71. //        state = REMOV; //更改状态。
  72.         break;
  73.         case REMOV:
  74.         MPU6050_getlastMotion6(&ax, &ay, &az, &gx, &gy, &gz);
  75.         HMC58X3_getlastValues(&hx,&hy,&hz);
  76.         UART2_ReportMotion(ax,ay,az,gx,gy,gz,hx,hy,hz);
  77.         state = REIMU;
  78.         if(HMC5883_calib)state = REHMC; //需要发送当前磁力计标定值
  79.         break;
  80.         default:
  81.         UART2_ReportHMC(HMC5883_maxx,HMC5883_maxy,HMC5883_maxz,
  82.                  HMC5883_minx,HMC5883_miny,HMC5883_minz,0);//发送标定值
  83.         state = REIMU;
  84.         break;
  85.         }//switch(state)                          
  86.         system_micrsecond=micros();         //取系统时间 单位 us
  87.         LED_Change();        //LED1改变亮度
  88.         }
  89. //--------------------------------------------------
  90.         //处理PC发送来的命令
  91.         if((PC_comm=UART2_CommandRoute())!=0xff)
  92.         {
  93.         switch(PC_comm){ //检查命令标识
  94.         case Gyro_init:                        MPU6050_InitGyro_Offset(); break; //读取陀螺仪零偏
  95.         case High_init:                                 break;                //气压高度 清零
  96.         case HMC_calib_begin:        HMC5883L_Start_Calib();        break; //开始磁力计标定
  97.         case HMC_calib:                HMC5883L_Save_Calib();        break;   //保存磁力计标定
  98.         }
  99.         }// 处理PC 发送的命令

  100.         }//主循环 while(1) 结束

  101. }  //main        

  102. //------------------End of File----------------------------
复制代码


01 - 运动控制MCU源代码(STM32F103RCT6)
  1. /**---------------------------------------------------------------
  2.         项目:两轮自平衡小车(Two-Wheels Auto-Balancing Vechile)
  3.         版本:v1.0.0
  4.         文件: Balancing.c
  5.         功能:自平衡计算
  6.         作者:flotox@yeah.net
  7.         日期:2014.9.5
  8.         更新:2014.9.5
  9. ----------------------------------------------------------------*/

  10. #include "stm32f10x.h"
  11. #include "GlobalVars.h"
  12. #include "MotorDriver.h"

  13. // float                Temp[200] = {0};
  14. // uint32_t        Temp_i = 0;

  15. /**
  16.         *        @brief                自平衡计算外设初始化
  17.         *        @param                none
  18.         *        @retval                none
  19.         */
  20. void        Balancing_Init(void){
  21.         
  22.         GPIO_InitTypeDef                                GPIO_InitStructure;
  23.         TIM_TimeBaseInitTypeDef        TIM_TimeBaseStructure;
  24.         NVIC_InitTypeDef                                NVIC_InitStructure;
  25.         
  26.         /*开启GPIOC外设时钟*/
  27.         RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
  28.         /*开启TIM4外设时钟*/
  29.         RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);
  30.         
  31.         /*配置PC.15端口为Out_PP模式*/
  32.         GPIO_InitStructure.GPIO_Pin = GPIO_Pin_15;
  33.         GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  34.         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
  35.         GPIO_Init(GPIOC, &GPIO_InitStructure);
  36.         
  37.         /*TIM4 NVIC设置*/
  38.         NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);                                                                                                        //2 bits for pre-emption priority 2 bits for subpriority
  39.         
  40.         NVIC_InitStructure.NVIC_IRQChannel = TIM4_IRQn;
  41.         NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;                                                                //指定抢占式优先级别,可取0~3
  42.         NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;                                                                                        //指定响应式优先级别,可取0~3
  43.         NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  44.         NVIC_Init(&NVIC_InitStructure);
  45.         
  46.         TIM_DeInit(TIM4);
  47.         
  48.         /*定时器基本配置*/
  49.         TIM_TimeBaseStructure.TIM_Prescaler = 0;                                                                                                                                //时钟预分频数0,TIM4的时钟计数频率为72MHz
  50.         TIM_TimeBaseStructure.TIM_Period = 20 - 1;                                                                                                                        //自动重装载寄存器数20,10ms溢出1次
  51.         TIM_TimeBaseStructure.TIM_ClockDivision = 0;                                                                                                                //采样分频
  52.         TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;                                                        //向上计数
  53.         TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStructure);
  54.         
  55.         TIM_PrescalerConfig(TIM4, 0x8c9f, TIM_PSCReloadMode_Immediate);                                        //时钟分频系数36000,定时器时钟为2KHz
  56.         TIM_ARRPreloadConfig(TIM4, DISABLE);                                                                                                                                                //禁止ARR预装载缓冲器
  57.         TIM_ITConfig(TIM4, TIM_IT_Update, ENABLE);                                                                                                                        //使能Update中断
  58.         
  59.         TIM_Cmd(TIM4, ENABLE);                                                                                                                                                                                                        //开启时钟
  60. }

  61. /**
  62.         *        @brief                自平衡计算循环子程序(10ms被调用一次)
  63.         *        @param                none
  64.         *        @retval                none
  65.         */
  66. void        Balancing_Loop(void){

  67.         uiCount_Led++;
  68.         
  69.         /*Led闪烁*/
  70.         if(uiCount_Led >= 40){
  71.                
  72.                 uiCount_Led = 0;
  73.                 GPIO_WriteBit(GPIOC,GPIO_Pin_15,(BitAction)(1-GPIO_ReadOutputDataBit(GPIOC,GPIO_Pin_15)));
  74.         }
  75.         
  76.         switch(iMotion_Type){

  77.                 case        MOTION_TYPE_NONE:
  78.                         
  79.                         fTarget_Speed = 0;
  80.                         fTarget_Turn = 0;
  81.                         break;
  82.                
  83.                 case        MOTION_TYPE_FORWARDS:
  84.                         
  85.                         fTarget_Speed = -150;
  86.                         fTarget_Turn = 0;
  87.                         break;
  88.                
  89.                 case        MOTION_TYPE_BACKWARDS:
  90.                         
  91.                         fTarget_Speed = 150;                        //150
  92.                         fTarget_Turn = 0;
  93.                         break;
  94.                
  95.                 case        MOTION_TYPE_TURN_LEFT:
  96.                         
  97.                         fTarget_Speed = 0;
  98.                         fTarget_Turn = -210;
  99.                         break;
  100.                
  101.                 case        MOTION_TYPE_TURN_RIGHT:
  102.                         
  103.                         fTarget_Speed = 0;
  104.                         fTarget_Turn = 210;
  105.                         break;
  106.                
  107.                 case        MOTION_TYPE_FORWARDS_TURN_LEFT:
  108.                         
  109.                         fTarget_Speed = -150;
  110.                         fTarget_Turn = -210;
  111.                         break;
  112.                
  113.                 case        MOTION_TYPE_FORWARDS_TURN_RIGHT:
  114.                         
  115.                         fTarget_Speed = -150;
  116.                         fTarget_Turn = 210;
  117.                         break;
  118.                
  119.                 case        MOTION_TYPE_BACKWARDS_TURN_LEFT:
  120.                         
  121.                         fTarget_Speed = 150;
  122.                         fTarget_Turn = -210;
  123.                         break;
  124.                
  125.                 case        MOTION_TYPE_BACKWARDS_TURN_RIGHT:
  126.                         
  127.                         fTarget_Speed = 150;
  128.                         fTarget_Turn = 210;
  129.                         break;
  130.         }
  131.         
  132.         /*动作改变时增加中间的过度过程,过度过程为50ms*/
  133.         if((iMotion_Type != iMotion_Type_Last) && (iCount_Motion_Type_Change == 0)){
  134.                
  135.                 iCount_Motion_Type_Change = 10;
  136.                 iMotion_Type_Last = iMotion_Type;
  137.         }
  138.         
  139.         if(iCount_Motion_Type_Change != 0){
  140.                
  141.                 iCount_Motion_Type_Change --;
  142.                 fTarget_Speed = 0;
  143.                 fTarget_Turn = 0;
  144.         }
  145.         
  146.         /*速度和位移一阶低通滤波*/
  147.         fSpeed_Vechile = (iCount_L + iCount_R) * 0.5;
  148.         fSpeed_Vechile_F = fSpeed_Vechile_F * 0.7 + fSpeed_Vechile * 0.3;
  149.         
  150.         /*累加求位移*/
  151.         fPosition += fSpeed_Vechile_F;

  152.         /*位移调节量*/
  153.         fPosition += fTarget_Speed;

  154.         /*位移限制,上下限待调节*/
  155.         if(fPosition > 5000){                                                                                                                                //5000
  156.                
  157.                 fPosition = 5000;
  158.         }
  159.         else if(fPosition < -5000){
  160.                
  161.                 fPosition = -5000;
  162.         }
  163.         
  164.         /*左轮和右轮光栅脉冲计数器清零*/
  165.         iCount_L = 0;
  166.         iCount_R = 0;
  167.         
  168.         /*角度限制*/
  169.         if( (fPitchAngle < 40.0) && (fPitchAngle > -40.0) ){
  170.                
  171.                
  172.                 /*俯仰角速度,单位deg/s,大于0则角速度方向向前,小于0则角速度方向向后*/
  173.                 fAngle_Vel = -(fPitchAngle - fPitchAngle_Last);
  174.                
  175.                 /*保存此次俯仰角度*/
  176.                 fPitchAngle_Last = fPitchAngle;
  177.                
  178.                 /*计算PWM输出控制量*/
  179.                 fPWM =        (-fpid_angle) * fPitchAngle +
  180.                                                 fpid_angle_vel * fAngle_Vel +
  181.                                                 fpid_speed * fSpeed_Vechile_F +
  182.                                                 fPosition * fpid_position;
  183.                
  184.                 /*旋转调节量*/
  185.                 fPWM_L = fPWM + fTarget_Turn;
  186.                 fPWM_R = fPWM - fTarget_Turn;
  187.                
  188.                 /*左轮控制*/
  189.                 if(fPWM_L > 0){
  190.                         
  191.                         MotorDriver_L_Turn_Forward();
  192.                 }
  193.                 else{
  194.                         
  195.                         MotorDriver_L_Turn_Reverse();
  196.                         fPWM_L = -fPWM_L;
  197.                 }
  198.                         
  199.                 /*右轮控制*/
  200.                 if(fPWM_R > 0){
  201.                         
  202.                         MotorDriver_R_Turn_Forward();
  203.                 }
  204.                 else{
  205.                         
  206.                         MotorDriver_R_Turn_Reverse();
  207.                         fPWM_R = -fPWM_R;
  208.                 }
  209.                
  210.                 /*加上死区电压*/
  211.                 fPWM_L += 40;
  212.                 fPWM_R += 10;
  213.                
  214.                 /*限制PWM*/
  215.                 if(fPWM_L > 1000){
  216.                         
  217.                         fPWM_L = 1000;
  218.                 }
  219.                
  220.                 if(fPWM_R > 1000){
  221.                         
  222.                         fPWM_R = 1000;
  223.                 }
  224.                
  225.                 /*输出PWM控制量*/
  226.                 TIM_SetCompare2(TIM8, (uint16_t)fPWM_L);                                        //左轮
  227.                 TIM_SetCompare2(TIM1, (uint16_t)fPWM_R);                                        //右轮
  228.         }
  229.         /*倾角过大时的姿态数据不参与计算*/
  230.         else{
  231.                
  232.                 TIM_SetCompare2(TIM8, 0);                                                                                                        //左轮
  233.                 TIM_SetCompare2(TIM1, 0);                                                                                                        //右轮
  234.         }
  235.         
  236. }
复制代码



全部资料51hei下载地址:
二轮自平衡小车.rar (14.78 MB, 下载次数: 59)


分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏5 分享淘帖 顶 踩
回复

使用道具 举报

沙发
ID:1 发表于 2018-9-30 02:44 | 只看该作者
好资料,51黑有你更精彩!!!
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表