小伙伴们,停更很久的RT-Thread实战笔记来啦,本章节教大家如何打造一个属于自己的平衡车,废话不多说,来吧,淦!!!
RT-Thread
PID
PWM
MPU6050
编码器
定时器
线程
利用手中已经积灰多年的小模块,废物利用,打造一个专属的平衡车
某宝买的L298N电机驱动模组

或者TB6612,关于这两个模组的介绍就不多说了,大家可以自行百度下哈

陀螺仪选用的是用的比较多的[MPU6050],目前好像要停产了,价格也越来越贵

电机采用的是带有编码器的直流减速电机,价格也略微贵一些




RT-Thread ART-PI控制板

亚克力板也是自己设计的尺寸图分享给大家

电机驱动接线:
| 电机 | ART-PI |
|---|---|
| PWMA | PB0 |
| IN1 | H14 |
| IN2 | C7 |
| IN3 | G10 |
| In4 | I6 |
| PWMB | PB1 |
| 12V | / |
| 5V | 5V |
| GND | GND |
MPU6050接线
| MPU6050 | ART-PI |
|---|---|
| 3.3V | 3.3V |
| GND | GND |
| SCL | PH11 |
| SDA | PH12 |
左电机与电机驱动模组:
| 电机 | ART-PI | 电机驱动模组 |
|---|---|---|
| 电机+ | / | OUT1 |
| 编码器电源- | GND | |
| 编码器A | PA8 | |
| 编码器B | PA9 | |
| 编码器电源+ | 3.3V/5V | |
| 电机- | / | OUT2 |
右电机与电机驱动模组:
| 电机 | ART-PI | 电机驱动模组 |
|---|---|---|
| 电机+ | / | OUT3 |
| 编码器电源- | GND | |
| 编码器A | PA1 | |
| 编码器B | PA15 | |
| 编码器电源+ | 3.3V/5V | |
| 电机- | / | OUT4 |
代码很多,主要介绍下,具体的大家可以看源码,源码都是开源的哈
软件包只用了按键和MPU6050的软件包,IIC用的是PH11和PH12
MPU6050驱动
移植的是DMP驱动,也可以用rt-thread软件包里面配置,我是自己移植过来的,也非常的简单,写好接口就可以了
- /**
- * @author:小飞哥玩嵌入式-小飞哥
- * @TODO:mpu6050初始化
- * @param NULL
- * @return NULL
- */
- void mpu_measurement_init(void)
- {
- i2c_bus = (struct mpu6xxx_device *) mpu6xxx_init(MPU6050_I2C_BUS_NAME, MPU6050_ADDR); //初始化MPU6050,测量单位为角速度,加速度 while(count++)
-
- rt_int8_t res = 1;
- while (res)
- {
- res = mpu_dmp_init();
- rt_kprintf("\r\nRES = %d\r\n",res);
-
- rt_thread_mdelay(500);
- rt_kprintf("\r\nMPU6050 DMP init Error\r\n");
- }
- rt_kprintf("\r\nMPU6050 DMP init OK\r\n");
- }
- /**
- * @author:小飞哥玩嵌入式-小飞哥
- * @TODO:MPU写入多字节数据
- * @param NULL
- * @return NULL
- */
- rt_uint8_t MPU_Write_Len(rt_uint8_t addr,rt_uint8_t reg,rt_uint8_t len,rt_uint8_t *databuf)
- {
- rt_int8_t res = 0;
- #ifdef RT_USING_I2C
- struct rt_i2c_msg msgs;
- rt_uint8_t buf[50] = {0};
- #endif
- buf[0] = reg;
-
- for(int i = 0;i<len;i++)
- {
- buf[i+1]=databuf[i];
- }
-
- if (i2c_bus->bus->type == RT_Device_Class_I2CBUS)
- {
- msgs.addr = i2c_bus->i2c_addr; /* slave address */
- msgs.flags = RT_I2C_WR; /* write flag */
- msgs.buf = buf; /* Send data pointer */
- msgs.len = len+1;
-
- if (rt_i2c_transfer((struct rt_i2c_bus_device *)i2c_bus->bus, &msgs, 1) == 1)
- {
- res = RT_EOK;
- }
- else
- {
- res = -RT_ERROR;
- }
- }
- }
- /**
- * @author:小飞哥玩嵌入式-小飞哥
- * @TODO:mpu读取多字节数据
- * @param NULL
- * @return NULL
- */
- rt_uint8_t MPU_Read_Len(rt_uint8_t addr,rt_uint8_t reg,rt_uint8_t len,rt_uint8_t *buf)
- {
- rt_int8_t res = 0;
- #ifdef RT_USING_I2C
- struct rt_i2c_msg msgs[2];
- #endif
- #ifdef RT_USING_SPI
- rt_uint8_t tmp;
- #endif
- if (i2c_bus->bus->type == RT_Device_Class_I2CBUS)
- {
- msgs[0].addr = i2c_bus->i2c_addr; /* Slave address */
- msgs[0].flags = RT_I2C_WR; /* Write flag */
- msgs[0].buf = ® /* Slave register address */
- msgs[0].len = 1; /* Number of bytes sent */
-
- msgs[1].addr = i2c_bus->i2c_addr; /* Slave address */
- msgs[1].flags = RT_I2C_RD; /* Read flag */
- msgs[1].buf = buf; /* Read data pointer */
- msgs[1].len = len; /* Number of bytes read */
-
- if (rt_i2c_transfer((struct rt_i2c_bus_device *)i2c_bus->bus, msgs, 2) == 2)
- {
- res = RT_EOK;
- }
- else
- {
- res = -RT_ERROR;
- }
- }
-
- return res;
- }
然后对接到inv_mpu.c里面的接口函数

电机驱动
- /**
- * @author:小飞哥玩嵌入式-小飞哥
- * @TODO:小车电机控制初始化
- * @param NULL
- * @return NULL
- */
- void rt_balanceCar_pinInit(void)
- {
- rt_pin_mode(motor_A1, PIN_MODE_OUTPUT );
- rt_pin_mode(motor_A2, PIN_MODE_OUTPUT );
- rt_pin_mode(motor_B1, PIN_MODE_OUTPUT );
- rt_pin_mode(motor_B2, PIN_MODE_OUTPUT );
-
- rt_pin_write(motor_A1,PIN_LOW);
- rt_pin_write(motor_A2,PIN_LOW);
- rt_pin_write(motor_B1,PIN_LOW);
- rt_pin_write(motor_B2,PIN_LOW);
- }
- /**
- * @author:小飞哥玩嵌入式-小飞哥
- * @TODO:小车左轮前进
- * @param NULL
- * @return NULL
- */
- void rt_balanceCar_LeftMotorforward(void)
- {
- rt_pin_write(motor_B1,PIN_LOW);
- rt_pin_write(motor_B2,PIN_HIGH);
- }
- /**
- * @author:小飞哥玩嵌入式-小飞哥
- * @TODO:小车左轮后退
- * @param NULL
- * @return NULL
- */
- void rt_balanceCar_LeftMotorback(void)
- {
- rt_pin_write(motor_B1,PIN_HIGH);
- rt_pin_write(motor_B2,PIN_LOW);
- }
- /**
- * @author:小飞哥玩嵌入式-小飞哥
- * @TODO:小车右轮前进
- * @param NULL
- * @return NULL
- */
- void rt_balanceCar_RightMotorforward(void)
- {
- rt_pin_write(motor_A1,PIN_LOW);
- rt_pin_write(motor_A2,PIN_HIGH);
- }
- /**
- * @author:小飞哥玩嵌入式-小飞哥
- * @TODO:小车右轮后退
- * @param NULL
- * @return NULL
- */
- void rt_balanceCar_RightMotorback(void)
- { rt_pin_write(motor_A1,PIN_HIGH);
- rt_pin_write(motor_A2,PIN_LOW);
- }
- /**
- * @author:小飞哥玩嵌入式-小飞哥
- * @TODO:小车整机前进
- * @param NULL
- * @return NULL
- */
- void rt_balanceCar_forward(void)
- {
- rt_pin_write(motor_A1,PIN_HIGH);
- rt_pin_write(motor_A2,PIN_LOW);
- rt_pin_write(motor_B1,PIN_HIGH);
- rt_pin_write(motor_B2,PIN_LOW);
- }
- /**
- * @author:小飞哥玩嵌入式-小飞哥
- * @TODO:小车整机后退
- * @param NULL
- * @return NULL
- */
- void rt_balanceCar_back(void)
- {
- rt_pin_write(motor_A1,PIN_LOW);
- rt_pin_write(motor_A2,PIN_HIGH);
- rt_pin_write(motor_B1,PIN_LOW);
- rt_pin_write(motor_B2,PIN_HIGH);
- }
- /**
- * @author:小飞哥玩嵌入式-小飞哥
- * @TODO:小车整机左转
- * @param NULL
- * @return NULL
- */
- void rt_balanceCar_turnLeft(void)
- {
- rt_pin_write(motor_A1,PIN_LOW);
- rt_pin_write(motor_A2,PIN_LOW);
- rt_pin_write(motor_B1,PIN_HIGH);
- rt_pin_write(motor_B2,PIN_LOW);
- }
- /**
- * @author:小飞哥玩嵌入式-小飞哥
- * @TODO:小车整机右转
- * @param NULL
- * @return NULL
- */
- void rt_balanceCar_turnRight(void)
- {
- rt_pin_write(motor_A1,PIN_HIGH);
- rt_pin_write(motor_A2,PIN_LOW);
- rt_pin_write(motor_B1,PIN_LOW);
- rt_pin_write(motor_B2,PIN_LOW);
- }
- /**
- * @author:小飞哥玩嵌入式-小飞哥
- * @TODO:小车电机停转
- * @param NULL
- * @return NULL
- */
- void rt_balanceCar_stop(void)
- {
- rt_pin_write(motor_A1,PIN_LOW);
- rt_pin_write(motor_A2,PIN_LOW);
- rt_pin_write(motor_B1,PIN_LOW);
- rt_pin_write(motor_B2,PIN_LOW);
- }
-
PWM控制
- /**
- * @author:小飞哥玩嵌入式-小飞哥
- * @TODO:pwm使能
- * @param NULL
- * @return NULL
- */
- void rt_balanceCar_pwmEnable(void)
- {
- rt_pwm_enable(pwm_dev, PWM_DEV_CHANNEL3);
- rt_pwm_enable(pwm_dev, PWM_DEV_CHANNEL4);
- }
- /**
- * @author:小飞哥玩嵌入式-小飞哥
- * @TODO:pwm失能
- * @param NULL
- * @return NULL
- */
- void rt_balanceCar_pwmDisable(void)
- {
- rt_pwm_disable(pwm_dev, PWM_DEV_CHANNEL3);
- rt_pwm_disable(pwm_dev, PWM_DEV_CHANNEL4);
- }
-
- /**
- * @author:小飞哥玩嵌入式-小飞哥
- * @TODO:pwm输出限幅
- * @param pwm1
- * @param pwm2
- * @return NULL
- */
- void rt_balanceCar_pwmlimit(rt_int32_t *pwm1,rt_int32_t *pwm2)
- {
- if(*pwm1 >= PWM_UPPER_LIMIT)
- {
- *pwm1 = PWM_UPPER_LIMIT;
- }
- else if(*pwm1 <= PWM_LOWER_LIMIT)
- {
- *pwm1 = PWM_LOWER_LIMIT;
- }
-
- if(*pwm2 >= PWM_UPPER_LIMIT)
- {
- *pwm2 = PWM_UPPER_LIMIT;
- }
- else if(*pwm2 <= PWM_LOWER_LIMIT)
- {
- *pwm2 = PWM_LOWER_LIMIT;
- }
- }
- /**
- * @author:小飞哥玩嵌入式-小飞哥
- * @TODO:pwm设置
- * @param channel1
- * @param channel2
- * @param L_speed
- * @param R_speed
- * @return NULL
- */
- void rt_balanceCar_pwmSet(rt_uint8_t channel1,rt_uint8_t channel2,rt_int32_t L_speed,rt_int32_t R_speed)
- {
- //输出限幅
- rt_balanceCar_pwmlimit(&L_speed,&R_speed);
-
- //pwm设置
- rt_pwm_set(pwm_dev, channel1, PWM_PERIOD, _ABS(L_speed));
- rt_pwm_set(pwm_dev, channel2, PWM_PERIOD, _ABS(R_speed));
- /*
- rt_pwm_enable(pwm_dev, channel1);
- rt_pwm_enable(pwm_dev, channel2);
- */
- }
- /**
- * @author:小飞哥玩嵌入式-小飞哥
- * @TODO:pwm初始化
- * @param NULL
- * @return NULL
- */
- rt_int8_t rt_balanceCar_pwmInit(void)
- {
- pwm_dev = (struct rt_device_pwm *)rt_device_find(PWM_DEV_NAME);
- if (pwm_dev == RT_NULL)
- {
- rt_kprintf("\r\npwm sample run failed! can't find %s device!\r\n", PWM_DEV_NAME);
- return RT_ERROR;
- }
- rt_kprintf("\r\npwm sample run success! find %s device!\r\n", PWM_DEV_NAME);
-
- //关闭PWM
- //rt_pwm_disable(pwm_dev, PWM_DEV_CHANNEL3);
- //rt_pwm_disable(pwm_dev, PWM_DEV_CHANNEL4);
- //开启PWM
- rt_pwm_enable(pwm_dev, PWM_DEV_CHANNEL3);
- rt_pwm_enable(pwm_dev, PWM_DEV_CHANNEL4);
- return RT_EOK;
- }
编码器
编码器驱动是把HAL库的驱动移植过来的,直接复制粘贴就可以了
- /* USER CODE END 0 */
-
- TIM_HandleTypeDef htim1;
- TIM_HandleTypeDef htim2;
- /* TIM1 init function */
-
- /**
- * @brief TIM1 Initialization Function
- * @param None
- * @retval None
- */
- static void MX_TIM1_Init(void)
- {
-
- /* USER CODE BEGIN TIM1_Init 0 */
-
- /* USER CODE END TIM1_Init 0 */
-
- TIM_Encoder_InitTypeDef sConfig = {0};
- TIM_MasterConfigTypeDef sMasterConfig = {0};
-
- /* USER CODE BEGIN TIM1_Init 1 */
-
- /* USER CODE END TIM1_Init 1 */
- htim1.Instance = TIM1;
- htim1.Init.Prescaler = 0;
- htim1.Init.CounterMode = TIM_COUNTERMODE_UP;
- htim1.Init.Period = 65535;
- htim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
- htim1.Init.RepetitionCounter = 0;
- htim1.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
- sConfig.EncoderMode = TIM_ENCODERMODE_TI1;
- sConfig.IC1Polarity = TIM_ICPOLARITY_RISING;
- sConfig.IC1Selection = TIM_ICSELECTION_DIRECTTI;
- sConfig.IC1Prescaler = TIM_ICPSC_DIV1;
- sConfig.IC1Filter = 0;
- sConfig.IC2Polarity = TIM_ICPOLARITY_RISING;
- sConfig.IC2Selection = TIM_ICSELECTION_DIRECTTI;
- sConfig.IC2Prescaler = TIM_ICPSC_DIV1;
- sConfig.IC2Filter = 0;
- if (HAL_TIM_Encoder_Init(&htim1, &sConfig) != HAL_OK)
- {
- Error_Handler();
- }
- sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
- sMasterConfig.MasterOutputTrigger2 = TIM_TRGO2_RESET;
- sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
- if (HAL_TIMEx_MasterConfigSynchronization(&htim1, &sMasterConfig) != HAL_OK)
- {
- Error_Handler();
- }
- /* USER CODE BEGIN TIM1_Init 2 */
-
- /* USER CODE END TIM1_Init 2 */
-
- }
-
- /**
- * @brief TIM2 Initialization Function
- * @param None
- * @retval None
- */
- static void MX_TIM2_Init(void)
- {
-
- /* USER CODE BEGIN TIM2_Init 0 */
-
- /* USER CODE END TIM2_Init 0 */
-
- TIM_Encoder_InitTypeDef sConfig = {0};
- TIM_MasterConfigTypeDef sMasterConfig = {0};
-
- /* USER CODE BEGIN TIM2_Init 1 */
-
- /* USER CODE END TIM2_Init 1 */
- htim2.Instance = TIM2;
- htim2.Init.Prescaler = 0;
- htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
- htim2.Init.Period = 4294967295;
- htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
- htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
- sConfig.EncoderMode = TIM_ENCODERMODE_TI1;
- sConfig.IC1Polarity = TIM_ICPOLARITY_RISING;
- sConfig.IC1Selection = TIM_ICSELECTION_DIRECTTI;
- sConfig.IC1Prescaler = TIM_ICPSC_DIV1;
- sConfig.IC1Filter = 0;
- sConfig.IC2Polarity = TIM_ICPOLARITY_RISING;
- sConfig.IC2Selection = TIM_ICSELECTION_DIRECTTI;
- sConfig.IC2Prescaler = TIM_ICPSC_DIV1;
- sConfig.IC2Filter = 0;
- if (HAL_TIM_Encoder_Init(&htim2, &sConfig) != HAL_OK)
- {
- Error_Handler();
- }
- sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
- sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
- if (HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig) != HAL_OK)
- {
- Error_Handler();
- }
- /* USER CODE BEGIN TIM2_Init 2 */
-
- /* USER CODE END TIM2_Init 2 */
-
- }
- /**
- * @author:小飞哥玩嵌入式-小飞哥
- * @TODO:清除编码器数值
- * @param NULL
- * @return NULL
- */
- void encoder_clearCounter(void)
- {
- __HAL_TIM_SET_COUNTER(&htim1,0);
- __HAL_TIM_SET_COUNTER(&htim2,0);
- }
- /**
- * @author:小飞哥玩嵌入式-小飞哥
- * @TODO:获取编码器数值
- * @param out s_encoder_measure
- * @return NULL
- */
- void encoder_getCounter(rt_int32_t *l_speed,rt_int32_t *r_speed)
- {
- *l_speed = ((rt_int32_t)__HAL_TIM_GET_COUNTER(&htim1)-COUNTER_RESET);
- *r_speed = (rt_int32_t)__HAL_TIM_GET_COUNTER(&htim2)-COUNTER_RESET;
-
- encoder_clearCounter();
- }
- /**
- * @author:小飞哥玩嵌入式-小飞哥
- * @TODO:编码器初始化
- * @param NULL
- * @return NULL
- */
- int hw_Encoder_init(void)
- {
- MX_TIM1_Init();
- MX_TIM2_Init();
-
- HAL_TIM_Encoder_Start(&htim1,TIM_CHANNEL_ALL);
- HAL_TIM_Encoder_Start(&htim2,TIM_CHANNEL_ALL);
-
- rt_kprintf("\r\ntim1,tim2 init ok\r\n");
- }
PID控制算法
PID采用的是位置式PID,关于位置式PID,本章也不再具体介绍了,主要包括直立环、转向环、速度环三个控制环
- /**
- * @author:小飞哥玩嵌入式-小飞哥
- * @TODO:PID参数初始化
- * @param NULL
- * @param NULL
- * @return NULL
- */
- void pid_init(void)
- {
- s_pid.kp_speed = -0.35;//速度环kp值
- s_pid.kp_stand = -1600*0.6;//直立环kp值
-
-
- s_pid.ki = s_pid.kp_speed/200;
- s_pid.kd = 65*0.6;
-
- s_pid.kp_turn = 20;
-
- s_pid.limit = 800;
- s_pid.err_current = 0;
- s_pid.err_last = 0;
- s_pid.err_sum = 0;
-
- s_pid.lowfilter_rate = 0.7;
-
- s_pid.mid_value = -1;
- }
-
- /**
- * @author:小飞哥玩嵌入式-小飞哥
- * @TODO:小车直立环控制
- * @param 当前角度
- * @param 目标角度
- * @param 真实角速度
- * @return pwm值
- */
-
- rt_int32_t balance_stand(float current_angle,float target_angle,float gyro_y)
- {
- rt_int32_t s_pwm_out;
-
- s_pwm_out = s_pid.kp_stand *(target_angle - current_angle) + s_pid.kd * gyro_y;
-
- return s_pwm_out ;
- }
- /**
- * @author:小飞哥玩嵌入式-小飞哥
- * @TODO:小车速度环控制
- * @param 左轮编码器
- * @param 右轮编码器
- * @param 目标值
- * @return pwm值
- */
- rt_int32_t balance_speed(rt_int32_t encoder_left,rt_int32_t encoder_right,rt_int32_t target)
- {
- rt_int32_t s_pwm_out;
- //计算当前误差
- s_pid.err_current = encoder_left + encoder_right - target;
- //低通滤波器,low_filter_out = (1-a)*Ek+a*low_filter_out_last
- s_pid.lowfilter_out = (1-s_pid.lowfilter_rate)*s_pid.err_current + s_pid.lowfilter_out_last*s_pid.lowfilter_rate;
- s_pid.lowfilter_out_last = s_pid.lowfilter_out;
- //速度环偏差积分,积分出位移
- s_pid.err_sum += s_pid.lowfilter_out;
- //积分限幅
- s_pid.err_sum = s_pid.err_sum>50000?50000:((s_pid.err_sum<-50000)?-50000:s_pid.err_sum);
- //速度环计算输出
- s_pwm_out = s_pid.kp_speed * s_pid.lowfilter_out + s_pid.ki * s_pid.err_sum;
-
- return s_pwm_out;
- }
-
- /**
- * @author:小飞哥玩嵌入式-小飞哥
- * @TODO:小车转向环控制
- * @param gyro_z
- * @return pwm值
- */
- rt_int32_t balance_turn(rt_int32_t gyro_z)
- {
- rt_int32_t pwm_out;
- pwm_out = s_pid.kp_turn*gyro_z;
- return pwm_out;
- }
-
最终是主控制代码
- /**
- * @author:小飞哥玩嵌入式-小飞哥
- * @TODO:小车控制初始化
- * @param NULL
- * @return NULL
- */
-
- //机械中值
-
- void rt_balanceCar_ctrlinit(void)
- {
- //pwm初始化
- rt_balanceCar_pwmInit();
- //电机控制IO初始化
- rt_balanceCar_pinInit();
- //PID参数初始化
- pid_init();
- //MPU6050初始化
- mpu_measurement_init();
- //mpu6050中断初始化
- mpu6050_isr_init();
- //编码器初始化
- hw_Encoder_init();
- //按键初始化
- rt_key_init();
- }
- //INIT_COMPONENT_EXPORT(rt_balanceCar_ctrlinit);
- /**
- * @author:小飞哥玩嵌入式-小飞哥
- * @TODO:小车运动控制
- * @param NULL
- * @return NULL
- */
- void rt_balanceCar_ctrl(rt_int32_t motor_l,rt_int32_t motor_r)
- {
- if(motor_l > 0)
- {
- rt_balanceCar_LeftMotorforward();
- }
- else {
-
- rt_balanceCar_LeftMotorback();
- }
-
- if(motor_r > 0)
- {
- rt_balanceCar_RightMotorforward();
- }
- else {
-
- rt_balanceCar_RightMotorback();
- }
-
- rt_balanceCar_pwmSet(PWM_DEV_CHANNEL3,PWM_DEV_CHANNEL4,motor_l,motor_r);
- }
-
- /* 线程入口 */
- static void thread1_entry(void* parameter)
- {
- S_MEASURE_OUT s_measure_out;
- S_ENCODER_MEASURE s_encoder_measure;
- char str[32];
- static rt_int32_t pwm_out = 0;
-
-
- static rt_int32_t pwm_value_stand = 0;
- static rt_int32_t pwm_value_speed = 0;
- static rt_int32_t pwm_value_turn = 0;
-
- while(1)
- {
- //获取编码器数据
- encoder_getCounter(&s_encoder_measure.l_speed,&s_encoder_measure.r_speed);
- if(RT_EOK == rt_sem_take(RT_TIMER_SEM, 0xFFFF))
- {
- Button_Process(); //需要周期调用按键处理函数
-
-
- //获取陀螺仪数据
- //mpu_measurement_out(measure_out);
- mpu6xxx_get_gyro(i2c_bus,&s_measure_out.gyro);
-
- if (0==mpu_dmp_get_data(&s_measure_out.pitch, &s_measure_out.roll, &s_measure_out.yaw) )
- {
- //计算直立环PWM输出
- pwm_value_stand = balance_stand(s_measure_out.pitch,s_pid.mid_value,s_measure_out.gyro.y);
- //计算速度环PWM输出
- pwm_value_speed = balance_speed(s_encoder_measure.l_speed,s_encoder_measure.r_speed,0);
- //计算转向环输出
- pwm_value_turn = balance_turn(s_measure_out.gyro.z);
- //PWM输出
- pwm_out = pwm_value_stand - s_pid.kp_stand*pwm_value_speed;
- //PWM控制
- if(_ABS(s_measure_out.pitch)>30)//倾角>30度,关闭电机
- {
- rt_balanceCar_stop();
- pid_init();
- }
- else {
- rt_balanceCar_ctrl(pwm_out+pwm_value_turn,pwm_out-pwm_value_turn);
- }
- }
- static int i = 0;
- i++;
- if(i%50 == 0)
- {
- i = 0;
-
- rt_kprintf("\r\n\r\n\r\n");
-
- sprintf(str,"pitch=%.2f\r\n",s_measure_out.pitch);
- rt_kprintf(str);
-
- sprintf(str,"roll=%.2f\r\n",s_measure_out.roll);
- rt_kprintf(str);
-
- sprintf(str,"yaw=%.2f\r\n",s_measure_out.yaw);
- rt_kprintf(str);
- rt_kprintf("\r\n\r\n\r\n");
-
-
- sprintf(str,"gyro.x=%d\r\n",s_measure_out.gyro.x);
- rt_kprintf(str);
- sprintf(str,"gyro.y=%d\r\n",s_measure_out.gyro.y);
- rt_kprintf(str);
- sprintf(str,"gyro.z=%d\r\n",s_measure_out.gyro.z);
- rt_kprintf(str);
- rt_kprintf("\r\nencoder_l = %d\r\n",s_encoder_measure.l_speed);
- rt_kprintf("\r\nencoder_r = %d\r\n",s_encoder_measure.r_speed);
- rt_kprintf("\r\ns_pid.kp_stand = %d\r\n",(rt_int32_t)s_pid.kp_stand);
-
- }
-
- }
- }
- }
- /**
- * @author:小飞哥玩嵌入式-小飞哥
- * @TODO:小车控制线程创建
- * @param NULL
- * @return NULL
- */
- int balanceCar_sample(void)
- {
- static rt_thread_t tid1 = RT_NULL;
-
- rt_balanceCar_ctrlinit();
- /* 创建线程 */
- tid1=rt_thread_create(
- "thread1",
- thread1_entry,
- RT_NULL,
- THREAD_STACK_SIZE,
- THREAD_PRIORITY, THREAD_TIMESLICE);
- /* 如果获得线程控制块,启动这个线程 */
- if (tid1 != RT_NULL)
- rt_thread_startup(tid1);
- return 0;
- }
- /* 导出到 msh 命令列表中 */
- INIT_COMPONENT_EXPORT(balanceCar_sample);
至此,基本代码控制就完成了,内容很多,小飞哥可能会出视频讲,大家可以先自己看源码消化哈
欢迎关注小飞哥玩嵌入式,期待遇到优秀的你