STC32G 三轮车负压电磁

前言

年后就没怎么碰车了,到3月中旬换三轮了,可算有一点成效了,做个记录。

整车效果

移步B站
18届负压电磁全元素
18届负压电磁无元素,速度纯享版
资源
工程代码

控制思路

循迹

角速度环以及速度环

差比和的结果与0做差得到的误差作为角速度环的输入。
角速度环的输出输出作为我们期望小车转向的角速度。

简单对差速小车建模,以顺时针方向的角速度为正参考方向,推导数学公式可得

v L r e f = v m + ω L 2 v_{Lref}=v_m+\frac{\omega L}{2} vLref=vm+2ωL
v R r e f = v m − ω L 2 v_{Rref}=v_m-\frac{\omega L}{2} vRref=vm2ωL

其中 v L r e f v_{Lref} vLref是左轮的参考速度, v R r e f v_{Rref} vRref是右轮的参考速度, v m v_m vm是小车整体的运行速度,或假想小车中心有一个轮子的运行速度, L L L是车模后轮的轮距,我测量的D车模的后轮距为0.17m, ω \omega ω为小车的角速度,即角速度环的输出

得到左右两轮子的参考速度以后,经过速度环控制后得到左右电机的占空比并幅值即可。

其中角速度环用PD控制,P环节用于放大误差送入矫正环节(在这里的三轮车矫正环节即控制两个轮子的速度以矫正误差),D环节用于抑制车体的震荡;速度环用PI控制,P放大误差进行速度调节,I用于消除静差,尤其是当我们上负压以后,I尤为重要。

由于三轮车的运动轨迹完全取决于两个轮子速度之间的关系,两个轮子的速度环控制必须做到快速而精准,需花时间调节速度环的参数。

电机PID参数整定

环岛处理

  1. 检测到圆环(预圆环)(某个电感大于某个阈值)
  2. 到达最佳入环位置(强制入环,直到陀螺仪大于某个,开始园内循迹)
  3. 圆内循迹
  4. 出环。

障碍处理

  1. 识别障碍**(TOF测距小于某个限制)**
  2. 避开障碍(左右轮固定差速,直到陀螺仪积分大于某个角度)
  3. 回到赛道(左右轮固定差速,直到陀螺仪为小于某个角度)
  4. 姿态调整(让小车的姿态基本与赛道平齐,直到陀螺仪角度在某个范围内或误差在某个范围内)

关键代码部分

差比和以及当前速度计算

三电感电磁循迹小车

角速度环

void dir_loop()
{
    float temp;
    pid_steer.ek =  0 - error;
    temp = pid_steer.KP * pid_steer.ek
           + imu660ra_gyro_z / 65.6;
//           + 300 * (pid_steer.ek - pid_steer.ek_1); // 参考角速度

    pid_motor_L.SetValue = speed_rate * speed_goal  -  temp * 0.0875;
    pid_motor_R.SetValue = speed_rate * speed_goal  +  temp * 0.0875;
}

速度环

void speed_loop()
{
    float inc_L, inc_R;
    // 限制内轮速度
    if(pid_motor_L.SetValue < 0)
        pid_motor_L.SetValue = 0;
    if(pid_motor_R.SetValue < 0)
        pid_motor_R.SetValue = 0;

    // 外轮速度限制
    if(pid_motor_L.SetValue > 2 * speed_goal * speed_rate)
        pid_motor_L.SetValue = 2 * speed_goal * speed_rate;
    if(pid_motor_R.SetValue > 2 * speed_goal * speed_rate)
        pid_motor_R.SetValue = 2 * speed_goal * speed_rate;

    inc_L = PID_Control_Inc(&pid_motor_L, 0);
    inc_R = PID_Control_Inc(&pid_motor_R, 0);

    duty_L += inc_L;
    duty_R += inc_R;

    if(duty_L > Motor_UpperLimit)
        duty_L = Motor_UpperLimit;
    if(duty_L < Motor_LowerLimit)
        duty_L = Motor_LowerLimit;

    if(duty_R > Motor_UpperLimit)
        duty_R = Motor_UpperLimit;
    if(duty_R < Motor_LowerLimit)
        duty_R = Motor_LowerLimit;
}

环岛处理

void circ_handler()
{
    static uint16 count_delay_R_circ_pre;
    static uint16 count_delay;

    if(flag_L_circ_pre) // 预圆环阶段
    {
        count_delay_R_circ_pre++;
        if(count_delay_R_circ_pre > 0.5 / speed_goal * 60 * TIM1_ISR_F) //
        {
            flag_L_circ_pre = 0;
            flag_L_circ_frc = 1; // force to get into circ
        }
    }
    if(flag_L_circ_frc)
    {
        Angle_circ += imu660ra_gyro_z * 0.002 / 65.6;
        if(Angle_circ < -35)
        {
            flag_L_circ_frc = 0;
            flag_L_circ_in = 1;
            flag_L_circ_out = 0;
        }
        else
        {
            pid_motor_L.SetValue = 0 * speed_rate * speed_goal;
            pid_motor_R.SetValue = 2 * speed_rate * speed_goal;
        }

    }
    if(flag_L_circ_in)
    {
        Angle_circ += imu660ra_gyro_z * 0.002 / 65.6;
        if(Angle_circ <= -300)
            flag_L_circ_in = 0;
    }
    if(flag_L_circ_in == 0 && flag_L_circ_out == 0)
    {
        count_delay++;
        if(count_delay > 5 * TIM1_ISR_F)
        {
            flag_L_circ_out = 1; // 已出环
            count_delay = 0;
            Angle_circ = 0;
        }
    }
}

障碍处理

void block_handler()
{
    if(flag_block_detected)
    {
        pid_motor_L.SetValue = 0 * speed_rate * speed_goal;
        pid_motor_R.SetValue = 2 * speed_rate * speed_goal;
        Angle_block += imu660ra_gyro_z * 0.002 / 65.6;
    }
    if(Angle_block < -45)
    {
        flag_block_detected = 0;
        flag_block_back = 1;
    }
    if(flag_block_back)
    {
        if(Angle_block < 50)
        {
            pid_motor_R.SetValue = 0 * speed_rate * speed_goal;
            pid_motor_L.SetValue = 2 * speed_rate * speed_goal;
        }
        else
            flag_block_adjust = 1;
        if(flag_block_adjust)
        {
            pid_motor_L.SetValue = 0.3 * speed_rate * speed_goal;
            pid_motor_R.SetValue = 1.7 * speed_rate * speed_goal;
        }


        Angle_block += imu660ra_gyro_z * 0.002 / 65.6;
    }
    if(Angle_block < 10 && Angle_block > -10 && flag_block_adjust)
    {
        flag_block_detected = 0;
        flag_block_back = 0;
        flag_block_adjust = 0;
        Angle_block = 0;

    }
}
  • 29
    点赞
  • 397
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 58
    评论
/*******************************************************************************/ // // oo——NXP2018_PRO——oo // // PART1:初始化区段 /*******************************************************************************/ /************************包含的头文件****************************/ #include "common.h" #include "include.h" #include "OLED.h" #include "SEEKFREE_18TFT.h" /***********************参数定义&设置****************************/ //--------------------------------------------------------------- //\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ //--------------------------------------------------------------- /***********************系统运行参数*****************************/ uint8 code_Time_flag=0; //程序运行时间 /**************************舵机*********************************/ uint8 KP_A=6,KP_B=27,KD=150; //MAIN舵机PID uint32 DJ_midpoint=7330; //舵机中值 uint32 DJ_PWM; //输出PWM /************************速度控制*******************************/ uint8 speed_need=20; //目标速度 uint8 speed_need_Boost=30; //目标高速 uint8 speed_need_normal=30; //目标速度 uint8 speed_need_L=30; //目标弯道 uint8 speed_SW_flag=1; //速度选择标志 /*************************电机控制******************************/ float Speed_P=4,Speed_I=0.15,Speed_D=1; //MAIN电机PID uint8 Block_motor_time_flag=0; //堵转计时标志 uint8 Block_motor_duty_flag=0; //堵转事件标志 uint8 Block_motor_delay_flag=0; //堵转弛懈标志 /**************************编码器********************************/ float feed_fix=10.6; //编码器修正系数 uint32 Feed_flag=0; //编码器采集计数 uint32 Feed_speed=0; //编码器采集速度 /***********************摄像头有关参数***************************/ /*调控参量*/ uint8 img_y_max=50; //扫描纵坐标最近值 uint8 img_y_min=10; //扫描纵坐标最远值 uint8 img_y_control=30; //扫描纵坐标控制值 /*传递参量*/ uint8 imgbuff[CAMERA_SIZE]; //定义存储接收图像的数组 uint8 img[CAMERA_W*CAMERA_H]; //摄像头解压数组 uint8 img_x=40; //扫描横坐标 uint8 img_y=30; //扫描纵坐标 uint8 start_point=40; //扫描起始点 uint8 mid_point[60]; //提取的中线 uint8 mid_point_His[10]; //历史的中线 uint8 left_point[60]; //左边界 int right_point[60]; //右边界 uint8 init_len[60]; //初始化赛道宽度 uint8 point_len[60]; //实时赛道宽度 uint8 street_len=0; //直道长度 uint8 len_His[10]; //直道长度历史数组 /*圆环补线*/ float L_Cur_K=0; //左圆环补线斜率 float R_Cur_K=0; //由圆环补线斜率

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 58
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

今天美美吃饭啦

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值