对智能小车测速代码的理解

本文解析了一个智能小车测速代码中,通过C语言计数器反转技巧实现编码器脉冲计数的巧妙方法,讨论了其工作原理及局限性。
摘要由CSDN通过智能技术生成

本文简述了本人对一种智能小车测速代码的原理的理解。如果大家有异议,还请指出。示例代码来自本人购买的智能小车配套的源码。代码如下:

int Read_Encoder(u8 TIMX)
{
    int Encoder_TIM;    
    switch(TIMX)
    {
        case 2:  Encoder_TIM= (short)TIM2 -> CNT;  TIM2 -> CNT=0; break;
        case 3:  Encoder_TIM= (short)TIM3 -> CNT;  TIM3 -> CNT=0; break;    
        case 4:  Encoder_TIM= (short)TIM4 -> CNT;  TIM4 -> CNT=0; break;    
        case 8:  Encoder_TIM= (short)TIM8 -> CNT;  TIM8 -> CNT=0; break;    
        default:  Encoder_TIM=0;
    }
    return Encoder_TIM;
}

void Get_Velocity_From_Encoder(void)
{
    
     //Retrieves the original data of the encoder
      //获取编码器的原始数据
        float Encoder_A_pr,Encoder_B_pr; 
        OriginalEncoder.A=Read_Encoder(Encoder1);    
        OriginalEncoder.B=Read_Encoder(Encoder2);    

      //Decide the encoder numerical polarity according to different car models
        //根据不同小车型号决定编码器数值极性
        switch(Car_Num)
        {
            case Akm_Car:       Encoder_A_pr=OriginalEncoder.A; Encoder_B_pr=-OriginalEncoder.B;break;
            case Diff_Car:      Encoder_A_pr=OriginalEncoder.A; Encoder_B_pr=-OriginalEncoder.B;break; 
            case Small_Tank_Car:Encoder_A_pr=OriginalEncoder.A; Encoder_B_pr=-OriginalEncoder.B;break;
            case Big_Tank_Car:  Encoder_A_pr=OriginalEncoder.A; Encoder_B_pr=-OriginalEncoder.B;break;
        }
        //The encoder converts the raw data to wheel speed in m/s
        //编码器原始数据转换为车轮速度,单位m/s
        MotorA.Current_Encoder= Encoder_A_pr*Frequency*Perimeter/1560.0f;  
        MotorB.Current_Encoder= Encoder_B_pr*Frequency*Perimeter/1560.0f;  //1560=4*13*30=2(两路脉冲)*2(上下沿计数)*霍尔编码器13线*电机的减速比
//        MotorA.Current_Encoder= Encoder_A_pr*CONTROL_FREQUENCY*Akm_wheelspacing//(4*13*30);  
//        MotorB.Current_Encoder= Encoder_B_pr*CONTROL_FREQUENCY*Akm_wheelspacing/Encoder_precision;  
}

代码流程简单来讲,就是Get_Velocity_From_Encoder调用Read_Encoder读取左右两个电机的编码器脉冲计数值,然后进行处理,最后算出车轮的速度,存放到各自的结构体的成员Current_Encoder中。不过,本文要说的其实是这里的Read_Encoder函数。这个函数一开始看起来觉得怪怪的,因为在我遇到的场景下,当车子向前行驶时,与TIM8相连的电机是在反转的,所以TIM8的计数方向是递减的,在测量周期内,编码器脉冲计数值应该是65536-CNT,而非CNT的值。但是,整个小车的运行看起来却是正常的,这是咋回事?带着这个疑问,我用KEIL的调试功能跑了一下程序,最终发现了其中的奥秘。
这个问题的关键其实就是这个将CNT强制转换成short类型的操作上。CNT是一个无符号32位整型变量。假设CNT的值为0x0000FFF5,那么这个CNT对应的内存区域就存储着0x0000FFF5的补码,即0x0000FFF5. 当其被强制转换成short类型时,C语言会截取这个补码低16位,并将其作为一个short类型变量的补码来处理,于是CNT的值就变成了-11,在计数器处于递减模式时,这个数值的绝对值正好就是编码器脉冲计数值。而且负号也正好表示电机是在反转的,这也符合实际情况。这可以说是对C语言特性的一个巧妙运用。不过这种做法其实也是有局限性的,它要求当计数器处于递减模式时,CNT的最高位要保持为1,当计数器处于递增模式时,CNT的最高位要保持为0,否则就要出错。下面简要说明一下。
假设计数器处于递减模式,然后此时CNT的值是0x00007FF5, 那么,其低16位就是个正数的补码,将其强制转换成short类型后,其数值就是32757。而此时,由于计数器处于递减模式,所以,这个数值的绝对值并不等于编码器的脉冲计数值。计数器处于递增模式时的情况与此类似。这种方法的局限性决定了其测量周期不能太长。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值