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

Drinker
Sir_Alex:

Я где то читал, что есть некоторые грабли у F103 процов с i2c шиной и эти грабли поправили в F4. Так что, как вариант сразу этот проц закладывать в новых проектах. Хотя кто то тут писал про свой проект построения своего софта и долгое отлавливания багов с i2c шиной, но поделится чем то полезным человек не захотел…

Нету у кортекса проблем с и2ц

igor_v_t
HikeR:

не, я имел ввиду то, что СС весь “погряз” в рилтайме. чтобы изменить частоту опроса датчиков нужно перелопатить все связанные таймауты, иначе вместо опроса плата будет слать только варнинги. насколько я помню, OpenPilot единственный открытый проект завязанные на RTOS, отсюда и трудности.

Ну в этом я пока не понимаю.
Я на Атмеге игрался с этим и понимаю так, что если повышение частоты опроса не уменьшает ошибку интегрирования не имеет смысла ее повышать частоту опроса гироскопа. То же с акселем. В MPU 6000 есть ФНЧ. И вполне может быть что повышение частоты эффекта просто не даст.
На MS5611 я эффект получил при повышении частоты до 100 Гц. Дальнейшее усреднение баро дает красивую картину. И смысла фильтровать с акселерометром нет.
При этом на плате МультиВии (SE) с Гудлака фильтрация баро с акселерометром эффекта не дала по причине медленного акселерометра.

SergDoc:

ну почему они каждому датчику собственную шину прикручивают?

А может люди не мучатся а суют два кристала в один корпус?

SergDoc

Я вобщем решил пока так - гибрид КК и СС пока останется как есть(через 2 недели будут новые движки -опробую), заказал LSM330DL сделаю что-то на подобии NAZE32…

rual
SergDoc:

почему они каждому датчику собственную шину прикручивают?

тут нет никакой проблемы, у меня одна шина, SCK, MISO, MOSI параллельно , CS и RDY индивидуально подключены. Чтение через ПДП, выбор кристала переключает диспетчер СПИ, он же выбирает обработчик данных (дус\аксель) по окончании ПДП.
Однозначно победить и2ц не смог, изредка вылетают ошибки.
код такой

/* ----------------- запрос обмена по I2C через перерывание -------------------------*/
void IMU_ReqI2C_Trans(uint8_t adr, uint8_t iadr, uint8_t cnt )
{
uint16_t time = micros();
IMU_I2C_ClrAllErr();
I2C_ClearFlag(I2C_IMU,I2C_FLAG_AF|I2C_FLAG_ARLO|I2C_FLAG_BERR);

/* ожидаем освобождения интерфейса */
while(I2C_GetFlagStatus(I2C_IMU, I2C_FLAG_BUSY)){
if (((micros()-time)&0xfff) > IMU_I2C_MAXTIM){
IMU_I2C_SetErr(LBSY);
return;
}
}
/* предварительная настройка переменных */
imu_i2c_dev_adr = adr;
imu_i2c_buf[0] = iadr;
imu_i2c_cnt = cnt;
imu_i2c_inx = 0;
I2C_AcknowledgeConfig(I2C_IMU, ENABLE);
/* передаем состояние START */
I2C_GenerateSTART(I2C_IMU, ENABLE);
}
/* обработчик прерывания по событиям и буферу и2ц ИНС
внутренний адрес размещаем в buf[0]*/
void I2C1_ISR(void)
{
switch(I2C_GetLastEvent(I2C_IMU)&(~I2C_FLAG_BTF))
{
case I2C_EVENT_MASTER_MODE_SELECT: /* EV5 */
if ((imu_i2c_inx == 0)/* передаём вынутренний адрес */
||(imu_i2c_dev_adr&0x01 == 0)) /* режим передачи */
I2C_Send7bitAddress(I2C_IMU,imu_i2c_dev_adr,I2C_Direction_Transmitter);
else /* запуск чтения после повторного старта */
I2C_Send7bitAddress(I2C_IMU,imu_i2c_dev_adr,I2C_Direction_Receiver);
break;
case I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED: /* EV6 */
case I2C_EVENT_MASTER_BYTE_TRANSMITTING: /* EV8 */
case I2C_EVENT_MASTER_BYTE_TRANSMITTED: /* EV8_2 */
if ((imu_i2c_inx == 1)&&(imu_i2c_dev_adr&0x01 != 0))
/* повторный старт для чтения */
I2C_GenerateSTART(I2C_IMU, ENABLE);
else { /* либо продолжаем писать */
if (imu_i2c_inx < imu_i2c_cnt+1)
/* передаём следующий байт */
I2C_SendData(I2C_IMU,imu_i2c_buf[imu_i2c_inx++]);
else /* передача буфера завершена */
I2C_GenerateSTOP(I2C_IMU, ENABLE);
}
break;

case I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED: /* EV6 */
case (uint32_t)(I2C_FLAG_BUSY|I2C_FLAG_MSL): /* состояние после сброса флага ADDR */
if (imu_i2c_cnt == 1) /* принимаем всего один байт */
I2C_AcknowledgeConfig(I2C_IMU, DISABLE);
break;

case I2C_EVENT_MASTER_BYTE_RECEIVED: /* EV7 */
if (imu_i2c_inx > imu_i2c_cnt) /* завершили чтение */
I2C_GenerateSTOP(I2C_IMU, ENABLE);
else {/* продолжаем чтение */
imu_i2c_buf[imu_i2c_inx++] = I2C_ReceiveData(I2C_IMU);
if (imu_i2c_inx == imu_i2c_cnt) /* будем принимать последний байт */
I2C_AcknowledgeConfig(I2C_IMU, DISABLE);
}
break;
default: /* не понятное состояние == ошибка интерфейса */
IMU_I2C_SetErr(IFERR);
I2C_GenerateSTOP(I2C_IMU, ENABLE);
I2C_SendData(I2C_IMU,I2C_GetLastEvent(I2C_IMU));
break;
}
/* проверим выход указателя за пределы буфера */
if (imu_i2c_inx > sizeof imu_i2c_buf)
{
imu_i2c_inx = sizeof imu_i2c_buf;
IMU_I2C_SetErr(OVBUF);
}

/* здесь вызов метода-заполнителя данных объекта ИНС */
switch(imu_i2c_dev_adr){
/* чтение магнитометра */
case MAG_I2C_DEV_ADR|0x01: MagmDataRdy(); break;
}
}
rual

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

/// это в загловочном файле макросы для фиксации ошибок и2с
typedef enum _IMU_ERR{
LBSY = 0, /* длительная занятость */
OVBUF, /* выход за пределы буфера */
IFERR, /* ошибка интерфейса */
ACKF /* нет ответа ведомого */
}IMU_ERR;
#define IMU_I2C_MAXTIM 250*8 /* макс. занятость интерфейса в микросек. */
#define IMU_I2C_SetErr(Err) {imu_i2c_err|= (1<<Err);}
#define IMU_I2C_ClrErr(Err) {imu_i2c_err&= ~(1<<Err);}
#define IMU_I2C_ClrAllErr() {imu_i2c_err = 0;}
#define IMU_I2C_GetErr() (imu_i2c_err)

typedef enum _IMU_ERR{
LBSY = 0, /* длительная занятость */
OVBUF, /* выход за пределы буфера */
IFERR, /* ошибка интерфейса */
ACKF /* нет ответа ведомого */
}IMU_ERR;
#define IMU_I2C_MAXTIM 250*8 /* макс. занятость интерфейса в микросек. */
#define IMU_I2C_SetErr(Err) {imu_i2c_err|= (1<<Err);}
#define IMU_I2C_ClrErr(Err) {imu_i2c_err&= ~(1<<Err);}
#define IMU_I2C_ClrAllErr() {imu_i2c_err = 0;}
#define IMU_I2C_GetErr() (imu_i2c_err)

/// инициализация и2ц
/* настойка и2ц ИНС */
RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1,ENABLE);
/* Configure I2C1 pins: PB6->SCL and PB7->SDA */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;
GPIO_Init(GPIOB, &GPIO_InitStructure);

I2C_DeInit(I2C_IMU);
I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;
I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_16_9;
I2C_InitStructure.I2C_OwnAddress1 = 1;
I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;
I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
I2C_InitStructure.I2C_ClockSpeed = 100000; /* 100kHz */
I2C_Cmd(I2C_IMU, ENABLE);
I2C_Init(I2C_IMU, &I2C_InitStructure);
/* настройка прерывания И2Ц ИНС */
NVIC_EnableIRQ(I2C1_ER_IRQn);
NVIC_EnableIRQ(I2C1_EV_IRQn);
NVIC_SetPriority(I2C1_EV_IRQn, 5);
/* разрешаем прерывание от и2ц */
I2C_ITConfig(I2C_IMU, I2C_IT_EVT|I2C_IT_BUF|I2C_IT_ERR, ENABLE);

всё это обращается к стандартным перефирийным библиотекам

RaJa
SergDoc:

STM32F103VET6, под него удобное IDE есть и ардупилот32 на нём легче организовать

Подскажите, Сергей, а что за IDE под него. У меня платка усть miniSTM32 STRIVE v2.1, там такой же проц, руки все до нее не доходят никак.

Dimm168pin:

я с орлом после sprint layout вообще не разобрался, в diptrace вроде понемногу освоился, смотрю что вроде такая же ерунда что и с мегами, кварц, пару емкостей и полетели)

А не поделитесь библиотеками компонентов для него? а то в нем даже элементарных вещей часто нет вроде светодиода SMD.

soliada
SergDoc:

Кто-нибудь под мультивий писал код под LSM330DL

Спросите Дмитрия, ник Омегапрайм,он таким датчиком давно пользуется.

rual
SergDoc:

У меня мама оттуда родом

если будете, в наших краях , ссобщите - пообщаемся

SergDoc:

Кто-нибудь под мультивий писал код под LSM330DL, нужен для портирования в NAZE32

я использую LSM330DL, правда у меня с ней глубоко аппаратный обмен, поэтому арду-подобные ИДЕ мне не идут. могу помочь с заголовочным файлом и данными инициализации.

/* умолчантельное заполнение настроечной структуры */
void Gyro::SetDefaultInitStruct(GYRO_CR* gyro_cr)
{
gyro_cr->CTRL_REG1_G = LSM330_G_DR400BW50
+ LSM330_G_PD
+ LSM330_Zen + LSM330_Yen + LSM330_Xen; /* Частота преобразования/ФНЧ1 400/50 Гц все оси вкл. */
gyro_cr->CTRL_REG2_G = LSM330_G_HPM0 + LSM330_G_HPC8; /* ФВЧ нижняя граница 0.1 Гц */
gyro_cr->CTRL_REG3_G = LSM330_G_I2_DRDY; /* вызвать прирывание по готовности данных на I2_DRDY */
gyro_cr->CTRL_REG4_G = LSM330_BDU /*+ LSM330_BLE*/ /* чтение блоком , первый мл.байт */
+ LSM330_G_FS2000; /* предел 2000 гр/с */
gyro_cr->CTRL_REG5_G = 0; /* буфер отключен, ФВЧ и ФНЧ2 отключены */
}
void Accel::SetDefaultInitStruct(ACC_CR* acc_cr)
{
acc_cr->CTRL_REG1_A = LSM330_A_ODR_50
+ LSM330_Zen + LSM330_Yen + LSM330_Xen; /* Частота преобразования 50 Гц все оси вкл.*/
acc_cr->CTRL_REG2_A = 0; /* ФВЧ отключен */
acc_cr->CTRL_REG3_A = LSM330_A_I1_DRDY1; /* прирывание по готовности данных */
acc_cr->CTRL_REG4_A = LSM330_BDU /*+ LSM330_A_HR*/ /* чтение блоком , первый мл.байт */
/*+ LSM330_BLE*/ + LSM330_A_FS16G; /* предел 16G */
acc_cr->CTRL_REG5_A = 0; /* буфер отключен, ФВЧ и ФНЧ2 отключены */
acc_cr->CTRL_REG6_A = 0; /* буфер отключен, ФВЧ и ФНЧ2 отключены */
}

LSM330def.rar

SergDoc

Небольшой предытог: Исправил некоторые кривости в платке псевдо NAZE32 буду изготавливать, сколько не крутил не вертел (три разбитых аппарата) всё равно свернул, хоть и на ARM, но к мультивию, мучения конечно мои ещё незакончены - надо ещё её запустить (детали ещё не отгрузили), дааа заимел хоть и не совсем но CopterControl (его ещё облетать надо, а новые моторы ещё в пути), надеюсь хоть в итоге видео полёта (и одной и днругой платки) будет 😃

SergDoc:

как пообещал знакомый программист не без исключения зачатков искуственного интеллекта (надеюсь)

А вот за это пусть сам программер (Аникейщик блин) и оправдывается 😁

SergDoc

Есть корпуса от НК401, думал туда программатор засунуть, а может сделать IMU и туда запихнуть?

8 days later
SergDoc

Даа ожидание страшная вещь (моторы застряли на таможне), есть некоторое предположение перебросит контроллер который псевдоCopterControl, на мультивий, точнее fy90q с прошивкой baseflight от Таймкопа, но нужна схема этой самой фишки, она в природе существует?

SergDoc

Ну вот собрал пепилац, трёшка - DT700, басики перепрошитые tgy прошивкой, ну и псевдоCopterControl, большОй (500мм радиус между центрами движков) аппарат получился, дома выше экрана поднять не решился, на экране ведёт себя хорошо, жду лётной погоды…

SergDoc

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

SergDoc

Сегодня баловался с коэффициентами гир, получил более менее приемлимые результаты, но появились осцилляции, теперь уже ПИДами баловаться надо, плохо ветер сильный и аппарат по прежнему тянет назад и вправо, скорей всего у меня ампула уровня приклеена кривовато и есть ощущение что текстолит слегка прогнулся на раме, ну это пока не существенно аппарат не переворачивается, но пока нужно держать на стике воюю дальше…

SergDoc

нахожу знакомые черты:) какой-то сборный прообраз CC, NAZE32 и всё на LSM330 -

www.youtube.com/watch?v=Eop6qx3kjeA

и самое обидное F405 который я так и не купил:(

у кого - нибудь есть инфа по этому делу?

Dimm168pin

вы свое то живое выкладывайте, и видео испытаний) интересно ж)