MrShoor
> Неужели так сложно было догадаться что я имел ввиду
В переписке принципом KISS злоупотреблять вообще противопоказано. В остальном я конечно согласен, что можно было и qsort. Но не нужно.
Ghost2
> Тут проблема в том, что с делением всегда получается некая зона
> нечувствительности по скорости
на маленьких скоростях у меня все идеально было- если мы прошли за эти 10мс 0 тиков, значит 0 импульсов, если 1 тик - 1 импульс, ничего и делить не надо. А вот на больших мелкие задержки между перенастройкой таймера стали важны.
Давай поговорим про трансмиссию Нивы. У нее все скорости кроме четвертой идут через 4 цилиндрических редуктора и 1 угловой. Это ж трындец. Можно же сделать чтоб все скорости шли через 2 цилиндрических редуктора, сделав основную кпп и раздатку не 3вальными а 2вальными. Кисс же? И процентов 5 наверное к кпд прибавится. Расход уменьшится
А нифига. Просто 3вальная коробка уже была готовая у шохи. А 2вальную это с нуля делать же. Вот тебе и кисс
1 frag / 2 deaths
Тут война со здравым смыслом, очевидно. Плюс, принцип KISS на производстве обретает совершенно иные грани.
Ghost2
> if (next_limit > max_limit)
Занижает точность скорости и дробной позиции без хорошей на то причины.
Если уж надо более общий вариант, то тогда так:
uint64_t position_target_scaled = 0; uint32_t position_current = 0; uint32_t last_time = 0; while (true) { uint32_t position_target = position_target_scaled >> 32; int32_t pos_delta = ( int32_t)( position_target - position_current); /* Limit to at most one step to keep a high frequency for velocity integration */ if ( pos_delta > 0) { send_step_forward( ); position_current += 1; } else if ( pos_delta < 0) { send_step_back( ); position_current -= 1; } uint32_t new_time = get_current_time( ); /* Assumes 32-bit precision for the clock, use a shorter type or a bitwise-and if it's lower */ uint32_t time_delta = new_time - last_time; position_target_scaled += ( uint64_t)get_scaled_vel( ) * time_delta; last_time = new_time; }
Имбирная Ведьмочка
> Занижает точность скорости и дробной позиции
Ниче она не занижает. Просто скорость у тебя в человеческих попугаях начинает измеряться, скажем, от 0 до 900. А не от нуля до нескольких сотен тысяч.
> без хорошей на то причины
Тебе виднее конечно.
ЗЫ. Ну, ежели ты радиотелескопом управлять намерен, то там конечно диапазон приращения скорости очень важен.
Имбирная Ведьмочка
> if (pos_delta > 0)
А вот такое вообще не работает.
Ghost2
> Просто скорость у тебя в человеческих попугаях начинает измеряться, скажем, от
> 0 до 900. А не от нуля до нескольких сотен тысяч.
Значит точность будет не 0.00001 от максимального значения, а только 0.001, в 100 раз хуже. Если максимум это 100 радиан в секунду — то это точность в 0.001 против 0.1 1/с.
Ghost2
> А вот такое вообще не работает.
Сфига ли? Опять недочитал?
Имбирная Ведьмочка
Точность определяется датчиком положения. Если у тебя датчик выдает 5 минут без учёта шума, то и скорость тебе нужно задавать с соответствующим разрешением.
> Сфига ли? Опять недочитал?
С того, что знаю. Шумы датчика будут постоянно дрочить двигатель, если ты в сдвиг на 32 не заложил некое понимание его работы.
Ghost2
> С того, что знаю. Шумы датчика будут постоянно дрочить двигатель, если ты в
> сдвиг на 32 не заложил некое понимание его работы.
Меняешь условия на ходу? В прошлом решении ты ни о каких шумах не вспоминал.
Но так уж и быть, держи регулятор с люфтом:
uint64_t position_target_scaled = 0; uint64_t position_target_scaled_filtered = 0; uint32_t position_current = 0; constexpr int64_t backlash = 1 << 31; /* half the motor's step */ uint32_t last_time = 0; while (true) { uint32_t position_target = position_target_scaled_filtered >> 32; int32_t pos_delta = ( int32_t)( position_target - position_current); /* Limit to at most one step to keep a high frequency for velocity integration */ if ( pos_delta > 0) { send_step_forward( ); position_current += 1; } else if ( pos_delta < 0) { send_step_back( ); position_current -= 1; } uint32_t new_time = get_current_time( ); /* Assumes 32-bit precision for the clock, use a shorter type or a bitwise-and if it's lower */ uint32_t time_delta = new_time - last_time; position_target_scaled += ( uint64_t)get_scaled_vel( ) * time_delta; last_time = new_time; int64_t position_filter_delta = position_target_scaled - position_target_scaled_filtered; if ( position_filter_delta > backlash) { position_target_scaled_filtered = position_target_scaled - backlash; } else if ( position_filter_delta < -backlash) { position_target_scaled_filtered = position_target_scaled + backlash; } }
Имбирная Ведьмочка
> Меняешь условия на ходу? В прошлом решении ты ни о каких шумах не вспоминал
Я и про регулятор не вспоминал, если чего. Точнее он в исходной задаче упоминался, но без подробностей его работы - выдает скорость, ну и ладно.
> Но так уж и быть, держи регулятор с люфтом
Простейший квадратичный регулятор с мертвой зоной делается примерно так:
static inline s32 dead_zone(s32 err, s32 min_err) { if( err > min_err) { return err - min_err; } if( err < -min_err) { return err + min_err; } return 0; } // k0, k1 - LQR coefficients, Qx.13 // vp - LQR current state // err = (target_pos - current_pos) s32 lqr_t::update( s32 err, s32 max_v) { err = dead_zone( err, min_err); if( err) { s32 uk = ( ( k0 * err) - ( k1 * vp)) / 8192; vp = clamp( vp + uk, -max_v, max_v); } else { vp = 0; } return vp; }
Еще приращение скорости надо ограничивать, чтобы при скачках ошибки (когда точка установки резко изменяется) она не улетала из нуля сразу в +/-max_v. А вот после ограничения ускорения эту скорость уже можно отправлять в код из #290.
Тема в архиве.