avatar

松果工作室

欢迎光临

  • 首页
  • freeRTOS
  • ESP
  • 开发手册
  • 快速笔记
  • 个人收藏
  • 工具
Home 步进电机篇
文章

步进电机篇

Posted 2023-12-29 Updated 2024-01- 2
By YCP
27~35 min read

中断控制方法和PID

#include <MPU6050_tockn.h>
#include <Wire.h>

MPU6050 mpu6050(Wire);
float value, gy;
#define PULSE_WIDTH 1

//-------------------------------------------------------------------------------------------------卡尔曼滤波
typedef struct
{
  float LastP;  //上次估算协方差 初始化值为0.02
  float Now_P;  //当前估算协方差 初始化值为0
  float out;    //卡尔曼滤波器输出 初始化值为0
  float Kg;     //卡尔曼增益 初始化值为0
  float Q;      //过程噪声协方差 初始化值为0.001
  float R;      //观测噪声协方差 初始化值为0.543
} KFP;          //Kalman Filter parameter
float kalmanFilter(KFP *kfp, float input) {
  kfp->Now_P = kfp->LastP + kfp->Q;
  kfp->Kg = kfp->Now_P / (kfp->Now_P + kfp->R);
  kfp->out = kfp->out + kfp->Kg * (input - kfp->out);  //因为这一次的预测值就是上一次的输出值
  kfp->LastP = (1 - kfp->Kg) * kfp->Now_P;
  return kfp->out;
}
KFP KFP_X = { 0.02, 0, 0, 0, 0.1, 0.001 };// Q小R大滤波平滑
//-------------------------------------------------------------------------------------------------卡尔曼滤波


//-------------------------------------------------------------------------------------------------PID控制器
float Angle_XX = 0.0f;
double angleoutput = 0;
float kp = 20, kd = 1;
float middleAngle = 0;
double angleout() {
  angleoutput = kp * (Angle_XX + middleAngle) + kd * gy;  //PD算法
  return angleoutput;
}
//-------------------------------------------------------------------------------------------------PID控制器


//-------------------------------------------------------------------------------------------------定时器中断
uint8_t EN = 0;
volatile unsigned long currentTick = 0UL;
volatile unsigned long ticksPerPulse = UINT64_MAX;
void setTimer1(int ocra) {
  TCCR1A = 0;  // set entire TCCR1A register to 0
  TCCR1B = 0;  // same for TCCR1B
  TCNT1 = 0;   // initialize counter value to 0
  OCR1A = ocra;
  TCCR1B |= (1 << WGM12);   // turn on CTC mode
  TCCR1B |= (1 << CS11);    // set prescaler to 8
  TIMSK1 |= (1 << OCIE1A);  // enable timer compare interrupt
}
void setTimers() {
  cli();
  setTimer1(49);  // 40kHz
  sei();
}
//-------------------------------------------------------------------------------------------------PID控制器


void setup() {
  // put your setup code here, to run once:
  pinMode(2, OUTPUT);
  pinMode(3, OUTPUT);
  digitalWrite(2, LOW);
  Serial.begin(9600);
  Wire.begin();
  mpu6050.begin();
  //mpu6050.calcGyroOffsets(true);

  setTimers();
  ticksPerPulse = 40;
}


void loop() {
  mpu6050.update();
  Angle_XX = kalmanFilter(&KFP_X, mpu6050.getAngleX());
  gy = mpu6050.getGyroY();

  if (Angle_XX > 0) digitalWrite(2, LOW);
  if (Angle_XX <= 0) digitalWrite(2, HIGH);
  
  if(Angle_XX > -0.1&&Angle_XX < 0.1){
    ticksPerPulse = UINT64_MAX;
  }
  else{
    ticksPerPulse = abs((int)(3500/angleout()));
  }
  
  Serial.println(Angle_XX);
}

ISR(TIMER1_COMPA_vect) {
  if (EN == 0) {
    if (currentTick >= ticksPerPulse) {
      currentTick = 0;
    }
    if (currentTick == 0) {
      PORTD |= _BV(PD3);  // digitalWrite(MOT_B_STEP, HIGH);
    } else if (currentTick == PULSE_WIDTH) {
      PORTD &= ~_BV(PD3);  // digitalWrite(MOT_B_STEP, LOW);
    }
    currentTick++;
  }
}

电机运动快速测试

#define STEP_PIN 13

void setup() {
  pinMode(STEP_PIN,OUTPUT);
}

void loop() {
  digitalWrite(STEP_PIN,LOW);
  delayMicroseconds(80);
  digitalWrite(STEP_PIN,HIGH);
  delayMicroseconds(1);
}

旋转编码器控制步进电机

const int pin_A = 2;
const int pin_B = 3;
const int pin_BT = 6;
const int pin_DIR = 4;
const int pin_CLK = 5;

int previousDir = 0; // 用于存储上一次的 dir 值

boolean CW_1 = 0;
boolean CW_2 = 0;

int dir = 0;
int flag = 0;
int final_DIR = 0;

void printsth() {
  Serial.println(dir);
  final_DIR = dir;
}

static int previous_value = 0;
void checkAndExecuteFunction(int current_value, void (*func)(int)) {
  if (current_value != previous_value) {
    // 参数不同,调用传入的函数指针所指向的函数
    (*func)(current_value);
    // 更新上一次的参数为当前值
    previous_value = current_value;
  }
}

void setup() {
  Serial.begin(9600);

  pinMode(pin_A, INPUT);
  pinMode(pin_BT, INPUT);
  pinMode(pin_B, INPUT);
  pinMode(pin_DIR, OUTPUT);
  pinMode(pin_CLK, OUTPUT);

  attachInterrupt(digitalPinToInterrupt(2), handleInterrupt, CHANGE);
}

void loop() {
 int dirChange = final_DIR - previousDir; // 计算 dir 的变化量
  if (dirChange != 0) {
    int stepsToMove = abs(dirChange); // 获取变化量的绝对值,即要移动的步数

    for (int i = 0; i < stepsToMove*32; i++) {
      digitalWrite(pin_CLK,LOW);
      delayMicroseconds(40);
      digitalWrite(pin_CLK,HIGH);
      delayMicroseconds(1);
    }

    previousDir = final_DIR; // 更新 previousDir 的值为当前的 dir
  }
}


void handleInterrupt() {
  boolean Val_A = digitalRead(pin_A);
  boolean Val_B = digitalRead(pin_B);
  if (flag == 0 && Val_A == LOW) {
    CW_1 = Val_B;
    flag = 1;
  }
  if (flag == 1 && Val_A == HIGH) {
    CW_2 = !Val_B;
    if (CW_1 == true && CW_2 == true) {
      dir++;
      digitalWrite(pin_DIR, LOW);
    }
    if (CW_1 == false && CW_2 == false) {
      dir--;
      digitalWrite(pin_DIR, HIGH);
    }
    flag = 0;
  }
checkAndExecuteFunction(dir, printsth);
}
坑和笔记
Others
License:  CC BY 4.0
Share

Further Reading

Dec 23, 2024

其他笔记

EC800K AT连接移远云 配置过程 # 配置产品信息(初次连接需配置) AT+QIOTCFG="productinfo","pxxxxt","cDVTxxxxxxxxWGVB" # 连接开发者中心 AT+QIOTREG=1 # 查询当前连接状态(+QIOTSTATE: 8为正常) AT+QI

Jun 21, 2024

环形滤波算法

#include <stdio.h> #include <stdlib.h> #define BUFFER_SIZE 10 // 缓冲区大小 #define THRESHOLD 180

Jun 17, 2024

STM32 ADC采集的三种方式

采样周期 单个采集模式 ADC_Settings: 程序使用 uint16_t ADC_Read(

OLDER

蓝牙广播(Broadcast)

NEWER

Docker 安装 Ubuntu 环境

Recently Updated

  • ESP32(八) 简单的webserver
  • ESP32(七) NVS
  • ESP32(四) STA & AP
  • 多级菜单
  • ESP32(五) ESP32 OTA

Trending Tags

WCH Linux Elec freeRTOS STM ESP Flutter Others SwiftUI

Contents

©2025 松果工作室. Some rights reserved.

Using the Halo theme Chirpy