当前位置: 首页 > ds >正文

平衡车 --- 测量减速比 M法、T法测速

🌈个人主页:羽晨同学

💫个人格言:“成为自己未来的主人~” 

我们这篇文章主要想要讲述的是测量减速比和M法测速

测量减速比

//
// @简介: 读取左编码器的位置
//
float App_Encoder_GetPos_L(void)
{return encoder_l /22.0f/(30613.0f/1500.0f)*360.0f;
}
//
// @简介: 读取右编码器的位置
//
float App_Encoder_GetPos_R(void)
{return encoder_r/22.0f/(30613.0f/1500.0f)*360.0f;
}

M法测速

减速比为20.4,每圈线数为22,因为有11对级。

M法是适用于电机高转速的时候的,这是因为M是由电机的编码器测出来的,而时间是由单片机进行计时的,这两个之间是存在一定误差的,误差大小为1/M,所以当M越大时,误差是越小的,所以说M法测速适用于大转速的时候。

对于T法而言,T法是适用于低转速的时候的,T法测速的误差来源是单片机的计算的时间的误差,当本身测量的时间足够长的时候,也就是速度足够慢的时候,小于1微秒,相对于整段时间而言就是微不足道的,所以,这个时候的误差会小很多。

static float last_pos_l = 0;
static float last_pos_r = 0;
//
// @简介: M法测速的测试代码
//
void Encoder_M_Method_Test(void)
{App_Usart_Init();App_Encoder_Init();while(1){Delay(1);float pos_l = App_Encoder_GetPos_L();float pos_r = App_Encoder_GetPos_R();float M_l = pos_l - last_pos_l;float M_r = pos_r - last_pos_r;float omega_l = M_l/0.001f;float omega_r = M_r/0.001f;My_USART_Printf(USART2,"%f,%f\n",omega_l,omega_r);last_pos_l = pos_l;last_pos_r = pos_r;}
}

T法测速

首先,我们用direction来表示电机转动的方向

static volatile int8_t direction_l = 1;//左电机旋转方向,1 - 正转, -1 - 反转
static volatile int8_t direction_r = 1;//右电机旋转方向,1 - 正转, -1 - 反转
//
// @简介:中断响应函数,右编码器的A相
//
void EXTI3_IRQHandler(void)
{EXTI_ClearFlag(EXTI_Line3);uint8_t a = GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_3);//A相当前电压uint8_t b = GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_4);//B相当前电压if(a==Bit_SET)//上升沿{if(b==Bit_RESET){direction_r = 1;encoder_r++;}else{direction_r = -1;encoder_r--;}}else{if(b==Bit_RESET){direction_r = -1;encoder_r--;}else{direction_r = 1;encoder_r++;}}
}
//
// @简介: 中断响应函数,左编码器的A相
//
void EXTI15_10_IRQHandler(void)
{if(EXTI_GetFlagStatus(EXTI_Line14)==Bit_SET){EXTI_ClearFlag(EXTI_Line14);uint8_t a = GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_14);//A相当前电压uint8_t b = GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_15);//B相当前电压if(a==Bit_SET)//上升沿{if(b==Bit_RESET){direction_l = 1;encoder_l++;}else{direction_l = -1;encoder_l--;}}else{if(b==Bit_SET){direction_l = -1;encoder_l--;}else{direction_l = 1;encoder_l++;}}}
}

接下来,我们获取左右电机编码器的时间,从而用T法进行测速

static volatile int8_t t0_l = 0,t1_l = 0;//左编码器电机的时间
static volatile int8_t t0_r = 0,t1_r = 0;//右编码器电机的时间

然后,我们在中断函数中进行处理:

	t1_r = t0_r;t0_r = GetUs();
		t1_l = t0_l;t0_l = GetUs();
//
// @简介: 获取左编码器的速度
//
float App_Encoder_GetSpeed_L(void)
{return direction_l/((t1_l -t0_l)* 10.0e-6f)/22.0f/(30613.0f/1500.0f)*360.0f;
}
//
// @简介: 获取右编码器的速度
//
float App_Encoder_GetSpeed_R(void)
{return direction_r/((t1_l -t0_l)* 10.0e-6f)/22.0f/(30613.0f/1500.0f)*360.0f;
}

然后,我们对这个代码进行测试

//
// @简介: T法测速的测试代码
//
void Encoder_T_Method_Test(void)
{App_Usart_Init();App_Encoder_Init();while(1){Delay(1);float omega_l = App_Encoder_GetSpeed_L();float omega_r = App_Encoder_GetSpeed_R();My_USART_Printf(USART2,"%f,%f\n",omega_l,omega_r);}
}

T法测速改进

T法测速是存在问题的,比如:

1. 速度不归零

2. 换向波形异常

3. 偶尔出现毛刺

我们接下来,主要是要解决这三个问题。

解决方式,为我们应该设置一个新的now,记录当前时间,然后两者取最大时间,代码如下:

//
// @简介: 获取左编码器的速度
//
float App_Encoder_GetSpeed_L(void)
{uint64_t now = GetUs();float T;if(t0_l - t1_l > now - t0_l){T = (t0_l - t1_l)*1.0e-6f;}else{T = (now - t0_l)*1.0e-6f;}return direction_l/T/22.0f/(30613.0f/1500.0f)*360.0f;
}
//
// @简介: 获取右编码器的速度
//
float App_Encoder_GetSpeed_R(void)
{uint64_t now = GetUs();float T;if(t0_r - t1_r > now - t0_r){T = (t0_r - t1_r)*1.0e-6f;}else{T = (now - t0_r)*1.0e-6f;}return direction_r/T/22.0f/(30613.0f/1500.0f)*360.0f;
}

这样子的话,从串口助手中看,当静止不动的时候,速度就为0了

对于第二种情况

这样,我们对direction进行标记,我们就知道在哪个时候发生了换向,此时,我们直接让omega为0就好了。

//
// @简介: 获取左编码器的速度
//
float App_Encoder_GetSpeed_L(void)
{if(direction_l == 2 || direction_l ==-2) return 0;uint64_t now = GetUs();float T;if(t0_l - t1_l > now - t0_l){T = (t0_l - t1_l)*1.0e-6f;}else{T = (now - t0_l)*1.0e-6f;}return direction_l / T / 22.0f/(30613.0f/1500.0f)*360.0f;
}
//
// @简介: 获取右编码器的速度
//
float App_Encoder_GetSpeed_R(void)
{if(direction_r == 2 || direction_r ==-2) return 0;uint64_t now = GetUs();float T;if(t0_r - t1_r > now - t0_r){T = (t0_r - t1_r)*1.0e-6f;}else{T = (now - t0_r)*1.0e-6f;}return direction_r/T/22.0f/(30613.0f/1500.0f)*360.0f;
}

你看,这个时候,换向点的地方,就不会那么突兀了。

接下来,我们解决这个毛刺的问题:

这个是我们测速的代码,我们可以看到,检测到边沿的时候,会产生对应的中断。导致now和t1、t0的时间发生改变。

这样就导致了,上面图片中的现象,这个就是毛刺产生的原因。

所以,我们只要关闭这个中断就好了

//
// @简介: 获取左编码器的速度
//
float App_Encoder_GetSpeed_L(void)
{__disable_irq();//关闭单片机的总中断int8_t direction_cpy = direction_l;uint64_t t0_cpy = t0_l;uint64_t t1_cpy = t1_l;__enable_irq();//开启总中断if(direction_cpy == 2 || direction_cpy ==-2) return 0;uint64_t now = GetUs();float T;if(t0_cpy - t1_cpy > now - t0_cpy){T = (t0_cpy - t1_cpy)*1.0e-6f;}else{T = (now - t0_cpy)*1.0e-6f;}return direction_cpy / T / 22.0f/(30613.0f/1500.0f)*360.0f;
}
//
// @简介: 获取右编码器的速度
//
float App_Encoder_GetSpeed_R(void)
{__disable_irq();//关闭单片机的总中断int8_t direction_cpy = direction_r;uint64_t t0_cpy = t0_r;uint64_t t1_cpy = t1_r;__enable_irq();//开启总中断if(direction_cpy == 2 || direction_cpy ==-2) return 0;uint64_t now = GetUs();float T;if(t0_cpy - t1_cpy > now - t1_cpy){T = (t0_cpy - t1_cpy)*1.0e-6f;}else{T = (now - t0_cpy)*1.0e-6f;}return direction_cpy/T/22.0f/(30613.0f/1500.0f)*360.0f;
}

这样子的话,毛刺就没有了

好了,今天的内容就到这里,明天再见

http://www.xdnf.cn/news/20201.html

相关文章:

  • 当公司在你电脑上安装了IP-guard,你必须知道的事
  • 【面试题】你在项目中做过哪些相关性优化?
  • 【sft技巧】模型微调技巧
  • 零样本学习与少样本学习
  • 下载及交叉编译libconfig
  • 惊爆!耐达讯自动化RS485转Profinet,电机连接的“逆天神器”?
  • C++17无锁编程实战
  • 2025数学建模国赛A题思路首发!
  • 【赛题已出】2025高教社杯全国大学生数学建模竞赛ABCDE赛题已发布!
  • 阵列信号处理之均匀面阵波束合成方向图的绘制与特点解读
  • 从零开始学大模型之预训练语言模型
  • [科普] 卫星导航系统的授时原理与精度分析
  • 【案例分享】外国使馆雷电综合防护系统改造方案(四)
  • 2025年数学建模国赛B题超详细解题思路
  • 【LVGL】从HTML到LVGL:嵌入式UI的设计迁移与落地实践
  • C# FileInfo 类深度解析文件时间属性
  • NIPT 的时点选择与胎儿的异常判定
  • leetcode162.寻找峰值
  • STM32 读写备份寄存器
  • VR红色教育基地+数字党建展厅+智慧校史馆
  • 网络安全防护——主动防护和被动防护
  • java程序员的爬虫技术
  • 研发文档更新滞后的常见原因与解决方法
  • 【大模型实战笔记 1】Prompt-Tuning方法
  • 【IO进程 共享内存、信号量集】
  • Redis AOF 持久化:银行的 “交易流水单” 管理逻辑
  • 从质疑到真香:小白使用「飞牛NAS」+「节点小宝」的花式操作
  • .NET 开发者的“Fiddler”:Titanium.Web.Proxy 库的强大魅力
  • 虚拟化安全:从逃逸漏洞到实战分析
  • Python快速入门专业版(三):print 格式化输出:% 占位符、format 方法与 f-string(谁更高效?)