打印
[STM32F4]

直流有刷电机控制(电流环,速度环,位置环)

[复制链接]
486|0
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
zero949079783|  楼主 | 2024-4-6 15:45 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 zero949079783 于 2024-4-14 13:40 编辑

上位机使用:正点原子ATK_PID硬件:正点原子电机开发板

直流有刷电机 (电流环):链接:https://pan.baidu.com/s/1cpPnogMKNhTAeAOBJlFAxA?pwd=n8ut
提取码:n8ut
直流有刷电机 (速度环):链接:https://pan.baidu.com/s/1bd6SHPedWeDGvbiKfD88Vg?pwd=0vvt
提取码:0vvt
直流有刷电机 (位置环):  
链接:https://pan.baidu.com/s/1Cy3HBHYqmDLjFAGRBZYWVQ?pwd=20dn
提取码:20dn



电流环:
#include "main.h"
#include "math.h"


/*************************************    第二部分    电压电流温度采集    **********************************************/
uint16_t g_adc_val[ADC_CH_NUM];                         /*ADC平均值存放数组*/



PID_TypeDef  g_current_pid;             /* 电流环PID参数结构体 */
/*
    Rt = Rp *exp(B*(1/T1-1/T2))

    Rt 是热敏电阻在T1温度下的阻值;
    Rp是热敏电阻在T2常温下的标称阻值;
    exp是e的n次方,e是自然常数,就是自然对数的底数,近似等于 2.7182818;
    B值是热敏电阻的重要参数,教程中用到的热敏电阻B值为3380;
    这里T1和T2指的是开尔文温度,T2是常温25℃,即(273.15+25)K
    T1就是所求的温度
*/

const float Rp = 10000.0f;          /* 10K */
const float T2 = (273.15f + 25.0f); /* T2 */
const float Bx = 3380.0f;           /* B */
const float Ka = 273.15f;

Motor_TypeDef g_motor_data;  /*电机参数变量*/
ENCODE_TypeDef g_encode;     /*编码器参数变量*/

/**
* [url=home.php?mod=space&uid=247401]@brief[/url]       计算温度值
* @param       para: 温度采集对应ADC通道的值(已滤波)
* [url=home.php?mod=space&uid=536309]@NOTE[/url]        计算温度分为两步:
                1.根据ADC采集到的值计算当前对应的Rt
                2.根据Rt计算对应的温度值
* @retval      温度值
*/
float get_temp(uint16_t para)
{
    float Rt;
    float temp;
   
    /*
        第一步:
        Rt = 3.3 * 4700 / VTEMP - 4700 ,其中VTEMP就是温度检测通道采集回来的电压值,VTEMP = ADC值* 3.3/4096
        由此我们可以计算出当前Rt的值:Rt = 3.3f * 4700.0f / (para * 3.3f / 4096.0f ) - 4700.0f;
    */
   
    Rt = 3.3f * 4700.0f / (para * 3.3f / 4096.0f ) - 4700.0f;       /* 根据当前ADC值计算出Rt的值 */

    /*
        第二步:
        根据当前Rt的值来计算对应温度值:Rt = Rp *exp(B*(1/T1-1/T2))
    */
   
    temp = Rt / Rp;                 /* 解出exp(B*(1/T1-1/T2)) ,即temp = exp(B*(1/T1-1/T2)) */
    temp = log(temp);               /* 解出B*(1/T1-1/T2) ,即temp = B*(1/T1-1/T2) */
    temp /= Bx;                     /* 解出1/T1-1/T2 ,即temp = 1/T1-1/T2 */
    temp += (1.0f / T2);            /* 解出1/T1 ,即temp = 1/T1 */
    temp = 1.0f / (temp);           /* 解出T1 ,即temp = T1 */
    temp -= Ka;                     /* 计算T1对应的摄氏度 */
    return temp;                    /* 返回温度值 */
}

/**
* [url=home.php?mod=space&uid=247401]@brief[/url]       计算ADC的平均值(滤波)
* @param       * p :存放ADC值的指针地址
* [url=home.php?mod=space&uid=536309]@NOTE[/url]        此函数对电压、温度、电流对应的ADC值进行滤波,
*              p[0]-p[2]对应的分别是电压、温度和电流
* @retval      无
*/
void calc_adc_val(uint16_t * adcdata)
{
          uint32_t temp[3] = {0,0,0};
                uint16_t i;
    for(i=0;i<ADC_COLL;i++)         /* 循环ADC_COLL次取值,累加 */
    {
        temp[0] += adcdata[0+i*ADC_CH_NUM];
        temp[1] += adcdata[1+i*ADC_CH_NUM];
        temp[2] += adcdata[2+i*ADC_CH_NUM];
    }
    temp[0] /= ADC_COLL;            /* 取平均值 */
    temp[1] /= ADC_COLL;
    temp[2] /= ADC_COLL;
               
    g_adc_val[0] = temp[0];                 /* 存入电压ADC通道平均值 */
    g_adc_val[1] = temp[1];                 /* 存入温度ADC通道平均值 */
    g_adc_val[2] = temp[2];                 /* 存入电流ADC通道平均值 */               
}
uint8_t current_flag =0;
void get_Motor_value(uint16_t * adcdata)
{
        #define CURRENT_NUM 4
        #define INIT_CURRENT_NUM 5
        float temp_current=0.0;
        static float adc_current = 0;
        static float init_adc_current = 0;
        static uint8_t current_count1 =0,current_count2 =0;
        
        current_count1++;
        calc_adc_val(adcdata);
        adc_current += g_adc_val[2];        /* 取出电流通道对应的ADC值进行累计 */
        
        if(current_count1 >= CURRENT_NUM)/* 累计15次 */
        {
                        adc_current = (float)(adc_current / current_count1);                 /* 取平均值 */
                        if(current_count2 <= INIT_CURRENT_NUM)
                        {
                                current_count2++;
                                init_adc_current += adc_current;                         /* 对平均值累计求和 */
                                if(current_count2 == INIT_CURRENT_NUM)
                                {
                                        init_adc_current = (float)(init_adc_current/current_count2);        /* 存储初始ADC值 */
                                        current_count2 = INIT_CURRENT_NUM+1;
                                        current_flag =1;
                                       
                                }
                        }
                        if(current_count2 >= (INIT_CURRENT_NUM+1))
                        {
                                       
                                        temp_current= ((adc_current - init_adc_current) *ADC2CURT);
                                        // g_motor_data.current = temp_current;
                                        FirstOrderRC_LPF(g_motor_data.current,temp_current,0.40);
                                        //g_motor_data.current = (float)((g_motor_data.current * (float)0.60) + ((float)0.40 * temp_current));  /* 一阶低通滤波 */
                                 
                                        if(g_motor_data.current <=20)
                                 {
                                                g_motor_data.current=0.0;
                                 }
                        }
                adc_current=0;
                current_count1=0;
        }
}





/*************************************    第三部分    编码器测速    ****************************************************/
void speed_computer(int32_t encode_now, uint8_t ms)
{
    uint8_t i = 0, j = 0;
    float temp = 0.0;
    static uint8_t sp_count = 0, k = 0;
    static float speed_arr[10] = {0.0};                     /* 存储速度进行滤波运算 */

    if (sp_count == ms)                                     /* 计算一次速度 */
    {
        /* 计算电机转速
           第一步 :计算ms毫秒内计数变化量
           第二步 ;计算1min内计数变化量:g_encode.speed * ((1000 / ms) * 60 ,
           第三步 :除以编码器旋转一圈的计数次数(倍频倍数 * 编码器分辨率)
           第四步 :除以减速比即可得出电机转速
        */
        g_encode.encode_now = encode_now;                                /* 取出编码器当前计数值 */
        g_encode.speed = (g_encode.encode_now - g_encode.encode_old);    /* 计算编码器计数值的变化量 */
        
        speed_arr[k++] = (float)(g_encode.speed * ((1000 / ms) * 60.0) / REDUCTION_RATIO / ROTO_RATIO );    /* 保存电机转速 */
        
        g_encode.encode_old = g_encode.encode_now;          /* 保存当前编码器的值 */

        /* 累计10次速度值,后续进行滤波*/
        if (k == 10)
        {
            for (i = 10; i >= 1; i--)                       /* 冒泡排序*/
            {
                for (j = 0; j < (i - 1); j++)
                {
                    if (speed_arr[j] > speed_arr[j + 1])    /* 数值比较 */
                    {
                        temp = speed_arr[j];                /* 数值换位 */
                        speed_arr[j] = speed_arr[j + 1];
                        speed_arr[j + 1] = temp;
                    }
                }
            }
            
            temp = 0.0;
            
            for (i = 2; i < 8; i++)                         /* 去除两边高低数据 */
            {
                temp += speed_arr[i];                       /* 将中间数值累加 */
            }
            
            temp = (float)(temp / 6);                       /*求速度平均值*/
            
            /* 一阶低通滤波
             * 公式为:Y(n)= qX(n) + (1-q)Y(n-1)
             * 其中X(n)为本次采样值;Y(n-1)为上次滤波输出值;Y(n)为本次滤波输出值,q为滤波系数
             * q值越小则上一次输出对本次输出影响越大,整体曲线越平稳,但是对于速度变化的响应也会越慢
             */
            g_motor_data.speed = (float)( ((float)0.48 * temp) + (g_motor_data.speed * (float)0.52) );
            k = 0;
        }
        sp_count = 0;
    }
    sp_count ++;
}

uint8_t g_run_flag = 0;

int32_t motor_pwm = 0;
atk_debug_data_rev get_atk_data;


void DCMotor_App(void)
{
        static uint8_t key=0;
        get_atkdebug(&get_atk_data);
        key=key_scan(0);
        if(key == KEY0_PRES)
        {        
                TurnTogLed(LED1);
                g_current_pid.SetPoint +=50;
                g_run_flag = 1;
                if (g_current_pid.SetPoint == 0)
                {
                                DC_Motor_Stop(MOTOR_1);           /* 停止则立刻响应 */                        
                                g_motor_data.motor_pwm = 0;
                                Motor_PWM_Set(g_motor_data.motor_pwm,MOTOR_1);                                  /* 设置电机转速 */
                }
                else
                {
                        DC_Motor_Start(MOTOR_1);
                        if(g_current_pid.SetPoint  >= 250)
                        {
                                g_current_pid.SetPoint  =250;
                        }
                        atk_debug_send_motorstate(RUN_STATE);           /* 上传电机状态(运行) */
                        //Motor_PWM_Set(g_current_pid.SetPoint,MOTOR_1);
                }
        }
        else if(key == KEY1_PRES)        {        
                TurnTogLed(LED1);

                if (g_current_pid.SetPoint == 0)
                {
                                DC_Motor_Stop(MOTOR_1);           /* 停止则立刻响应 */                        
                                g_motor_data.motor_pwm = 0;
                                DC_Motor_Speed(g_motor_data.motor_pwm,MOTOR_1); /* 设置电机转速 */                                 
                }
                else
                {


                }
        }
        else if(key == KEY2_PRES)
        {

                DC_Motor_Stop(MOTOR_1);
                g_run_flag = 0;                                 /* 标记电机停止 */
                g_motor_data.motor_pwm = 0;
                Motor_PWM_Set(g_motor_data.motor_pwm,MOTOR_1);          /* 设置电机转向、速度 */
                pid_init();
                atk_debug_send_motorstate(BREAKED_STATE);           /* 上传电机状态(刹车) */
                atk_debug_send_initdata(TYPE_PID1, (float *)(&g_current_pid.SetPoint), KP, KI, KD);           /* 同步数据到上位机 */
        }
}

void DCMotor_Value(void)
{
        static uint16_t g_time =0;
        int32_t motor_pwm_temp = 0;                                       
        
        if(current_flag == 0 )
                return;
                                
                                
                                /* 获取编码器值,用于计算速度 */
                                get_EncodeValue(5);        /* 中位平均值滤除编码器抖动数据,5ms计算一次速度*/
                                
                                if(g_time  % 499 ==0)
                                {                                                                                 
                                       
                                        g_motor_data.volatage  = g_adc_val[0]*ADC2VBUS;               
                                        atk_debug_send_valtage(g_motor_data.volatage );
                                        __NOP();__NOP();__NOP();
                                        g_motor_data.board_temp = get_temp(g_adc_val[1]);
                                        __NOP();__NOP();__NOP();
                                        atk_debug_send_temp(0,get_temp(g_adc_val[1]));
                                        __NOP();__NOP();__NOP();
                                        //g_motor_data.current          = (g_adc_val[2]*ADC2CURT)*0.001;
                                        atk_debug_send_current(g_motor_data.current*0.001,0,0);                        
                                        __NOP();__NOP();__NOP();               
                                        atk_debug_send_speed(g_motor_data.speed);
                                        __NOP();__NOP();__NOP();               
//                                        printf("\r\n******************************\r\n");
//                                        printf("KEY0:增加比较值,KEY1:减小比较值,KEY2:停止电机\r\n\r\n");
//                                        printf("Valtage:%.2fV \r\n",    g_motor_data.volatage);                   /* 打印电压值 */
//                                        printf("Temp:%.2fC \r\n",                    g_motor_data.board_temp   );                  /* 打印温度值 */
//                                        printf("Current:%.2fmA \r\n",   g_motor_data.current); /* 打印电流值 */
//                                        printf("电机速度:%.1f RPM\r\n\r\n",   g_motor_data.speed);               
//                                        printf("\r\n******************************\r\n");
                                }
                                else if(g_time % SMAPLSE_PID_SPEED == 0)                /* 电机速度 50ms进行一次pid计算 */
                                {
                                        if(g_run_flag)
                                        {
                                       
                                                 /* PID计算,输出比较值(占空比) */
                                                motor_pwm_temp = increment_pid_ctrl (&g_current_pid,g_motor_data.current);
                                                g_motor_data.motor_pwm = (int32_t)((g_motor_data.motor_pwm * 0.5) + (motor_pwm_temp * 0.5));
                                                if(g_motor_data.motor_pwm >= 8200)
                                                {
                                                        g_motor_data.motor_pwm = 8200;
                                                }
                                                else if (g_motor_data.motor_pwm <= 0)
                                                {
                                                        g_motor_data.motor_pwm = 0;
                                                }
                                       
                                                Motor_PWM_Set(g_motor_data.motor_pwm,MOTOR_1); /* 设置电机转速 */
                                        }
                                                atk_debug_send_wave_data( 1 ,g_motor_data.current);                           /* 选择通道1发送实际电流(波形显示)*/
                                                atk_debug_send_wave_data( 2 ,g_current_pid.SetPoint);                         /* 选择通道2,发送目标电流(波形显示)*/
                                                atk_debug_send_wave_data( 3 ,g_motor_data.motor_pwm * 100 / 8400);          /* 选择通道3,发送占空比(波形显示)*/
                                }

                                g_time ++;
        
}

void get_EncodeValue(uint8_t  ms)
{
        int encode_now = gtim_get_encode();
        speed_computer(encode_now, ms);
}


PID_TypeDef  g_speed_pid;           /* 速度环PID参数结构体 */

/**
* [url=home.php?mod=space&uid=247401]@brief[/url]       pid初始化
* @param       无
* @retval      无
*/
void pid_init(void)
{
        


                memset(&g_motor_data,0,sizeof(g_motor_data));
                memset(&g_current_pid,0,sizeof(g_current_pid));
        
    g_current_pid.SetPoint = 0;        /* 设定目标值 */
    g_current_pid.ActualValue = 0.0;    /* 期望输出值 */
    g_current_pid.SumError = 0.0;       /* 积分值 */
    g_current_pid.Error = 0.0;          /* Error[1] */
    g_current_pid.LastError = 0.0;      /* Error[-1] */
    g_current_pid.PrevError = 0.0;      /* Error[-2] */
    g_current_pid.Proportion = KP;      /* 比例常数 Proportional Const */
    g_current_pid.Integral = KI;        /* 积分常数 Integral Const */
    g_current_pid.Derivative = KD;      /* 微分常数 Derivative Const */
}

void DCMotorsample_Init(void)
{
                pid_init();
                ADC1CbReg(get_Motor_value);
}


速度环:
#include "main.h"
#include "math.h"


/*************************************    第二部分    电压电流温度采集    **********************************************/
uint16_t g_adc_val[ADC_CH_NUM];                         /*ADC平均值存放数组*/


PID_TypeDef  g_speed_pid;     /*速度环PID参数结构体*/

/*
    Rt = Rp *exp(B*(1/T1-1/T2))

    Rt 是热敏电阻在T1温度下的阻值;
    Rp是热敏电阻在T2常温下的标称阻值;
    exp是e的n次方,e是自然常数,就是自然对数的底数,近似等于 2.7182818;
    B值是热敏电阻的重要参数,教程中用到的热敏电阻B值为3380;
    这里T1和T2指的是开尔文温度,T2是常温25℃,即(273.15+25)K
    T1就是所求的温度
*/

const float Rp = 10000.0f;          /* 10K */
const float T2 = (273.15f + 25.0f); /* T2 */
const float Bx = 3380.0f;           /* B */
const float Ka = 273.15f;

Motor_TypeDef g_motor_data;  /*电机参数变量*/
ENCODE_TypeDef g_encode;     /*编码器参数变量*/

/**
* [url=home.php?mod=space&uid=247401]@brief[/url]       计算温度值
* @param       para: 温度采集对应ADC通道的值(已滤波)
* [url=home.php?mod=space&uid=536309]@NOTE[/url]        计算温度分为两步:
                1.根据ADC采集到的值计算当前对应的Rt
                2.根据Rt计算对应的温度值
* @retval      温度值
*/
float get_temp(uint16_t para)
{
    float Rt;
    float temp;
   
    /*
        第一步:
        Rt = 3.3 * 4700 / VTEMP - 4700 ,其中VTEMP就是温度检测通道采集回来的电压值,VTEMP = ADC值* 3.3/4096
        由此我们可以计算出当前Rt的值:Rt = 3.3f * 4700.0f / (para * 3.3f / 4096.0f ) - 4700.0f;
    */
   
    Rt = 3.3f * 4700.0f / (para * 3.3f / 4096.0f ) - 4700.0f;       /* 根据当前ADC值计算出Rt的值 */

    /*
        第二步:
        根据当前Rt的值来计算对应温度值:Rt = Rp *exp(B*(1/T1-1/T2))
    */
   
    temp = Rt / Rp;                 /* 解出exp(B*(1/T1-1/T2)) ,即temp = exp(B*(1/T1-1/T2)) */
    temp = log(temp);               /* 解出B*(1/T1-1/T2) ,即temp = B*(1/T1-1/T2) */
    temp /= Bx;                     /* 解出1/T1-1/T2 ,即temp = 1/T1-1/T2 */
    temp += (1.0f / T2);            /* 解出1/T1 ,即temp = 1/T1 */
    temp = 1.0f / (temp);           /* 解出T1 ,即temp = T1 */
    temp -= Ka;                     /* 计算T1对应的摄氏度 */
    return temp;                    /* 返回温度值 */
}

/**
* [url=home.php?mod=space&uid=247401]@brief[/url]       计算ADC的平均值(滤波)
* @param       * p :存放ADC值的指针地址
* [url=home.php?mod=space&uid=536309]@NOTE[/url]        此函数对电压、温度、电流对应的ADC值进行滤波,
*              p[0]-p[2]对应的分别是电压、温度和电流
* @retval      无
*/
void calc_adc_val(uint16_t * adcdata)
{
          uint32_t temp[3] = {0,0,0};
                uint16_t i;
    for(i=0;i<ADC_COLL;i++)         /* 循环ADC_COLL次取值,累加 */
    {
        temp[0] += adcdata[0+i*ADC_CH_NUM];
        temp[1] += adcdata[1+i*ADC_CH_NUM];
        temp[2] += adcdata[2+i*ADC_CH_NUM];
    }
    temp[0] /= ADC_COLL;            /* 取平均值 */
    temp[1] /= ADC_COLL;
    temp[2] /= ADC_COLL;
               
    g_adc_val[0] = temp[0];                 /* 存入电压ADC通道平均值 */
    g_adc_val[1] = temp[1];                 /* 存入温度ADC通道平均值 */
    g_adc_val[2] = temp[2];                 /* 存入电流ADC通道平均值 */               
}

void get_Motor_value(uint16_t * adcdata)
{
        calc_adc_val(adcdata);
        
}





/*************************************    第三部分    编码器测速    ****************************************************/
void speed_computer(int32_t encode_now, uint8_t ms)
{
    uint8_t i = 0, j = 0;
    float temp = 0.0;
    static uint8_t sp_count = 0, k = 0;
    static float speed_arr[10] = {0.0};                     /* 存储速度进行滤波运算 */

    if (sp_count == ms)                                     /* 计算一次速度 */
    {
        /* 计算电机转速
           第一步 :计算ms毫秒内计数变化量
           第二步 ;计算1min内计数变化量:g_encode.speed * ((1000 / ms) * 60 ,
           第三步 :除以编码器旋转一圈的计数次数(倍频倍数 * 编码器分辨率)
           第四步 :除以减速比即可得出电机转速
        */
        g_encode.encode_now = encode_now;                                /* 取出编码器当前计数值 */
        g_encode.speed = (g_encode.encode_now - g_encode.encode_old);    /* 计算编码器计数值的变化量 */
        
        speed_arr[k++] = (float)(g_encode.speed * ((1000 / ms) * 60.0) / REDUCTION_RATIO / ROTO_RATIO );    /* 保存电机转速 */
        
        g_encode.encode_old = g_encode.encode_now;          /* 保存当前编码器的值 */

        /* 累计10次速度值,后续进行滤波*/
        if (k == 10)
        {
            for (i = 10; i >= 1; i--)                       /* 冒泡排序*/
            {
                for (j = 0; j < (i - 1); j++)
                {
                    if (speed_arr[j] > speed_arr[j + 1])    /* 数值比较 */
                    {
                        temp = speed_arr[j];                /* 数值换位 */
                        speed_arr[j] = speed_arr[j + 1];
                        speed_arr[j + 1] = temp;
                    }
                }
            }
            
            temp = 0.0;
            
            for (i = 2; i < 8; i++)                         /* 去除两边高低数据 */
            {
                temp += speed_arr[i];                       /* 将中间数值累加 */
            }
            
            temp = (float)(temp / 6);                       /*求速度平均值*/
            
            /* 一阶低通滤波
             * 公式为:Y(n)= qX(n) + (1-q)Y(n-1)
             * 其中X(n)为本次采样值;Y(n-1)为上次滤波输出值;Y(n)为本次滤波输出值,q为滤波系数
             * q值越小则上一次输出对本次输出影响越大,整体曲线越平稳,但是对于速度变化的响应也会越慢
             */
            g_motor_data.speed = (float)( ((float)0.48 * temp) + (g_motor_data.speed * (float)0.52) );
            k = 0;
        }
        sp_count = 0;
    }
    sp_count ++;
}

uint8_t g_run_flag = 0;

int32_t motor_pwm = 0;

void DCMotor_App(void)
{
        static uint8_t key=0;
        key=key_scan(0);
        if(key == KEY0_PRES)
        {        
                TurnTogLed(LED1);
                g_speed_pid.SetPoint +=30;
                g_run_flag = 1;
                if (g_speed_pid.SetPoint == 0)
                {
                                DC_Motor_Stop(MOTOR_1);           /* 停止则立刻响应 */                        
                                g_motor_data.motor_pwm = 0;
                                Motor_PWM_Set(g_motor_data.motor_pwm,MOTOR_1);                                  /* 设置电机转速 */
                }
                else
                {
                        DC_Motor_Start(MOTOR_1);
                        if(g_speed_pid.SetPoint  >= 300)
                        {
                                g_speed_pid.SetPoint  =300;
                        }
                        atk_debug_send_motorstate(RUN_STATE);           /* 上传电机状态(运行) */
                        DC_Motor_Speed(g_speed_pid.SetPoint,MOTOR_1); /* 设置电机转速 */

                }
        }
        else if(key == KEY1_PRES)        {        
                TurnTogLed(LED1);
                g_speed_pid.SetPoint -= 30;

                g_run_flag = 1;
                if (g_speed_pid.SetPoint == 0)
                {
                                DC_Motor_Stop(MOTOR_1);           /* 停止则立刻响应 */                        
                                g_motor_data.motor_pwm = 0;
                                DC_Motor_Speed(g_motor_data.motor_pwm,MOTOR_1); /* 设置电机转速 */                                 
                }
                else
                {
                        DC_Motor_Start(MOTOR_1);
                        if(g_speed_pid.SetPoint  <= -300)
                        {
                                g_speed_pid.SetPoint  =-300;
                        }
                        DC_Motor_Speed(g_speed_pid.SetPoint,MOTOR_1); /* 设置电机转速 */

                        atk_debug_send_motorstate(RUN_STATE);           /* 上传电机状态(运行) */
                }
        }
        else if(key == KEY2_PRES)
        {
                DC_Motor_Stop(MOTOR_1);
                g_run_flag = 0;                                 /* 标记电机停止 */
                g_motor_data.motor_pwm = 0;
                Motor_PWM_Set(g_motor_data.motor_pwm,MOTOR_1);          /* 设置电机转向、速度 */
                g_speed_pid.SetPoint = 0;
                pid_init();
                atk_debug_send_motorstate(BREAKED_STATE);           /* 上传电机状态(刹车) */
                atk_debug_send_initdata(TYPE_PID1, (float *)(&g_speed_pid.SetPoint), KP, KI, KD);           /* 同步数据到上位机 */
        }
}

void DCMotor_Value(void)
{
        static uint16_t init_adc_val = 0;
        static uint16_t g_time =0;
        static uint8_t num = 0;
        if(num < 2)
        {
                num ++;
                atk_debug_send_motorcode(DC_MOTOR);         /* 上传电机类型(直流有刷电机) */
    atk_debug_send_motorstate(IDLE_STATE);      /* 上传电机状态(空闲) */
                init_adc_val = g_adc_val[2];
                init_adc_val += g_adc_val[2];       /* 现在的值和上一次存储的值相加 */
    init_adc_val /= 2;  
        }else
        {                                                        
                                
                                
                                
                                /* 获取编码器值,用于计算速度 */
                                get_EncodeValue(5);        /* 中位平均值滤除编码器抖动数据,5ms计算一次速度*/
                                
                                if(g_time  % 1000 ==0)
                                {                                                                                 
                                       
                                        __NOP();__NOP();__NOP();
                                        g_motor_data.board_temp = get_temp(g_adc_val[1]);
                                            
//                                                        
                                        printf("\r\n******************************\r\n");
                                        printf("KEY0:增加比较值,KEY1:减小比较值,KEY2:停止电机\r\n\r\n");
                                        printf("Valtage:%.2fV \r\n",    g_motor_data.volatage);                   /* 打印电压值 */
                                        printf("Temp:%.2fC \r\n",                    g_motor_data.board_temp   );                  /* 打印温度值 */
                                        printf("Current:%.2fmA \r\n",   g_motor_data.current); /* 打印电流值 */
                                        printf("电机速度:%.1f RPM\r\n\r\n",   g_motor_data.speed);               
                                        printf("\r\n******************************\r\n");
                                }
                                else if(g_time %300 == 0)
                                {
                                        atk_debug_send_temp(0,get_temp(g_adc_val[1]));
                                }
                                else if(g_time %200 == 0)
                                {
                                        g_motor_data.volatage  = g_adc_val[0]*ADC2VBUS;               
                                        atk_debug_send_valtage(g_motor_data.volatage );
                                }
                                else if(g_time % SMAPLSE_PID_SPEED == 0)                /* 电机速度 50ms进行一次pid计算 */
                                {
                                        atk_debug_send_speed(g_motor_data.speed);
                                        if(g_run_flag)
                                        {
                                       
                                                 /* PID计算,输出比较值(占空比) */
                                                g_motor_data.motor_pwm = increment_pid_ctrl (&g_speed_pid,g_motor_data.speed);
                                                
                                                if(g_motor_data.motor_pwm >= 8200)
                                                {
                                                        g_motor_data.motor_pwm = 8200;
                                                }
                                                else if (g_motor_data.motor_pwm <= -8200)
                                                {
                                                        g_motor_data.motor_pwm = -8200;
                                                }
                                       
                                                Motor_PWM_Set(g_motor_data.motor_pwm,MOTOR_1); /* 设置电机转速 */
                                        }
                                                atk_debug_send_wave_data( 1 ,g_motor_data.speed);                           /* 选择通道1,发送实际速度(波形显示)*/
                                                atk_debug_send_wave_data( 2 ,g_speed_pid.SetPoint);                         /* 选择通道2,发送目标速度(波形显示)*/
                                                atk_debug_send_wave_data( 3 ,g_motor_data.motor_pwm * 100 / 8400);          /* 选择通道3,发送占空比(波形显示)*/
                                }
                                else if(g_time % 20 == 0)
                                {
                                        g_motor_data.current          = (abs(g_adc_val[2]-init_adc_val)*ADC2CURT)*0.001;
                                        atk_debug_send_current(g_motor_data.current,0,0);                                       
                                }
                                g_time ++;
        }
}

void get_EncodeValue(uint8_t  ms)
{
        int encode_now = gtim_get_encode();
        speed_computer(encode_now, ms);
}


PID_TypeDef  g_speed_pid;           /* 速度环PID参数结构体 */

/**
* [url=home.php?mod=space&uid=247401]@brief[/url]       pid初始化
* @param       无
* @retval      无
*/
void pid_init(void)
{
        
                memset(&g_motor_data,0,sizeof(g_motor_data));
                memset(&g_speed_pid,0,sizeof(g_speed_pid));
        
                /* 初始化速度环PID参数 */
    g_speed_pid.SetPoint = 0;       /* 设定目标值 */
    g_speed_pid.ActualValue = 0.0;  /* 期望输出值 */
    g_speed_pid.SumError = 0.0;     /* 积分值 */
    g_speed_pid.Error = 0.0;        /* Error[1] */
    g_speed_pid.LastError = 0.0;    /* Error[-1] */
    g_speed_pid.PrevError = 0.0;    /* Error[-2] */
    g_speed_pid.Proportion = KP;    /* 比例常数 Proportional Const */
    g_speed_pid.Integral = KI;      /* 积分常数 Integral Const */
    g_speed_pid.Derivative = KD;    /* 微分常数 Derivative Const */
        
                atk_debug_send_wave_data( 1 ,g_motor_data.speed);                           /* 选择通道1,发送实际速度(波形显示)*/
                atk_debug_send_wave_data( 2 ,g_speed_pid.SetPoint);                         /* 选择通道2,发送目标速度(波形显示)*/
                atk_debug_send_wave_data( 3 ,g_motor_data.motor_pwm * 100 / 8400);          /* 选择通道3,发送占空比(波形显示)*/
}

void DCMotorsample_Init(void)
{
                pid_init();
                ADC1CbReg(get_Motor_value);
}

位置环:
#include "main.h"
#include "math.h"


/*************************************    第二部分    电压电流温度采集    **********************************************/
uint16_t g_adc_val[ADC_CH_NUM];                         /*ADC平均值存放数组*/



PID_TypeDef  g_location_pid;             /*位置环PID参数结构体*/

/*
    Rt = Rp *exp(B*(1/T1-1/T2))

    Rt 是热敏电阻在T1温度下的阻值;
    Rp是热敏电阻在T2常温下的标称阻值;
    exp是e的n次方,e是自然常数,就是自然对数的底数,近似等于 2.7182818;
    B值是热敏电阻的重要参数,教程中用到的热敏电阻B值为3380;
    这里T1和T2指的是开尔文温度,T2是常温25℃,即(273.15+25)K
    T1就是所求的温度
*/

const float Rp = 10000.0f;          /* 10K */
const float T2 = (273.15f + 25.0f); /* T2 */
const float Bx = 3380.0f;           /* B */
const float Ka = 273.15f;

Motor_TypeDef g_motor_data;  /*电机参数变量*/
ENCODE_TypeDef g_encode;     /*编码器参数变量*/

/**
* [url=home.php?mod=space&uid=247401]@brief[/url]       计算温度值
* @param       para: 温度采集对应ADC通道的值(已滤波)
* [url=home.php?mod=space&uid=536309]@NOTE[/url]        计算温度分为两步:
                1.根据ADC采集到的值计算当前对应的Rt
                2.根据Rt计算对应的温度值
* @retval      温度值
*/
float get_temp(uint16_t para)
{
    float Rt;
    float temp;
   
    /*
        第一步:
        Rt = 3.3 * 4700 / VTEMP - 4700 ,其中VTEMP就是温度检测通道采集回来的电压值,VTEMP = ADC值* 3.3/4096
        由此我们可以计算出当前Rt的值:Rt = 3.3f * 4700.0f / (para * 3.3f / 4096.0f ) - 4700.0f;
    */
   
    Rt = 3.3f * 4700.0f / (para * 3.3f / 4096.0f ) - 4700.0f;       /* 根据当前ADC值计算出Rt的值 */

    /*
        第二步:
        根据当前Rt的值来计算对应温度值:Rt = Rp *exp(B*(1/T1-1/T2))
    */
   
    temp = Rt / Rp;                 /* 解出exp(B*(1/T1-1/T2)) ,即temp = exp(B*(1/T1-1/T2)) */
    temp = log(temp);               /* 解出B*(1/T1-1/T2) ,即temp = B*(1/T1-1/T2) */
    temp /= Bx;                     /* 解出1/T1-1/T2 ,即temp = 1/T1-1/T2 */
    temp += (1.0f / T2);            /* 解出1/T1 ,即temp = 1/T1 */
    temp = 1.0f / (temp);           /* 解出T1 ,即temp = T1 */
    temp -= Ka;                     /* 计算T1对应的摄氏度 */
    return temp;                    /* 返回温度值 */
}

/**
* @brief       计算ADC的平均值(滤波)
* @param       * p :存放ADC值的指针地址
* [url=home.php?mod=space&uid=536309]@NOTE[/url]        此函数对电压、温度、电流对应的ADC值进行滤波,
*              p[0]-p[2]对应的分别是电压、温度和电流
* @retval      无
*/
void calc_adc_val(uint16_t * adcdata)
{
          uint32_t temp[3] = {0,0,0};
                uint16_t i;
    for(i=0;i<ADC_COLL;i++)         /* 循环ADC_COLL次取值,累加 */
    {
        temp[0] += adcdata[0+i*ADC_CH_NUM];
        temp[1] += adcdata[1+i*ADC_CH_NUM];
        temp[2] += adcdata[2+i*ADC_CH_NUM];
    }
    temp[0] /= ADC_COLL;            /* 取平均值 */
    temp[1] /= ADC_COLL;
    temp[2] /= ADC_COLL;
               
    g_adc_val[0] = temp[0];                 /* 存入电压ADC通道平均值 */
    g_adc_val[1] = temp[1];                 /* 存入温度ADC通道平均值 */
    g_adc_val[2] = temp[2];                 /* 存入电流ADC通道平均值 */               
}

void get_Motor_value(uint16_t * adcdata)
{
        calc_adc_val(adcdata);
        
}





/*************************************    第三部分    编码器测速    ****************************************************/
void speed_computer(int32_t encode_now, uint8_t ms)
{
    uint8_t i = 0, j = 0;
    float temp = 0.0;
    static uint8_t sp_count = 0, k = 0;
    static float speed_arr[10] = {0.0};                     /* 存储速度进行滤波运算 */

    if (sp_count == ms)                                     /* 计算一次速度 */
    {
        /* 计算电机转速
           第一步 :计算ms毫秒内计数变化量
           第二步 ;计算1min内计数变化量:g_encode.speed * ((1000 / ms) * 60 ,
           第三步 :除以编码器旋转一圈的计数次数(倍频倍数 * 编码器分辨率)
           第四步 :除以减速比即可得出电机转速
        */
        g_encode.encode_now = encode_now;                                /* 取出编码器当前计数值 */
        g_encode.speed = (g_encode.encode_now - g_encode.encode_old);    /* 计算编码器计数值的变化量 */
        
        speed_arr[k++] = (float)(g_encode.speed * ((1000 / ms) * 60.0) / REDUCTION_RATIO / ROTO_RATIO );    /* 保存电机转速 */
        
        g_encode.encode_old = g_encode.encode_now;          /* 保存当前编码器的值 */

        /* 累计10次速度值,后续进行滤波*/
        if (k == 10)
        {
            for (i = 10; i >= 1; i--)                       /* 冒泡排序*/
            {
                for (j = 0; j < (i - 1); j++)
                {
                    if (speed_arr[j] > speed_arr[j + 1])    /* 数值比较 */
                    {
                        temp = speed_arr[j];                /* 数值换位 */
                        speed_arr[j] = speed_arr[j + 1];
                        speed_arr[j + 1] = temp;
                    }
                }
            }
            
            temp = 0.0;
            
            for (i = 2; i < 8; i++)                         /* 去除两边高低数据 */
            {
                temp += speed_arr[i];                       /* 将中间数值累加 */
            }
            
            temp = (float)(temp / 6);                       /*求速度平均值*/
            
            /* 一阶低通滤波
             * 公式为:Y(n)= qX(n) + (1-q)Y(n-1)
             * 其中X(n)为本次采样值;Y(n-1)为上次滤波输出值;Y(n)为本次滤波输出值,q为滤波系数
             * q值越小则上一次输出对本次输出影响越大,整体曲线越平稳,但是对于速度变化的响应也会越慢
             */
            g_motor_data.speed = (float)( ((float)0.48 * temp) + (g_motor_data.speed * (float)0.52) );
            k = 0;
        }
        sp_count = 0;
    }
    sp_count ++;
}

uint8_t g_run_flag = 0;

int32_t motor_pwm = 0;

void DCMotor_App(void)
{
        static uint8_t key=0;
        key=key_scan(0);
        if(key == KEY0_PRES)
        {        
                TurnTogLed(LED1);
                g_location_pid.SetPoint +=1320;        /* 正转一圈,电机旋转圈数 = 计数值变化量 / 44 / 30 */
                g_run_flag = 1;
                if (g_location_pid.SetPoint == 0)
                {
                                DC_Motor_Stop(MOTOR_1);           /* 停止则立刻响应 */                        
                                g_motor_data.motor_pwm = 0;
                                Motor_PWM_Set(g_motor_data.motor_pwm,MOTOR_1);                                  /* 设置电机转速 */
                }
                else
                {
                        DC_Motor_Start(MOTOR_1);
                        if(g_location_pid.SetPoint  >= 6600)
                        {
                                g_location_pid.SetPoint  =6600;
                        }
                        atk_debug_send_motorstate(RUN_STATE);           /* 上传电机状态(运行) */
                        DC_Motor_Speed(g_location_pid.SetPoint,MOTOR_1); /* 设置电机转速 */

                }
        }
        else if(key == KEY1_PRES)        {        
                TurnTogLed(LED1);
                g_location_pid.SetPoint -= 1320;        /* 正转一圈,电机旋转圈数 = 计数值变化量 / 44 / 30 */

                g_run_flag = 1;
                if (g_location_pid.SetPoint == 0)
                {
                                DC_Motor_Stop(MOTOR_1);           /* 停止则立刻响应 */                        
                                g_motor_data.motor_pwm = 0;
                                DC_Motor_Speed(g_motor_data.motor_pwm,MOTOR_1); /* 设置电机转速 */                                 
                }
                else
                {
                        DC_Motor_Start(MOTOR_1);
                        if(g_location_pid.SetPoint  <= -6600)
                        {
                                g_location_pid.SetPoint  =-6600;
                        }
                        DC_Motor_Speed(g_location_pid.SetPoint,MOTOR_1); /* 设置电机转速 */

                        atk_debug_send_motorstate(RUN_STATE);           /* 上传电机状态(运行) */
                }
        }
        else if(key == KEY2_PRES)
        {
                DC_Motor_Stop(MOTOR_1);
                g_run_flag = 0;                                 /* 标记电机停止 */
                g_motor_data.motor_pwm = 0;
                Motor_PWM_Set(g_motor_data.motor_pwm,MOTOR_1);          /* 设置电机转向、速度 */
                g_location_pid.SetPoint = 0;
                pid_init();
                atk_debug_send_motorstate(BREAKED_STATE);           /* 上传电机状态(刹车) */
                atk_debug_send_initdata(TYPE_PID1, (float *)(&g_location_pid.SetPoint), KP, KI, KD);           /* 同步数据到上位机 */
        }
}

void DCMotor_Value(void)
{
        int32_t motor_pwm_temp = 0;
        static uint16_t init_adc_val = 0;
        static uint16_t g_time =0;
        static uint8_t num = 0;
        if(num < 2)
        {
                num ++;
                atk_debug_send_motorcode(DC_MOTOR);         /* 上传电机类型(直流有刷电机) */
    atk_debug_send_motorstate(IDLE_STATE);      /* 上传电机状态(空闲) */
                init_adc_val = g_adc_val[2];
                init_adc_val += g_adc_val[2];       /* 现在的值和上一次存储的值相加 */
    init_adc_val /= 2;  
        }else
        {                                                        
                                
                                

                                /* 获取编码器值,用于计算速度 */
                                get_EncodeValue(5);        /* 中位平均值滤除编码器抖动数据,5ms计算一次速度*/
                                
                                if(g_time  % 1000 ==0)
                                {                                                                                 
                                       
                                        g_motor_data.volatage  = g_adc_val[0]*ADC2VBUS;               
                                        atk_debug_send_valtage(g_motor_data.volatage );
                                        __NOP();__NOP();__NOP();
                                        g_motor_data.board_temp = get_temp(g_adc_val[1]);
                                        atk_debug_send_temp(0,g_motor_data.board_temp);  
                                        __NOP();__NOP();__NOP();
                                       
                                        g_motor_data.current          = (abs(g_adc_val[2]-init_adc_val)*ADC2CURT)*0.001;
                                        atk_debug_send_current(g_motor_data.current,0,0);                        
                                        __NOP();__NOP();__NOP();
                                       
//                                        printf("\r\n******************************\r\n");
//                                        printf("KEY0:增加比较值,KEY1:减小比较值,KEY2:停止电机\r\n\r\n");
//                                        printf("Valtage:%.2fV \r\n",    g_motor_data.volatage);                   /* 打印电压值 */
//                                        printf("Temp:%.2fC \r\n",                    g_motor_data.board_temp   );                  /* 打印温度值 */
//                                        printf("Current:%.2fmA \r\n",   g_motor_data.current); /* 打印电流值 */
//                                        printf("电机速度:%.1f RPM\r\n\r\n",   g_motor_data.speed);               
//                                        printf("\r\n******************************\r\n");
                                }

                                else if(g_time % SMAPLSE_PID_SPEED == 0)                /* 电机速度 50ms进行一次pid计算 */
                                {
                                        if(g_run_flag == 1)
                                        {
                                                /* PID计算,输出比较值(占空比),再进行一阶低通滤波 */
                                                motor_pwm_temp = increment_pid_ctrl(&g_location_pid,g_motor_data.location);
                                                g_motor_data.motor_pwm = (int32_t)((g_motor_data.motor_pwm * 0.5) + (motor_pwm_temp * 0.5));
                                                 if (g_motor_data.motor_pwm >= 3000)                     /* 限制占空比 */
                                                {
                                                                g_motor_data.motor_pwm = 3000;
                                                }
                                                else if (g_motor_data.motor_pwm <= -3000)
                                                {
                                                                g_motor_data.motor_pwm = -3000;
                                                }
                                                atk_debug_send_wave_data( 1 ,g_motor_data.location);                                        /* 选择通道1,发送实际位置(波形显示)*/
            atk_debug_send_wave_data( 2 ,g_location_pid.SetPoint);                                      /* 选择通道2,发送目标位置(波形显示)*/
                                                
                                                Motor_PWM_Set(g_motor_data.motor_pwm,MOTOR_1);
                                        }
                                }

                                g_time ++;
        }
}

void get_EncodeValue(uint8_t  ms)
{
        int encode_now = gtim_get_encode();
        
  g_motor_data.location = encode_now;                             /* 获取当前计数总值,用于位置闭环控制 */     
        speed_computer(encode_now, ms);
}


/**
* @brief       pid初始化
* @param       无
* @retval      无
*/
void pid_init(void)
{
        
                memset(&g_motor_data,0,sizeof(g_motor_data));
                memset(&g_location_pid,0,sizeof(g_location_pid));
        
    g_location_pid.SetPoint = 0.0;       /* 设定目标值 */
    g_location_pid.ActualValue = 0.0;    /* 期望输出值 */
    g_location_pid.SumError = 0.0;       /* 积分值 */
    g_location_pid.Error = 0.0;          /* Error[1] */
    g_location_pid.LastError = 0.0;      /* Error[-1] */
    g_location_pid.PrevError = 0.0;      /* Error[-2] */
    g_location_pid.Proportion = KP;      /* 比例常数 Proportional Const */
    g_location_pid.Integral = KI;        /* 积分常数 Integral Const */
    g_location_pid.Derivative = KD;      /* 微分常数 Derivative Const */
        
                atk_debug_send_wave_data( 1 ,g_motor_data.speed);                           /* 选择通道1,发送实际速度(波形显示)*/
                atk_debug_send_wave_data( 2 ,g_location_pid.SetPoint);                         /* 选择通道2,发送目标速度(波形显示)*/
                atk_debug_send_wave_data( 3 ,g_motor_data.motor_pwm * 100 / 8400);          /* 选择通道3,发送占空比(波形显示)*/
}

void DCMotorsample_Init(void)
{
                pid_init();
                ADC1CbReg(get_Motor_value);
}





   

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

31

主题

81

帖子

1

粉丝