Создание собственной системы стабилизации

oleg70
SergDoc:

сделать запуск петли по прерыванию готовности с гир

Огласите (если не секрет) какие общие мысли в этом плане по реализации…
Я тоже сейчас этим занят, пока нет стройной идеи как в реальном времени синхронизировать прерывания от гиры и акселя+маг, “тычу” осциллографом на ноги INT, меняю режимы… (думаю что задачка не из легких, но интересная)
Во всяком случае понятно почему особо ни кто это не делает-, нужно точно высчитывать время запроса/чтения и т.д.

SergDoc

ну вот петля:

currentTime = micros();
    if (mcfg.looptime == 0 || (int32_t)(currentTime - loopTime) >= 0) {
        loopTime = currentTime + mcfg.looptime;


        computeIMU();
        // Measure loop rate just afer reading the sensors
        currentTime = micros();
        cycleTime = (int32_t)(currentTime - previousTime);
        previousTime = currentTime;
#ifdef MPU6000_DMP
        mpu6000DmpLoop();
#endif


#ifdef MAG
        if (sensors(SENSOR_MAG)) {
            if (abs(rcCommand[YAW]) < 70 && f.MAG_MODE) {
                int16_t dif = heading - magHold;
                if (dif <= -180)
                    dif += 360;
                if (dif >= +180)
                    dif -= 360;
                if (f.SMALL_ANGLES_25)
                    rcCommand[YAW] -= dif * cfg.P8[PIDMAG] / 30;    // 18 deg
            } else
                magHold = heading;
        }
#endif


#ifdef BARO
        if (sensors(SENSOR_BARO)) {
            if (f.BARO_MODE) {
                static uint8_t isAltHoldChanged = 0;
                static int16_t AltHoldCorr = 0;
                if (cfg.alt_hold_fast_change) {
                    // rapid alt changes
                    if (abs(rcCommand[THROTTLE] - initialThrottleHold) > cfg.alt_hold_throttle_neutral) {
                        errorAltitudeI = 0;
                        isAltHoldChanged = 1;
                        rcCommand[THROTTLE] += (rcCommand[THROTTLE] > initialThrottleHold) ? -cfg.alt_hold_throttle_neutral : cfg.alt_hold_throttle_neutral;
                    } else {
                        if (isAltHoldChanged) {
                            AltHold = EstAlt;
                            isAltHoldChanged = 0;
                        }
                        rcCommand[THROTTLE] = initialThrottleHold + BaroPID;
                    }
                } else {
                    // slow alt changes for apfags
                    if (abs(rcCommand[THROTTLE] - initialThrottleHold) > cfg.alt_hold_throttle_neutral) {
                        // Slowly increase/decrease AltHold proportional to stick movement ( +100 throttle gives ~ +50 cm in 1 second with cycle time about 3-4ms)
                        AltHoldCorr += rcCommand[THROTTLE] - initialThrottleHold;
                        if (abs(AltHoldCorr) > 500) {
                            AltHold += AltHoldCorr / 500;
                            AltHoldCorr %= 500;
                        }
                        errorAltitudeI = 0;
                        isAltHoldChanged = 1;
                    } else if (isAltHoldChanged) {
                        AltHold = EstAlt;
                        isAltHoldChanged = 0;
                    }
                    rcCommand[THROTTLE] = initialThrottleHold + BaroPID;
                }
            }
        }
#endif


        if (sensors(SENSOR_GPS)) {
            if ((f.GPS_HOME_MODE || f.GPS_HOLD_MODE) && f.GPS_FIX_HOME) {
                float sin_yaw_y = sinf(heading * 0.0174532925f);
                float cos_yaw_x = cosf(heading * 0.0174532925f);
                if (cfg.nav_slew_rate) {
                    nav_rated[LON] += constrain(wrap_18000(nav[LON] - nav_rated[LON]), -cfg.nav_slew_rate, cfg.nav_slew_rate); // TODO check this on uint8
                    nav_rated[LAT] += constrain(wrap_18000(nav[LAT] - nav_rated[LAT]), -cfg.nav_slew_rate, cfg.nav_slew_rate);
                    GPS_angle[ROLL] = (nav_rated[LON] * cos_yaw_x - nav_rated[LAT] * sin_yaw_y) / 10;
                    GPS_angle[PITCH] = (nav_rated[LON] * sin_yaw_y + nav_rated[LAT] * cos_yaw_x) / 10;
                } else {
                    GPS_angle[ROLL] = (nav[LON] * cos_yaw_x - nav[LAT] * sin_yaw_y) / 10;
                    GPS_angle[PITCH] = (nav[LON] * sin_yaw_y + nav[LAT] * cos_yaw_x) / 10;
                }
            }
        }


       // PID - note this is function pointer set by setPIDController()
         pid_controller();


        mixTable();
        writeServos();
        writeMotors();
    }
}

в computeIMU(); за одно считываются данные с датчиков - это в imu.c
так вот вместо:

currentTime = micros();
    if (mcfg.looptime == 0 || (int32_t)(currentTime - loopTime) >= 0) {
        loopTime = currentTime + mcfg.looptime;

сделать запуск по прерыванию от гир, (это я так думаю) ну до этого ещё далеко ибо вожусь в 8-м таймером, не хочет запускаться…
в ардупилоте запуск цикла построен на прерывании от гир, если не ошибаюсь… да и у rual тоже…
но тут сразу поплывут фильтры, и PID надо добивать уже до времени цикла…

oleg70

Пока имею следующее: прерывания 250 (Гц) =0,004 (Сек) беру с DRDY LSM, при 72 Мгц на борту, в обработчике за половину периода (~0,002 сек.) успеваю три раза прочитать и усреднить гироскоп, прочитать 1 раз акс/маг, выполнить алгоритм ИМУ и даже можно ПИД впихнуть… Вроде все “красиво” и время на другие процессы остается но:
Не нравится - что нет проверки готовности гир при чтении (и похоже что косяки из за этого в данных вылазят)…
DMA к гире подцепил, но та же проблема: идут сбои… как проверить готовность?

SergDoc

готовность только по прерыванию, ибо если читать регистр готовности - пройдёт вечность…

oleg70
SergDoc:

вот петля:

Здесь везде привязка к currentTime = micros();, а мне хочется от нее избавиться

SergDoc:

готовность только по прерыванию

Вот здесь то и самое интересное… Например у LSM сигнал DRDY не зависит от установленного DATArate и всегда 250 Гц (?), а L3GD20 просто выставляет “1” на ноге когда можно прочитать данные и ждет пока их не прочитаешь (?)
Тут есть над чем поразмыслить…

rual
SergDoc:

чёт опять туплю, это ссылки на адреса памяти?

Да, там расположен уникальный номер проца. Для Ф4 надоть уточнить адрес.
Кста, это при работе УСБ активно используется при создании соединения. Разные дискавери у меня на разные виртуальные компорты садятся.

oleg70:

Например у LSM сигнал DRDY не зависит от установленного DATArate и всегда 250 Гц (?),

Нет, соответствует выставленной частоте отсчётов.

oleg70:

а L3GD20 просто выставляет “1” на ноге когда можно прочитать данные и ждет пока их не прочитаешь (?)

Да, после чтения снимает до очередной готовности (так все СТшные датчики работают и ХМЦ5883 тожа).

SergDoc
rual:

Да, там расположен уникальный номер проца. Для Ф4 надоть уточнить адрес.

я уже выковырял 😃 rcopen.com/forum/f134/topic224458/2240
на картинках что выше Unique devise ID в правом нижнем углу 😃

SergDoc

Может кто найдёт ошибку github.com/SergDoc/…/drv_pwm.c
восьмой таймер не запускается, первый такой-же, на нём у меня моторы - работает, а восьмой хоть застрелись…
тактирование таймеров и портов включено отдельно

  RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2 | RCC_APB1Periph_TIM3 | RCC_APB1Periph_TIM4 | RCC_APB1Periph_TIM5 | RCC_APB1Periph_I2C2 | RCC_APB1Periph_SPI2 | RCC_APB1Periph_USART2 | RCC_APB1Periph_USART3 , ENABLE);
    RCC_APB2PeriphClockCmd( RCC_APB2Periph_TIM1 | RCC_APB2Periph_TIM8 | RCC_APB2Periph_ADC1 | RCC_APB2Periph_USART1 | RCC_APB2Periph_SPI1, ENABLE);
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA | RCC_AHB1Periph_GPIOB | RCC_AHB1Periph_GPIOC | RCC_AHB1Periph_GPIOD | RCC_AHB1Periph_GPIOE | RCC_AHB1Periph_DMA2, ENABLE);
    RCC_ClearFlag();
SergDoc

затык у меня наверно здесь:

 setup = hardwareMaps[i];

    for (i = 0; i < MAX_PORTS; i++) {
        uint8_t port = setup[i] & 0x0F;
        uint8_t mask = setup[i] & 0xF0;

        if (setup[i] == 0xFF) // terminator
            break;

как этого избежать?

если так?

 setup = hardwareMaps[i];

    for (i = 0; i < MAX_PORTS; i++) {
        uint16_t port = setup[i] & 0x00FF;
        uint16_t mask = setup[i] & 0xFF00;

        if (setup[i] == 0xFFFF) // terminator
            break;

запустил все таймеры 😃

SergDoc

Сегодня поймал глюк приёмника, возможно по этой же причине у меня улетел аппарат в прошлом году, т.к. я заводил 8-й таймер, а он у меня предназначен для серв, естественно надо подключить было серву, а по причине того что питания развязаны и регуль не подключал, то самое простое что придумал, взял питание сервы с приёмника, и вот - АРМ кручу платку - серва крутится - хорошо, ага а дизарм то уже тю-тю - в каком положении стики оставил в том и показания остались - получается приёмник подвис из-за питания, т.к. я ещё и серву подцепил…

vatanuki
SergDoc:

приёмник подвис из-за питания

подскажите что за приемник? такой?

SergDoc

Да он самый… но тут получается, что питание от usb через обычный диод т.е. с подключенной сервой ~4.3В получилось, плате то моей не критично у меня всё на 3.3В, а вот приёмнику не понравилось…

oleg70
rual:

так все СТшные датчики работают

Не мог не поделиться…: Решил сделать компенсацию дрейфа “0” гиры от встроенного датчика температуры.
Так вот имеем: при нагреве (t+) “0” гиры смещается в минус и показания датчика температуры тоже (???) уменьшаются…
При комнатной температуре ~24 гр.с. датчик показывает “12” (??) и при нагреве феном уходит в минуса…
Вопрос: это какой то великий замысел или издевательство…(как компенсировать гиру?)

oleg70

Вот “матбаза”: Temperature sensor output change vs.temperature -1 °C/digit
Temperature data (1LSB/deg - 8-bit resolution). The value is expressed as two’s complement.
Пишу в коде: int8_t temper=(int8_t)data[…];
Где ошибка?

SergDoc

смотри как в mpu3050 сделано

static void mpu3050ReadTemp(int16_t *tempData)
{
    uint8_t buf[2];
    i2cRead(MPU3050_ADDRESS, MPU3050_TEMP_OUT, 2, buf);


    *tempData = 35 + ((int32_t)(buf[0] << 8 | buf[1]) + 13200) / 280;
}
oleg70
SergDoc:

char

не помогло… (то же самое)

SergDoc

буду дома покопаюсь может найду чего…