光电编码器测速T法和M/T法是什么
时间: 2024-01-27 12:05:29 浏览: 329
光电编码器是一种通过感应物体运动进行位置或速度测量的设备。其中,光电编码器测速的两种方法包括T法和M/T法。
T法是通过测量光电编码器输出的脉冲数来计算物体的速度,即速度=脉冲数/时间间隔。这种方法的优点是精度高,但需要对脉冲数进行积分计算,因此计算复杂度较高。
M/T法是将光电编码器输出的脉冲数转换成脉冲信号的频率,再通过计算频率与时间间隔之间的比值来得到速度。这种方法的优点是计算简单,但精度相对较低。
选择哪种方法取决于具体的应用场景和测量精度要求。
相关问题
Stm32对光电编码器M法测速的代码
下面是一份基于STM32的光电编码器M法测速的代码,供参考:
```
#include "stm32f10x.h"
#define PI 3.1415926535f
#define ENCODER_PPR 600.0f // 光电编码器的脉冲数(每转)
volatile uint16_t encoder_count = 0;
volatile uint16_t last_encoder_count = 0;
volatile uint16_t encoder_speed = 0;
void TIM3_IRQHandler(void)
{
if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET)
{
encoder_count = TIM_GetCounter(TIM2);
TIM_SetCounter(TIM2, 0);
if (encoder_count > last_encoder_count)
{
encoder_speed = (encoder_count - last_encoder_count) * 7200 / ENCODER_PPR; // 计算转速(单位:rpm)
}
else
{
encoder_speed = (last_encoder_count - encoder_count) * 7200 / ENCODER_PPR;
}
last_encoder_count = encoder_count;
TIM_ClearITPendingBit(TIM3, TIM_IT_Update);
}
}
int main(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
NVIC_InitTypeDef NVIC_InitStructure;
// 初始化TIM2作为计数器
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
TIM_TimeBaseStructure.TIM_Period = 0xFFFF;
TIM_TimeBaseStructure.TIM_Prescaler = 0;
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
TIM_Cmd(TIM2, ENABLE);
// 初始化TIM3作为计算转速的定时器
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
TIM_TimeBaseStructure.TIM_Period = 1000; // 定时器周期为1ms
TIM_TimeBaseStructure.TIM_Prescaler = 7200 - 1; // 定时器时钟源为72MHz,预分频7200,计数时钟为10kHz
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);
TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE);
TIM_Cmd(TIM3, ENABLE);
// 配置中断优先级
NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
while (1)
{
// do something
}
}
```
该代码中使用了STM32的TIM2和TIM3定时器,其中TIM2作为光电编码器的计数器,每接收到一个脉冲就加1,而TIM3作为计算转速的定时器,每隔1ms就计算一次转速并保存到全局变量encoder_speed中。在TIM3的中断服务函数中,通过计算TIM2的计数值来得到编码器转动的脉冲数,从而计算出转速。需要注意的是,在计算转速时需要将脉冲数转换为转速,这里使用了PPR和7200来进行转换。
stm32c8t6作为主控芯片 ,直流光电编码器测速电机作为控制转速的电机,用32的标准库编程,写出模糊PID控制的完整代码
很抱歉,我不是一个能直接编写代码的AI,但我可以给你一些思路和参考代码:
思路:
1. 通过读取直流光电编码器的脉冲数量,计算电机的当前转速。
2. 根据设定的目标转速和当前转速,计算出误差值。
3. 使用模糊PID控制算法,根据误差值计算出合适的控制量。
4. 将控制量输出到电机控制器中,通过PWM控制电机的转速。
参考代码:
以下是一个简单的基于标准库的模糊PID控制代码示例,仅供参考:
```c
#include "stm32f1xx.h"
#include "math.h"
#define ENCODER_PULSES_PER_REV 1024 // 每圈的脉冲数
#define PWM_FREQ 20000 // PWM 频率,单位 Hz
// PID控制器参数
#define KP 1.0f
#define KI 0.0f
#define KD 0.0f
// 模糊PID控制器参数
#define ERROR_THRESHOLD 0.1f
#define ERROR_RATE_THRESHOLD 0.05f
#define ERROR_LOW -1.0f
#define ERROR_HIGH 1.0f
#define ERROR_RATE_LOW -1.0f
#define ERROR_RATE_HIGH 1.0f
#define CONTROL_LOW -1.0f
#define CONTROL_HIGH 1.0f
// 电机控制器参数
#define PWM_MAX 65535 // PWM最大值
#define PWM_MIN 0 // PWM最小值
#define PWM_DEADBAND 10 // PWM死区,防止电机抖动
volatile uint32_t encoderCount = 0; // 直流光电编码器计数器
float targetSpeed = 100.0f; // 目标转速
float currentSpeed = 0.0f; // 当前转速
float error = 0.0f; // 误差
float lastError = 0.0f; // 上一次的误差
float errorRate = 0.0f; // 误差变化率
float control = 0.0f; // 控制量
float pwm = 0.0f; // PWM输出
void TIM2_IRQHandler(void)
{
if (TIM2->SR & TIM_SR_UIF)
{
TIM2->SR &= ~TIM_SR_UIF;
encoderCount++;
}
}
void initEncoder(void)
{
// 初始化编码器GPIO
RCC->APB2ENR |= RCC_APB2ENR_IOPAEN;
GPIOA->CRL &= ~(GPIO_CRL_CNF0 | GPIO_CRL_MODE0 | GPIO_CRL_CNF1 | GPIO_CRL_MODE1);
GPIOA->CRL |= GPIO_CRL_CNF0_1 | GPIO_CRL_MODE0_0 | GPIO_CRL_CNF1_1 | GPIO_CRL_MODE1_0;
// 初始化编码器计数器
RCC->APB1ENR |= RCC_APB1ENR_TIM2EN;
TIM2->PSC = 0;
TIM2->ARR = 0xFFFF;
TIM2->CNT = 0;
TIM2->CR1 |= TIM_CR1_CEN;
TIM2->DIER |= TIM_DIER_UIE;
NVIC_EnableIRQ(TIM2_IRQn);
}
void initPWM(void)
{
// 初始化PWM GPIO
RCC->APB2ENR |= RCC_APB2ENR_IOPBEN;
GPIOB->CRH &= ~(GPIO_CRH_CNF13 | GPIO_CRH_MODE13);
GPIOB->CRH |= GPIO_CRH_CNF13_1 | GPIO_CRH_MODE13_0;
// 初始化PWM定时器
RCC->APB1ENR |= RCC_APB1ENR_TIM4EN;
TIM4->PSC = SystemCoreClock / (PWM_FREQ * PWM_MAX);
TIM4->ARR = PWM_MAX;
TIM4->CCR2 = 0;
TIM4->CCER |= TIM_CCER_CC2E;
TIM4->CCMR1 |= TIM_CCMR1_OC2M_2 | TIM_CCMR1_OC2M_1;
TIM4->CR1 |= TIM_CR1_CEN;
}
float fuzzyPID(float error, float errorRate)
{
float errorLow = -ERROR_THRESHOLD;
float errorHigh = ERROR_THRESHOLD;
float errorRateLow = -ERROR_RATE_THRESHOLD;
float errorRateHigh = ERROR_RATE_THRESHOLD;
float controlLow = -1.0f;
float controlHigh = 1.0f;
float errorNB = 0.0f;
float errorNS = 0.0f;
float errorZO = 0.0f;
float errorPS = 0.0f;
float errorPB = 0.0f;
float errorRateNB = 0.0f;
float errorRateNS = 0.0f;
float errorRateZO = 0.0f;
float errorRatePS = 0.0f;
float errorRatePB = 0.0f;
float controlNB = 0.0f;
float controlNS = 0.0f;
float controlZO = 0.0f;
float controlPS = 0.0f;
float controlPB = 0.0f;
float totalError = 0.0f;
float totalErrorRate = 0.0f;
float totalControl = 0.0f;
float totalWeight = 0.0f;
// 计算误差的隶属度函数
if (error <= errorLow)
{
errorNB = 1;
}
else if (error > errorLow && error < 0)
{
errorNB = (error - errorLow) / (0 - errorLow);
errorNS = 1 - errorNB;
}
else if (error == 0)
{
errorZO = 1;
}
else if (error > 0 && error < errorHigh)
{
errorPS = (errorHigh - error) / (errorHigh - 0);
errorZO = 1 - errorPS;
}
else if (error >= errorHigh)
{
errorPB = 1;
}
// 计算误差变化率的隶属度函数
if (errorRate <= errorRateLow)
{
errorRateNB = 1;
}
else if (errorRate > errorRateLow && errorRate < 0)
{
errorRateNB = (errorRate - errorRateLow) / (0 - errorRateLow);
errorRateNS = 1 - errorRateNB;
}
else if (errorRate == 0)
{
errorRateZO = 1;
}
else if (errorRate > 0 && errorRate < errorRateHigh)
{
errorRatePS = (errorRateHigh - errorRate) / (errorRateHigh - 0);
errorRateZO = 1 - errorRatePS;
}
else if (errorRate >= errorRateHigh)
{
errorRatePB = 1;
}
// 计算控制量的隶属度函数
controlNB = CONTROL_LOW;
controlNS = (CONTROL_LOW + CONTROL_HIGH) / 2;
controlZO = CONTROL_HIGH;
controlPS = (CONTROL_LOW + CONTROL_HIGH) / 2;
controlPB = CONTROL_HIGH;
// 计算模糊推理
for (int i = 0; i < 5; i++)
{
for (int j = 0; j < 5; j++)
{
if (i == 0 || j == 0)
{
continue;
}
totalWeight = fminf(errorNB, errorRateNB);
totalControl = controlNB;
totalError = i - 3;
totalErrorRate = j - 3;
if (errorNS > 0 && errorRateNB > 0)
{
totalWeight = fminf(totalWeight, fminf(errorNS, errorRateNB));
totalControl = fmaxf(totalControl, controlNS);
totalError = totalError + (i - 2);
totalErrorRate = totalErrorRate - (j - 2);
}
if (errorNS > 0 && errorRateZO > 0)
{
totalWeight = fminf(totalWeight, fminf(errorNS, errorRateZO));
totalControl = fmaxf(totalControl, controlNS);
totalError = totalError + (i - 2);
}
if (errorNS > 0 && errorRatePS > 0)
{
totalWeight = fminf(totalWeight, fminf(errorNS, errorRatePS));
totalControl = fmaxf(totalControl, controlZO);
totalError = totalError + (i - 2);
totalErrorRate = totalErrorRate + (j - 2);
}
if (errorZO > 0 && errorRateNB > 0)
{
totalWeight = fminf(totalWeight, fminf(errorZO, errorRateNB));
totalControl = fmaxf(totalControl, controlNS);
totalErrorRate = totalErrorRate - (j - 2);
}
if (errorZO > 0 && errorRateZO > 0)
{
totalWeight = fminf(totalWeight, fminf(errorZO, errorRateZO));
totalControl = fmaxf(totalControl, controlZO);
}
if (errorZO > 0 && errorRatePS > 0)
{
totalWeight = fminf(totalWeight, fminf(errorZO, errorRatePS));
totalControl = fmaxf(totalControl, controlZO);
totalErrorRate = totalErrorRate + (j - 2);
}
if (errorPS > 0 && errorRateNB > 0)
{
totalWeight = fminf(totalWeight, fminf(errorPS, errorRateNB));
totalControl = fmaxf(totalControl, controlZO);
totalError = totalError - (i - 2);
totalErrorRate = totalErrorRate - (j - 2);
}
if (errorPS > 0 && errorRateZO > 0)
{
totalWeight = fminf(totalWeight, fminf(errorPS, errorRateZO));
totalControl = fmaxf(totalControl, controlZO);
totalError = totalError - (i - 2);
}
if (errorPS > 0 && errorRatePS > 0)
{
totalWeight = fminf(totalWeight, fminf(errorPS, errorRatePS));
totalControl = fmaxf(totalControl, controlPS);
totalError = totalError - (i - 2);
totalErrorRate = totalErrorRate + (j - 2);
}
if (totalWeight > 0)
{
control = control + (totalControl * totalWeight);
}
}
}
return control;
}
int main(void)
{
// 初始化硬件
SystemInit();
initEncoder();
initPWM();
// 进入主循环
while (1)
{
// 计算当前转速
currentSpeed = encoderCount * 60.0f / (ENCODER_PULSES_PER_REV * TIM2->CNT);
encoderCount = 0;
// 计算误差和误差变化率
error = targetSpeed - currentSpeed;
errorRate = error - lastError;
lastError = error;
// 计算模糊PID控制量
control = fuzzyPID(error, errorRate);
// 计算PWM输出
pwm = PWM_MIN + (PWM_MAX - PWM_MIN) * (control + 1) / 2;
if (pwm < (PWM_MIN + PWM_DEADBAND))
{
pwm = PWM_MIN;
}
else if (pwm > (PWM_MAX - PWM_DEADBAND))
{
pwm = PWM_MAX;
}
TIM4->CCR2 = (uint16_t)pwm;
}
}
```
需要注意的是,以上代码仅是一个简单的示例,实际应用中需要根据具体情况进行调整和优化。如果您有任何问题或需要进一步的帮助,请随时联系我。
阅读全文
相关推荐










