1 Star 4 Fork 0

sam/四轴DIY代码

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
克隆/下载
flykong.ino 12.31 KB
一键复制 编辑 原始数据 按行查看 历史
sam 提交于 2019-05-25 20:49 +08:00 . 重命名文件flykong为flykong.ino
//MPU6050相关设置
#include <Kalman.h>
#include <Wire.h>
#include <Math.h>
float fRad2Deg = 57.295779513f; //将弧度转为角度的乘数
const int MPU = 0x68; //MPU-6050的I2C地址
const int nValCnt = 7; //一次读取寄存器的数量
const int nCalibTimes = 1000; //校准时读数的次数
int calibData[nValCnt]; //校准数据
float realVals[7];
unsigned long nCurTime;
unsigned long nLastTime = 0; //上一次读数的时间
float fLastRoll = 0.0f; //上一次滤波得到的Roll角
float fLastPitch = 0.0f; //上一次滤波得到的Pitch角
Kalman kalmanRoll; //Roll角滤波器
Kalman kalmanPitch; //Pitch角滤波器
/**控制接收端变量设置start***/
int i=0;
int iii=0;
int ii[3];
int ss[4];
int s=0;//speed
int a=0;// RX init
int h=0;
int p=0;
int staus=0;// 当前状态,为1时可飞
int pp=0;//限飞电压
int limit=90;//pwm最大输出(0-255)
/**控制接收端变量设置end***/
/**pid变量设置start***/
unsigned long t=0;
float top;
float left;
float topRate ;
float leftRate ;
float measured ;
int sampletime=4;//ms 控制间隔时间
//外环
double kp=0.001;//0.45
double ki=0.0035;
double kd=0.0015;//0.0023
//内环
double knp=0.025;//0.45
double kni=0.0035;
double knd=0.0055;//0.0023
int out1,out2,out3,out4;
float desired=0.5;//获取期望角度
int topp;//是否进行pid调整的中间变量
int leftp;//是否进行pid调整的中间变量
double error; //偏差:期望-测量值
double integ; //偏差积分
double iLimit; //作积分限制
double deriv; //微分应该可用陀螺仪角速度代替
double prerror;////前一次偏差
double prlerror;////前一次偏差
/**pid变量设置end***/
/**电机引脚变量设置start***/
int pin1=4;
int pin2=5;
int pin3=10;
int pin4=11;
/**电机引脚变量设置end***/
/**PID调整函数***/
void pid()
{
h=s; //遥控传进来的speed值赋值给h变量
int ol=(nCurTime-t)/1000; //获取间隔时间 单位ms
if(ol>sampletime){ //此处判断是否进行调节
t=nCurTime;
measured=top; //获取roll角度
/**PID外环roll方向 start***/
error = desired - measured; //偏差:期望-测量值
float pout=kp*error; //pid外环 P项比例输出
float iout=ki*error*sampletime; //pid外环 i项积分输出
float rout=pout+iout; //pid外环 外环输出
/**PID外环roll方向 end***/
/**PID内环roll方向 start***/
error =rout-topRate; //角速度偏差:外环积分值-陀螺仪roll角速度测量值直接用的
pout=knp*error; //pid内环 P项比例输出
iout=kni*error*sampletime; //pid内环 I项积分输出
float dout=knd*(error-prerror);//pid内环 D项微分输出
prerror=error; //保存本次误差
float rrout=pout+iout+dout; //pid内环 输出
/**PID内环roll方向 end***/
/**PID外环pitch方向 start***/
measured=left;//pitch //获取pitch角度
error = desired - measured; //偏差:期望-测量值
pout=kp*error; //pid外环 P项比例输出
iout=ki*error*sampletime; //pid外环 I项积分输出
rout=pout+iout; //pid外环 D项微分输出
/**PID外环pitch方向 end***/
/**PID内环pitch方向 start***/
error =rout-leftRate; //角速度偏差:外环积分值-陀螺仪pitch角速度测量值直接用的
pout=knp*error; //pid内环 P项比例输出
iout=kni*error*sampletime; //pid内环 D项微分输出
dout=knd*(error-prlerror); //pid内环 D项微分输出
prlerror=error; //保存本次误差
float piout=pout+iout+dout; //pid内环 输出
/**PID内环pitch方向 end***/
/**PWM输出 start***/
out1=s-piout+rrout;
out3=s+piout-rrout;
out2=s-piout-rrout;
out4=s+piout+rrout;
/**PWM输出 end***/
/**PWM输出限幅 start***/
if(out1>limit)
out1=limit;
if(out2>limit)
out2=limit;
if(out3>limit)
out3=limit;
if(out4>limit)
out4=limit;
/**PWM输出限幅 end***/
/**PWM停止输出判断 start***/
if(out3<0)
out3=0;
if(out2<0)
out2=0;
if(out1<0)
out1=0;
if(out4<0)
out4=0;
if(s==0)
{
out1=0;
out2=0;
out3=0;
out4=0;
}
/**PWM停止输出判断 end***/
/**电路电源判断 start***/
//p=analogRead(A6);
//Serial.print("dianyuan:");
//Serial.println(p);
/**电路电源判断 end***/
/**PWM输出串口检测 start***/
//Serial.print("out1:");
//Serial.println(out1);
//Serial.print("out3:");
//Serial.println(out3);
//Serial.print("out2:");
//Serial.println(out2);
//Serial.print("out4:");
//Serial.println(out4);
/**PWM输出串口检测 end***/
/**PWM输出 start***/
analogWrite(pin1,out1);
analogWrite(pin2,out2);
analogWrite(pin3,out3);
analogWrite(pin4,out4);
/**PWM输出 end***/
}
}
void setup() {
/**飞控开机提示 start***/
pinMode(25,OUTPUT);//蜂鸣器引脚
for(int d=1;d<4;d++)
{
tone(25, 3);
delay(100);
noTone(25);
delay(100);
}
/**飞控开机提示end***/
/**MPU6050初始化 start***/
Wire.begin(); //初始化Wire库
WriteMPUReg(0x6B, 0); //启动MPU6050设备
Calibration(); //执行校准
nLastTime = micros(); //记录当前时间
/**MPU6050初始化 end***/
/**串口初始化 start***/
Serial2.begin(115200);
Serial.begin(115200);
/**串口初始化 end***/
/**电机输出口初始化 start***/
pinMode(pin1,OUTPUT);
pinMode(pin2,OUTPUT);
pinMode(pin3,OUTPUT);
pinMode(pin4,OUTPUT);
/**电机输出口初始化 end***/
}
void loop() {
/**MPU6050测量结果输出 start***/
int readouts[nValCnt];
ReadAccGyr(readouts); //读出测量值
Rectify(readouts, realVals); //根据校准的偏移量进行纠正
//计算加速度向量的模长,均以g为单位
float fNorm = sqrt(realVals[0] * realVals[0] + realVals[1] * realVals[1] + realVals[2] * realVals[2]);
float fRoll = GetRoll(realVals, fNorm); //计算Roll角
if (realVals[1] > 0) {
fRoll = -fRoll;
}
float fPitch = GetPitch(realVals, fNorm); //计算Pitch角
if (realVals[0] < 0) {
fPitch = -fPitch;
}
//计算两次测量的时间间隔dt,以秒为单位
nCurTime = micros();
float dt = (double)(nCurTime - nLastTime) / 1000000.0;
//对Roll角和Pitch角进行卡尔曼滤波
float fNewRoll = kalmanRoll.getAngle(fRoll, realVals[4], dt);
float fNewPitch = kalmanPitch.getAngle(fPitch, realVals[5], dt);
//跟据滤波值计算角度速
float fRollRate = (fNewRoll - fLastRoll) / dt;
float fPitchRate = (fNewPitch - fLastPitch) / dt;
//更新本次测的时间
nLastTime = nCurTime;
//更新Roll角和Pitch角
fLastRoll = fNewRoll;//top
fLastPitch = fNewPitch;//left
/**MPU6050测量结果输出 end***/
/**pid 涉及相关变量初始化 start***/
topRate=fRollRate;
leftRate= fPitchRate;
top=fNewRoll;
left=fNewPitch;
/**pid 涉及相关变量初始化 end***/
/**pid 本次是否进行调整判断 start***/
if(top<-1)
topp=-top;
else
topp=top;
if(left<-1)
leftp=-left;
else
leftp=left;
p=analogRead(A6);//电路电压测量
if(((h!=s)||(topp>desired)||(leftp>desired))&&(staus==1)&&(p>pp))
pid();
/**pid 本次是否进行调整判断 end***/
/**遥控数据接收 start***/
if( Serial2.available()>1)
{ i=Serial2.read();
if(i>0)
math(); //遥控数据处理函数调用
}
/**遥控数据接收 end***/
/**电源判断,低压停止飞行 start***/
// if((p<pp)&&(s>0)&&(staus==1))
// {
// power();
//
// }
/**电源判断,低压停止飞行 end***/
}
//向MPU6050写入一个字节的数据
//指定寄存器地址与一个字节的值
void WriteMPUReg(int nReg, unsigned char nVal) {
Wire.beginTransmission(MPU);
Wire.write(nReg);
Wire.write(nVal);
Wire.endTransmission(true);
}
//从MPU6050读出一个字节的数据
//指定寄存器地址,返回读出的值
unsigned char ReadMPUReg(int nReg) {
Wire.beginTransmission(MPU);
Wire.write(nReg);
Wire.requestFrom(MPU, 1, true);
Wire.endTransmission(true);
return Wire.read();
}
//从MPU6050读出加速度计三个分量、温度和三个角速度计
//保存在指定的数组中
void ReadAccGyr(int *pVals) {
Wire.beginTransmission(MPU);
Wire.write(0x3B);
Wire.requestFrom(MPU, nValCnt * 2, true);
Wire.endTransmission(true);
for (long i = 0; i < nValCnt; ++i) {
pVals[i] = Wire.read() << 8 | Wire.read();
}
}
//对大量读数进行统计,校准平均偏移量
void Calibration()
{
float valSums[7] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0};
//先求和
for (int i = 0; i < nCalibTimes; ++i) {
int mpuVals[nValCnt];
ReadAccGyr(mpuVals);
for (int j = 0; j < nValCnt; ++j) {
valSums[j] += mpuVals[j];
}
}
//再求平均
for (int i = 0; i < nValCnt; ++i) {
calibData[i] = int(valSums[i] / nCalibTimes);
}
calibData[2] += 16384; //设芯片Z轴竖直向下,设定静态工作点。
}
//算得Roll角。算法见文档。
float GetRoll(float *pRealVals, float fNorm) {
float fNormXZ = sqrt(pRealVals[0] * pRealVals[0] + pRealVals[2] * pRealVals[2]);
float fCos = fNormXZ / fNorm;
return acos(fCos) * fRad2Deg;
}
//算得Pitch角。算法见文档。
float GetPitch(float *pRealVals, float fNorm) {
float fNormYZ = sqrt(pRealVals[1] * pRealVals[1] + pRealVals[2] * pRealVals[2]);
float fCos = fNormYZ / fNorm;
return acos(fCos) * fRad2Deg;
}
//对读数进行纠正,消除偏移,并转换为物理量。公式见文档。
void Rectify(int *pReadout, float *pRealVals) {
for (int i = 0; i < 3; ++i) {
pRealVals[i] = (float)(pReadout[i] - calibData[i]) / 16384.0f;
}
pRealVals[3] = pReadout[3] / 340.0f + 36.53;
for (int i = 4; i < 7; ++i) {
pRealVals[i] = (float)(pReadout[i] - calibData[i]) / 131.0f;
}
}
//遥控数据处理函数
void math()
{
/**停止飞行声音提醒 start***/
if((i==36)&&(p>pp))
{staus=0; //是否可以飞行状态值
stop_f(); //停止飞行函数
for(int d=2;d>0;d--)
{
tone(25,3);
delay(d*200);
noTone(25);
delay(100);
}
}
/**停止飞行声音提醒 end***/
if(i==38)
{
a=1;
}
if(i==33)
{
if(iii==1)
ss[a]=ii[0];
if(iii==2)
ss[a]=ii[0]*10+ii[1];
if(iii==3)
ss[a]=ii[0]*100+ii[1]*10+ii[2];
iii=0;
a=a+1;
}
if(i==37)
{
// x1=ss[1]; //x轴控制值
// y1=ss[2]; //x轴控制值
s=ss[3]; //Speed控制值
//是否可以飞行状态值 设置
if((p>pp)&&(s>0))
staus=1;
a=0; //数据接收控制符
}
if(i>47)
{
iii=iii+1;
if(iii==1)
ii[0]=i-48;
if(iii==2)
ii[1]=i-48;
if(iii==3)
ii[2]=i-48;
i=0;
}
}
/**遥控停止飞行函数 start***/
void stop_f()
{
Serial2.print(p);
if(s>10){
for(int sss=s;sss>0;sss--)
{
analogWrite(pin1,sss);
analogWrite(pin2,sss);
analogWrite(pin3,sss);
analogWrite(pin4,sss);
delay(10);
}
analogWrite(pin1,0);
analogWrite(pin2,0);
analogWrite(pin3,0);
analogWrite(pin4,0);
}
s=0;
staus=0;
}
/**遥控停止飞行函数 end***/
/**低压停止飞行函数 start***/
void power()
{
Serial2.print(1);//低压报警值,传至遥控端
if(s>0){
for(int sss=s;sss>0;sss--)
{
analogWrite(pin1,sss);
analogWrite(pin2,sss);
analogWrite(pin3,sss);
analogWrite(pin4,sss);
delay(10);
}
analogWrite(pin1,0);
analogWrite(pin2,0);
analogWrite(pin3,0);
analogWrite(pin4,0);
}
s=0;
staus=0;
}
/**低压停止飞行函数 end***/
Loading...
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
C
1
https://gitee.com/stduino/four_axis_diy_code.git
git@gitee.com:stduino/four_axis_diy_code.git
stduino
four_axis_diy_code
四轴DIY代码
master

搜索帮助