我已经基于TinyCLR.com的.NET Micro Framework板从头开始构建了tricopter。我使用了运行在72 MHz的FEZ Mini。在http://bit.ly/TriRot了解有关我的项目的更多信息。
因此,在进行飞行前检查后,我初始化并测试每个组件,例如校准IMU并旋转每个电机,检查我是否获得接收器数据等,它进入一个永久循环然后调用每个循环上的飞行控制器方法。
我正在尝试使用PID controller调整我的Ziegler-Nichols method,但我总是会越来越大的超调。我最终只能使用proportional control获得[大多数]稳定振荡(设置K i 和K d = 0);使用秒表计算周期K 的平均时间为3.198秒。
我在类似的answer Rex Logan上看到了question(chris12892){{3}}。
我最初使用“持续时间”变量(以毫秒为单位)使得我的直升机非常具有攻击性,显然是因为我在每个循环中将运行的积分器误差乘以数千。然后我把它除以另外一千来把它带到几秒钟,但我仍然在争吵......
雷克斯的答案中我不明白的是:
他的意思是什么
在正常的采样系统中,delta项将是一个......
一个什么?在正常情况下这应该是一秒吗?什么 如果这个值波动?
我的飞行控制器方法如下:
private static Single[] FlightController(Single[] imuData, Single[] ReceiverData)
{
Int64 TicksPerMillisecond = TimeSpan.TicksPerMillisecond;
Int64 CurrentTicks = DateTime.Now.Ticks;
Int64 TickCount = CurrentTicks - PreviousTicks;
PreviousTicks = CurrentTicks;
Single Duration = (TickCount / TicksPerMillisecond) / 1000F;
const Single Kp = 0.117F; //Proportional Gain (Instantaneou offset)
const Single Ki = 0.073170732F; //Integral Gain (Permanent offset)
const Single Kd = 0.001070122F; //Differential Gain (Change in offset)
Single RollE = 0;
Single RollPout = 0;
Single RollIout = 0;
Single RollDout = 0;
Single RollOut = 0;
Single PitchE = 0;
Single PitchPout = 0;
Single PitchIout = 0;
Single PitchDout = 0;
Single PitchOut = 0;
Single rxThrottle = ReceiverData[(int)Channel.Throttle];
Single rxRoll = ReceiverData[(int)Channel.Roll];
Single rxPitch = ReceiverData[(int)Channel.Pitch];
Single rxYaw = ReceiverData[(int)Channel.Yaw];
Single[] TargetMotorSpeed = new Single[] { rxThrottle, rxThrottle, rxThrottle };
Single ServoAngle = 0;
if (!FirstRun)
{
Single imuRoll = imuData[1] + 7;
Single imuPitch = imuData[0];
//Roll ----- Start
RollE = rxRoll - imuRoll;
//Proportional
RollPout = Kp * RollE;
//Integral
Single InstanceRollIntegrator = RollE * Duration;
RollIntegrator += InstanceRollIntegrator;
RollIout = RollIntegrator * Ki;
//Differential
RollDout = ((RollE - PreviousRollE) / Duration) * Kd;
//Sum
RollOut = RollPout + RollIout + RollDout;
//Roll ----- End
//Pitch ---- Start
PitchE = rxPitch - imuPitch;
//Proportional
PitchPout = Kp * PitchE;
//Integral
Single InstancePitchIntegrator = PitchE * Duration;
PitchIntegrator += InstancePitchIntegrator;
PitchIout = PitchIntegrator * Ki;
//Differential
PitchDout = ((PitchE - PreviousPitchE) / Duration) * Kd;
//Sum
PitchOut = PitchPout + PitchIout + PitchDout;
//Pitch ---- End
TargetMotorSpeed[(int)Motors.Motor.Left] += RollOut;
TargetMotorSpeed[(int)Motors.Motor.Right] -= RollOut;
TargetMotorSpeed[(int)Motors.Motor.Left] += PitchOut;// / 2;
TargetMotorSpeed[(int)Motors.Motor.Right] += PitchOut;// / 2;
TargetMotorSpeed[(int)Motors.Motor.Rear] -= PitchOut;
ServoAngle = rxYaw + 15;
PreviousRollE = imuRoll;
PreviousPitchE = imuPitch;
}
FirstRun = false;
return new Single[] {
(Single)TargetMotorSpeed[(int)TriRot.LeftMotor],
(Single)TargetMotorSpeed[(int)TriRot.RightMotor],
(Single)TargetMotorSpeed[(int)TriRot.RearMotor],
(Single)ServoAngle
};
}
编辑:我发现上面的代码中有两个错误(现在修复)。我正在整合和区分最后的IMU值而不是最后的错误值。完全摆脱了失控的冥想。现在唯一的问题是它看起来有点慢。当我扰乱系统时,它会很快响应并阻止它继续,但是需要很长时间才能回到设定点(0),大约10秒或更长时间。现在这只是调整PID吗?我将在下面给出建议,并告诉您是否有任何改变。
我遇到的一个问题是: 作为一个.NET板,我不想依赖于任何类型的精确计时,所以我不是试图以我执行该方法的频率计算出来,当然如果我计算实际时间和因子,它应该更好,还是我误解了什么?