if debugging and testing is the process to remove bugs, then writing software
must be the process creating them

no time for testing and bug catching - we are up in the mountains.
happy new year to all ...
scrat wrote:Just for info...yesterday I have tested (in garage) the latest baseflight hex from git. ALT HOLD works now almost prefect. At default settings. Quad is in + - 20 cmI'm happy camper now.
But I saw on git that there exist new VEL_PID's for baro, but I can't tune them in chrome configurator.
scrat wrote:Just for info...yesterday I have tested (in garage) the latest baseflight hex from git. ALT HOLD works now almost prefect. At default settings. Quad is in + - 20 cmI'm happy camper now.
But I saw on git that there exist new VEL_PID's for baro, but I can't tune them in chrome configurator.
IceWind wrote:Thanks TC.
So I set gimbal_flags to 2 to get the AUX forwarding enabled. But when testing doesn't seem to work.
I plugged a servo signal to the RC5 to test and when I do that it just starts going nuts.
I later tried on other RC's like 6 and 7. On RC7 the input signal is 1500 so I would expect the servo to center.
Any idea what I might be missing?
crazyal wrote:I'm happy to hear that my stuff finally works for someone else than me
Right, the VEL_PIDs are only in the development version of cTns Baseflight-Configurator as they were "dead code" and I added the patch just recently.
It seems like no current GUI supports the VEL_PID. You can use the patched Version I have on my github https://github.com/luggi/baseflight-configurator or use the devopment version which only works with Chrome Beta.
Plüschi wrote:Attached the Graupner SUMD receiver code i have been testing recently.
Connections to NAZE is Gnd, 5V and serial input pin #4
Edit: now its a real patch
timecop wrote:Plüschi wrote:placing if () on same line doesn't make it faster.
Crashpilot1000 wrote:Have you ever developed anything on your own in your copypasted mess?
QuadsDestroyer wrote:Timecop,
Would you be capable to make baseflight compatible with the OneShot output method developed by Felix Nielssen (ronco) as implemented in the UltraESC-FlyduinoNanoWii combo?
The method is schematised here
Warthox, the reference in multicopter sport flying, describes its benefits in terms of performance at http://www.rcgroups.com/forums/showpost ... stcount=42.
You can find the practical implementation of the method in the file Output.ino within http://ultraesc.de/downloads/MWC21Nano_v099.zip
If you could do this it would be brilliant and clearly make the Naze the best FC available.
Also it would save me from switching from Afro Naze to Nanowii...
Thank you very much
crazyal wrote:Simply because it didn't work as well as hoped. I never really got the default pids tuned right and timecop didn't like the float pid factors, because they don't blend in nicely with the 8-bit defaults. If you like playing around with beta stuff, give it a shot and we might find some values that work "magically"
Crashpilot1000 wrote:You will have to ask/trust in the guys with Flyduino branding on their underwear.
Cheers Rob
QuadsDestroyer wrote:timecop: yes I did and just found one person asking you after which you refused without more explanation than just saying there's no improvement...
However, could you develop the reasoning behind which OneShot doesn't bring anything? Videos and testimonies say the opposite though...Especially for 3d enabled ESCs...
If it has really been extensively covered in this thread, then let me know and I will look again...
Cheers
brm: are you saying that what ronco claims to have achieved is impossible because of the hw pwm on both chips and that he is basically lying?!?
QuadsDestroyer wrote:Warthox describes its benefits in terms of performance at http://www.rcgroups.com/forums/showpost ... stcount=42.
Plüschi wrote:QuadsDestroyer wrote:Warthox describes its benefits in terms of performance at http://www.rcgroups.com/forums/showpost ... stcount=42.
Guy complains the esc cycle and the mwii cycle are not synced. There is a variable delay of 0 to 2ms. True. But there is also a variable delay of 0 to 20ms because in mwii rc input and rc processing are NOT sync.
But there is hope. Baseflight. Set looptime to 2.5ms and leave esc rate 400hz and your cycle and esc are synced. Can you feel the difference?
Lets do a reality check:
The highest sensor lowpass is 250hz. With the tarduino mwii averaging we get down to 125hz (averaging IS a lowpass). The fastest the FC will react to movement is 1000ms/125 = 8ms.
Guy talks about crisp reactions. The RC transmitter needs 20ms for reading ADC and to mix it up and then at least 20ms over the air time. The receiver needs another 20ms to assemble the stuff and send it to the FC. Then mwii averages it over 4 cycles, which adds 40ms delay. Before the FC starts the calculations there is already a summed up 100ms delay.
The 2ms delay doesent matter at all. I call the "feeling a 2ms delay difference" and "crisp" complete BS.
Code: Select all
static uint16_t PWMValues[8] = {1000,1000,1000,1000,1000,1000,1000,1000};
static uint8_t PWM_type[8] = {1,1,1,1,1,1,1,1}; // 0= oneshot125 (125-250us), 1= oneshot 1-2ms with ~450Hz, 2= 1-2ms at ~225Hz(DServo), 3 = 1-2ms at ~56Hz(AServo)
void setup_PWM_OUT(){
/* PWM Output Pins:
PWM1 ->TIM 3 CH1 -> A6
PWM2 ->TIM 3 CH2 -> A7
PWM3 ->TIM 3 CH3 -> B0
PWM4 ->TIM 3 CH4 -> B1
PWM5 -> TIM 2 CH1 -> PA0
PWM6 -> TIM 2 CH2 -> PA1
PWM7 ->TIM 4 CH3 -> B8
PWM8 ->TIM 4 CH4 -> B9
*/
//oneshot 125 = 1007 - 2014 (125-250us);
//450Hz = 8056 - 16112 (1000-2000us)
//GPIO settings ---------------------------------------------------------------------------------
GPIO_InitTypeDef gpioinitTIM;
gpioinitTIM.GPIO_Mode = GPIO_Mode_AF_PP;
gpioinitTIM.GPIO_Speed = GPIO_Speed_50MHz;
//GPIOA
gpioinitTIM.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_6 | GPIO_Pin_7;
GPIO_Init(GPIOA, &gpioinitTIM);
//GPIOB
gpioinitTIM.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_8 | GPIO_Pin_9;
GPIO_Init(GPIOB, &gpioinitTIM);
//TIMER 2, 3 & 4 ---------------------------------------------------------------------------------
//timer base config
TIM_TimeBaseInitTypeDef timerbaseinit;
timerbaseinit.TIM_Prescaler = 8;
timerbaseinit.TIM_CounterMode = TIM_CounterMode_Up;
timerbaseinit.TIM_Period = 0xFFFF;
timerbaseinit.TIM_ClockDivision = 0;
timerbaseinit.TIM_RepetitionCounter = 0;
TIM_TimeBaseInit(TIM3, &timerbaseinit);
TIM_TimeBaseInit(TIM2, &timerbaseinit);
TIM_TimeBaseInit(TIM4, &timerbaseinit);
// channel base config
TIM_OCInitTypeDef channelbaseconf;
channelbaseconf.TIM_OCMode = TIM_OCMode_PWM2;
channelbaseconf.TIM_OutputState = TIM_OutputState_Enable;
channelbaseconf.TIM_Pulse = 8056; // 1ms basic output
channelbaseconf.TIM_OCPolarity = TIM_OCPolarity_Low;
TIM_OC1Init(TIM3, &channelbaseconf);
TIM_OC2Init(TIM3, &channelbaseconf);
TIM_OC3Init(TIM3, &channelbaseconf);
TIM_OC4Init(TIM3, &channelbaseconf);
TIM_OC1Init(TIM2, &channelbaseconf);
TIM_OC2Init(TIM2, &channelbaseconf);
TIM_OC3Init(TIM4, &channelbaseconf);
TIM_OC4Init(TIM4, &channelbaseconf);
//start timers ---------------------------------------------------------------------------------
// enable Tim3
TIM_CtrlPWMOutputs(TIM3, ENABLE);
TIM_Cmd(TIM3, ENABLE);
// enable Tim2
TIM_CtrlPWMOutputs(TIM2, ENABLE);
TIM_Cmd(TIM2, ENABLE);
// enable Tim4
TIM_CtrlPWMOutputs(TIM4, ENABLE);
TIM_Cmd(TIM4, ENABLE);
}
//assumes a cycletime of minmum 1111us
void writePWMOutputs(){
static uint8_t skipCounter = 0; // skips one loop for 450Hz for 1-2ms
static uint8_t stretchCounter = 0; // stretches the pulse to 225 or 56Hz for servos
static uint8_t refresh_compare[3] = {0,0,0};
uint8_t drive_fast[3] = {1,1,1};
uint16_t usePWMValues[8];
uint8_t i;
// calculate the needed duty values for the timer channels and check if 900Hz for one are possible
for(i = 0;i< 8; i++){
if(PWM_type[i] != 0){
usePWMValues[i] = constrain((PWMValues[i]*8056)/1000,8056,16112);
if(i < 3) drive_fast[0] = 0;
if(i > 3 && i < 5) drive_fast[1] = 0;
if(i > 5) drive_fast[2] = 0;
}else{
usePWMValues[i] = constrain((PWMValues[i]*1007)/1000,1007,2014);
}
}
// if there is one 1-2ms signal needed at one of the timer groupes, skip one reload to have at last 2055us time
if(!(drive_fast[0] == 0 && skipCounter != 0)){
uint16_t TIM3_actCounter = TIM_GetCounter(TIM3);
if((TIM3_actCounter > 2020 && drive_fast[0] == 1) || TIM3_actCounter > 16200){ // protect the signal from reload before the compare values are reached
TIM_Cmd(TIM3, DISABLE);
TIM_SetCounter(TIM3, 0xFFFF);
refresh_compare[0] = 1;
}else refresh_compare[0] = 0;
}else refresh_compare[0] = 0;
if(!(drive_fast[1] == 0 && skipCounter != 0)){
uint16_t TIM2_actCounter = TIM_GetCounter(TIM2);
if((TIM2_actCounter > 2020 && drive_fast[0] == 1) || TIM2_actCounter > 16200){
TIM_Cmd(TIM2, DISABLE);
TIM_SetCounter(TIM2, 0xFFFF);
refresh_compare[1] = 1;
}else refresh_compare[1] = 0;
}else refresh_compare[1] = 0;
if(!(drive_fast[2] == 0 && skipCounter != 0)){
uint16_t TIM4_actCounter = TIM_GetCounter(TIM4);
if((TIM4_actCounter > 2020 && drive_fast[0] == 1) || TIM4_actCounter > 16200){
TIM_Cmd(TIM4, DISABLE);
TIM_SetCounter(TIM4, 0xFFFF);
refresh_compare[2] = 1;
}else refresh_compare[2] = 0;
}else refresh_compare[2] = 0;
// stretch the low time to the needed frequency
if(refresh_compare[0]){
if(PWM_type[0] < 2 || (PWM_type[0] == 2 && stretchCounter % 2) || (PWM_type[0] == 3 && stretchCounter == 7)) TIM_SetCompare1(TIM3, usePWMValues[0]);
else TIM_SetCompare1(TIM3, 0);
if(PWM_type[1] < 2 || (PWM_type[1] == 2 && stretchCounter % 2) || (PWM_type[1] == 3 && stretchCounter == 7)) TIM_SetCompare2(TIM3, usePWMValues[1]);
else TIM_SetCompare2(TIM3, 0);
if(PWM_type[2] < 2 || (PWM_type[2] == 2 && stretchCounter % 2) || (PWM_type[2] == 3 && stretchCounter == 7)) TIM_SetCompare3(TIM3, usePWMValues[2]);
else TIM_SetCompare3(TIM3, 0);
if(PWM_type[3] < 2 || (PWM_type[3] == 2 && stretchCounter % 2) || (PWM_type[3] == 3 && stretchCounter == 7)) TIM_SetCompare4(TIM3, usePWMValues[3]);
else TIM_SetCompare4(TIM3, 0);
}
if(refresh_compare[1]){
if(PWM_type[4] < 2 || (PWM_type[4] == 2 && stretchCounter % 2) || (PWM_type[4] == 3 && stretchCounter == 7)) TIM_SetCompare1(TIM2, usePWMValues[4]);
else TIM_SetCompare1(TIM2, 0);
if(PWM_type[5] < 2 || (PWM_type[5] == 2 && stretchCounter % 2) || (PWM_type[5] == 3 && stretchCounter == 7)) TIM_SetCompare2(TIM2, usePWMValues[5]);
else TIM_SetCompare2(TIM2, 0);
}
if(refresh_compare[2]){
if(PWM_type[6] < 2 || (PWM_type[6] == 2 && stretchCounter % 2) || (PWM_type[6] == 3 && stretchCounter == 7)) TIM_SetCompare3(TIM4, usePWMValues[6]);
else TIM_SetCompare3(TIM4, 0);
if(PWM_type[7] < 2 || (PWM_type[7] == 2 && stretchCounter % 2) || (PWM_type[7] == 3 && stretchCounter == 7)) TIM_SetCompare4(TIM4, usePWMValues[7]);
else TIM_SetCompare4(TIM4, 0);
}
// re enable the timers
TIM_Cmd(TIM3, ENABLE);
TIM_Cmd(TIM2, ENABLE);
TIM_Cmd(TIM4, ENABLE);
if(++skipCounter == 2){
skipCounter = 0;
if(++stretchCounter == 8) stretchCounter = 0;
}
}
Plüschi wrote:Starting a pwm pulse after a calculation loop with variable execution times gives me shivers. Is that what this one-shot thing does?
Instead lets use the rock stable and easy adjustable 16bit pwm timer to start the loop calculation. Each timer overrun sets a flag to start main loop calculations. Synced pwm and mainloop, stable, simple, good
Ok, 328 and 32u4 tarduinos with 8bit / 10bit timers cant do it ....
Edit:
I have tested it on a tarduino 2560. Checking the TIFR3 register TOV3 flag to sync the main loop. Doesent even need an interrupt. Simple & works. Now i am a STM32 noob, what would be the simple way to check and reset one of the pwm generating timers overflow flag?
hinkel wrote:crazyal wrote:Simply because it didn't work as well as hoped. I never really got the default pids tuned right and timecop didn't like the float pid factors, because they don't blend in nicely with the 8-bit defaults. If you like playing around with beta stuff, give it a shot and we might find some values that work "magically"
Thanks for the answer, it was just mysterious for me, I have not tried this PidBaseflight, but I play with the mwii and Alex.k Pidcontroller from Harakiri and they are fine. So I have some stupid idea to let running both and mix the result with a tuneable coef factor for exemple :
60% mwiipid and 40%Pidrewrite(Alex.k) .
But i am not programmer and it is certainly not a good Idea because i dont know if it is possible to do it so, also you need to tune both PID controller with differents values separately and there is no garantie of better result . Eventually someone is more about to do this or to say that is stupid idea ?
Code: Select all
MwiiTimescale = FLOATcycleTime * 3.3333333e-4f;
dT = FLOATcycleTime * 0.000001f;
RCfactor = dT / (MainDptCut + dT); // used for pt1 element
prop = (float)min(max(abs(rcCommand[PITCH]), abs(rcCommand[ROLL])), 500);
for (axis = 0; axis < 3; axis++)
{
if (axis == YAW) // We use mwii 2.3 YAW for both pid controllers
{
tmp0 = (int16_t)(((int32_t)rcCommand[axis] * (2 * (int32_t)cfg.yawRate + 30)) >> 5);
error = (float)tmp0 - gyroData[axis];
if (abs(tmp0) > 50)
{
ITerm = 0.0f;
errorGyroI[axis] = 0.0f;
}
else
{
errorGyroI[axis] += (error * (float)cfg.I8[axis] * MwiiTimescale) * 0.001f;
errorGyroI[axis] = constrain(errorGyroI[axis], -268370.0f, 268370.0f);
ITerm = (float)constrain(errorGyroI[axis] * 0.1221f , -250.0f, 250.0f);
}
PTerm = (error * (float)cfg.P8[axis]) * 0.015625f;
if(NumberOfMotors > 3) // Constrain YAW by D value if not servo driven in that case servolimits apply
{
tmp0flt = 300.0f;
if(cfg.D8[axis]) tmp0flt -= (float)cfg.D8[axis];
PTerm = constrain(PTerm, -tmp0flt, +tmp0flt);
}
axisPID[axis] = PTerm + ITerm;
}
else
{
rcCommandAxis = (float)rcCommand[axis]; // Calculate common values for pid controllers
if ((f.ANGLE_MODE || f.HORIZON_MODE))
{
error = constrain(2.0f * rcCommandAxis + GPS_angle[axis], -500.0f, +500.0f) - angle[axis] + cfg.angleTrim[axis];
}
switch (cfg.mainpidctrl)
{
case 0:
if (f.ANGLE_MODE || f.HORIZON_MODE)
{
PTermACC = error * (float)cfg.P8[PIDLEVEL] * 0.007813f;
tmp0flt = (float)cfg.D8[PIDLEVEL] * 5.0f;
PTermACC = constrain(PTermACC, -tmp0flt, +tmp0flt);
errorAngleI[axis] += error * MwiiTimescale * 0.01f;
errorAngleI[axis] = constrain(errorAngleI[axis], -100.0f, +100.0f);
ITermACC = (errorAngleI[axis] * (float)cfg.I8[PIDLEVEL]) * 0.002441f; // Scaled down by 10
}
if (!f.ANGLE_MODE)
{
error = (rcCommandAxis * 64.0f / (float)cfg.P8[axis]) - gyroData[axis];
errorGyroI[axis] += error * MwiiTimescale * 0.01f;
errorGyroI[axis] = constrain(errorGyroI[axis], -160.0f, +160.0f);
if (abs((int16_t)gyroData[axis]) > 640) errorGyroI[axis] = 0.0f;
ITermGYRO = (errorGyroI[axis] * (float)cfg.I8[axis]) * 0.012207f;
PTermGYRO = rcCommandAxis;
if (f.HORIZON_MODE)
{
tmp0flt = 500.0f - prop;
PTerm = (PTermACC * tmp0flt + PTermGYRO * prop) * 0.002;
ITerm = (ITermACC * tmp0flt + ITermGYRO * prop) * 0.002;
}
else
{
PTerm = PTermGYRO;
ITerm = ITermGYRO;
}
}
else
{
PTerm = PTermACC;
ITerm = ITermACC;
}
PTerm -= (gyroData[axis] * dynP8[axis] * 0.0125f);
delta = (gyroData[axis] - lastGyro[axis]) / MwiiTimescale;
lastGyro[axis] = gyroData[axis];
lastDTerm[axis] += RCfactor * (delta - lastDTerm[axis]);
axisPID[axis] = PTerm + ITerm - (lastDTerm[axis] * dynD8[axis] * 0.09375f);
break;
// Alternative Controller by alex.khoroshko http://www.multiwii.com/forum/viewtopic.php?f=8&t=3671&start=30#p37465
// But a little modified...
case 1: // 1 = New mwii controller (float pimped + pt1element)
if (!f.ANGLE_MODE) // control is GYRO based (ACRO and HORIZON - direct sticks control is applied to rate PID
{
tmp0flt = (float)(((int32_t)(cfg.rollPitchRate + 27) * (int32_t)rcCommand[axis]) >> 4);
if (f.HORIZON_MODE) tmp0flt += ((float)cfg.I8[PIDLEVEL] * error) * 0.039063f;
}
else tmp0flt = ((float)cfg.P8[PIDLEVEL] * error) * 0.022321f;
tmp0flt -= gyroData[axis];
PTerm = (float)cfg.P8[axis] * tmp0flt * 0.007813f;
errorGyroI[axis] += (float)cfg.I8[axis] * tmp0flt * dT * 4.883f;
errorGyroI[axis] = constrain(errorGyroI[axis], -20972.0f, 20972.0f);
ITerm = errorGyroI[axis] * 0.01221f;
delta = ((tmp0flt - lastGyro[axis]) * 0.01638f) / dT;
lastGyro[axis] = tmp0flt;
lastDTerm[axis] += RCfactor * (delta - lastDTerm[axis]);
axisPID[axis] = PTerm + ITerm + (((float)cfg.D8[axis] * lastDTerm[axis]) * 0.023438f); // D scaled up by 2
break;
} // End of Switch
}
axisPID[axis] = (float)((int32_t)(axisPID[axis] + 0.5f)); // Round up result.
}