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

ROS 2 FishBot PID控制电机代码

#include <Arduino.h>
#include <Wire.h>
#include <MPU6050_light.h>
#include <Esp32McpwmMotor.h>
#include <Esp32PcntEncoder.h>Esp32McpwmMotor motor;        // 创建一个名为motor的对象,用于控制电机
Esp32PcntEncoder encoders[2]; // 创建一个数组用于存储两个编码器MPU6050 mpu(Wire);int64_t last_ticks[2] = {0, 0}; // 用于存储上一次编码器的计数
int64_t delta_ticks[2] = {0, 0}; // 用于存储两次编码器计数之间的差值
int64_t last_update_time = 0;    // 用于存储上一次更新时间
float current_speed[2] = {0, 0}; // 用于存储当前速度// put function declarations here:
int myFunction(int, int);#define TRIG 27
#define ECHO 21
#define LED_BUILTIN 2unsigned long previousMillis = 0; // 用于记录上一次电平切换的时间
const long interval = 500;        // 定时器间隔,单位为毫秒void setup()
{// put your setup code here, to run once:int result = myFunction(2, 3);Serial.begin(115200);pinMode(TRIG, OUTPUT);pinMode(ECHO, INPUT);pinMode(LED_BUILTIN, OUTPUT);Wire.begin(18, 19); // SDA, SCLbyte status = mpu.begin();Serial.print(F("MPU6050 status: "));Serial.println(status);while (status != 0){// stop everything if could not connect to MPU6050}mpu.calcOffsets(true, true); // gyro and acceleroSerial.println("Done!");Serial.println("===========================\n");motor.attachMotor(0, 22, 23); // 将电机0连接到引脚22和引脚23motor.attachMotor(1, 12, 13); // 将电机1连接到引脚12和引脚13Serial.println("Motor Done!");// 编码器encoders[0].init(0, 32, 33); // 初始化第一个编码器,使用GPIO 32和33连接encoders[1].init(1, 26, 25); // 初始化第二个编码器,使用GPIO 26和25连接Serial.println("Encoder Done!");// 控制电机motor.updateMotorSpeed(0, 100); // 设置电机0的速度为负70motor.updateMotorSpeed(1, 0);  // 设置电机1的速度为正70
}unsigned long timer = 0;
void loop()
{// put your main code here, to run repeatedly:digitalWrite(TRIG, HIGH);delayMicroseconds(10);digitalWrite(TRIG, LOW);double duration = pulseIn(ECHO, HIGH);double distance = duration * 0.034 / 2;// Serial.printf("Distance: %lf cm\n", distance);/*mpu.update();if ((millis() - timer) > 1000){// 温度Serial.printf("Temp: %lf\n", mpu.getTemp());// 加速度计数据Serial.printf("Accel: %lf %lf %lf\n", mpu.getAccX(), mpu.getAccY(), mpu.getAccZ());// 加速度计角度Serial.printf("Angle: %lf %lf %lf\n", mpu.getAngleX(), mpu.getAngleY(), mpu.getAngleZ());// 陀螺仪数据Serial.printf("Gyro: %lf %lf %lf\n", mpu.getGyroX(), mpu.getGyroY(), mpu.getGyroZ());// 综合角度Serial.printf("Angle: %lf %lf %lf\n", mpu.getAngleX(), mpu.getAngleY(), mpu.getAngleZ());Serial.println("===========================\n");timer = millis();}*/// 获取当前时间unsigned long currentMillis = millis();// 检查是否达到定时器间隔if (currentMillis - previousMillis >= interval){// 记录当前时间previousMillis = currentMillis;// 切换2号脚的电平digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));}delay(10);// 读取编码器的计数器数值int64_t dt = millis() - last_update_time; // 计算时间差delta_ticks[0] = encoders[0].getTicks() - last_ticks[0]; // 计算第一个编码器的差值delta_ticks[1] = encoders[1].getTicks() - last_ticks[1]; // 计算第二个编码器的差值current_speed[0] = delta_ticks[0]*0.105805 / (float)dt; // 计算第一个编码器的速度current_speed[1] = delta_ticks[1]*0.105805 / (float)dt; // 计算第二个编码器的速度//下次正常计算last_ticks[0] = encoders[0].getTicks(); // 保存第一个编码器的计数last_ticks[1] = encoders[1].getTicks(); // 保存第二个编码器的计数last_update_time = millis(); // 保存当前时间// 读取并打印两个编码器的计数器数值 一圈1930个脉冲 直径65mm  一个脉冲前进=0.105805mmSerial.printf("speed1=%lf,speed2=%lf\n", current_speed[0], current_speed[1]);//Serial.printf("tick1=%d,tick2=%d\n", encoders[0].getTicks(), encoders[1].getTicks());
}// put function definitions here:
int myFunction(int x, int y)
{return x + y;
}

Lib

PidController.cpp

#include "PidController.h"
#include <Arduino.h>PidController::PidController() = default;
// 默认构造函数
PidController::PidController(float kp, float ki, float kd) {_kp = kp;_ki = ki;_kd = kd;}
/*float update(float current);// 更新PID控制器,提供当前值,返回控制量void update_target(float target); // 更新目标值void update_pid(float kp, float ki, float kd); // 更新PID参数void reset(); // 重置PID控制器void out_limit(float); // 输出限制
*/
float PidController::update(float current){error_ = target_ - current; // 计算误差error_sum_ += error_; // 累加误差if(error_sum_ > intergral_up_) error_sum_ = intergral_up_; // 积分限幅if(error_sum_ < -1*intergral_up_) error_sum_ = -1*intergral_up_; // 积分限幅derror_ = error_ - prev_error_; // 计算误差变化率prev_error_ = error_; // 保存上一次误差float output = _kp * error_ + _ki * error_sum_ + _kd * derror_; // 计算输出if(output > out_max_) output = out_max_; // 输出限幅if(output < out_min_) output = out_min_; // 输出限幅return output;
}
void PidController::update_target(float target){target_ = target;
}
void PidController::update_pid(float kp, float ki, float kd){_kp = kp;_ki = ki;_kd = kd; 
}
void PidController::reset(){error_ = 0;error_sum_ = 0;derror_ = 0; prev_error_ = 0;_kp = 0;_ki = 0;_kd = 0;intergral_up_ = 2500; out_max_ = 0;out_min_ = 0;
}
void PidController::out_limit(float out_min, float out_max){out_max_ = out_max;out_min_ = out_min; 
}

PidController.h

#ifndef _PID_CONTROLLER_H_
#define _PID_CONTROLLER_H_class PidController{public:PidController() = default;PidController(float kp, float ki, float kd);private:// pid 控制器参数float target_;// 目标值float out_min_;// 输出最小值float out_max_;// 输出最大值float _kp; // 比例系数float _ki; // 积分系数float _kd; // 微分系数float intergral_up_ = 2500; // 积分上限//pid 中间float error_; // 误差float error_sum_; // 误差和float derror_; // 误差差分float prev_error_; // 上次误差public:float update(float current);// 更新PID控制器,提供当前值,返回控制量void update_target(float target); // 更新目标值void update_pid(float kp, float ki, float kd); // 更新PID参数void reset(); // 重置PID控制器void out_limit(float out_min, float out_max); // 输出限制};#endif
// _PID_CONTROLLER_H_;

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

相关文章:

  • ‌中继器:网络中的“血包”与“加时器”‌
  • 【python编程从入门到到实践】第六章 字典
  • 将PyQt5设计的程序打包成.exe文件
  • 掌握 void 类型在函数返回值中的应用
  • 企业级数据安全实践:ChatBI的多源异构治理与OLAP查询加速方案
  • Java中的JDK7和JDK8时间类详解
  • Zotero文献管理
  • Nginx重写功能
  • 使用Python调用ComfyUI API实现图像生成
  • Java+MySQL学生管理系统
  • 【github分享】开发者学习路线图
  • DBdoctor:一款企业级数据库性能诊断工具
  • 什么是 ANR 如何避免它
  • Java 程序流程控制篇
  • 什么是电路耦合以及如何解耦合
  • PostgreSQL 的 pg_column_size 函数
  • 《打造自己的DeepSeek》第2期:怎么安装自己的DeepSeek?
  • 当 Manus AI 遇上 OpenAI Operator,谁能更胜一筹?
  • Python 对象引用、可变性和垃圾 回收(标识、相等性和别名)
  • python 写一个工作 简单 番茄钟
  • Linux-Ubuntu安装Stable Diffusion Forge
  • 【计组】真题
  • 快速傅里叶变换暴力涨点!基于时频特征融合的高创新时间序列分类模型
  • 相或为K(位运算)蓝桥杯(JAVA)
  • 【C++】16.继承
  • PHP API安全设计四要素:构建坚不可摧的接口防护体系
  • linux kernel调度触发机制
  • 现有预测式外呼系统如何接入AI系统,使用AI辅助,判断出意向客户再转人工
  • 红外遥控键
  • RDD 两类操作详解(Scala):转换与行动