Контроллер для кордовых электричек

VitalikV

А нам для гувернера, на сколько нужно считать обороты? Можно привязаться к каким либо другим параметрам, которые прямо или обратно пропорциональны оборотам? Например KV , известен, количество банок аккумулятора тоже. Напряжение на фазе при изменении нагрузки меняется, или всегда постоянно?

Что касается датчика холла расположенного среди других магнитов, внутри мотора, или рядом с ним, как то сомнительно. Надо датчик и магнит, по которому считаются обороты, выносить за пределы магнитного поля мотора… Или делать как на машине, на коленвалу, зубчатый шкив из магнитного сплава и по зубцам считать обороты

Маркс

напряжение меняется, но не сильно.
там не столько меняется напряжение, сколько амплитуда и частота


на этих графиках видно. желтые это фазовые сигналы при разных оборотах

надо еще подумать, если пойму откуда лишние импульсы на выходе ОУ,
может получится с ними побороться без программных изысков

VitalikV

Лишние импульсы, могут быть корректировкой. Например регулятор считает, что нужный магнит должен прилететь на следующий зуб через 0,2секунды, а он из-за нагрузки , или перегазовки , прилетает , через 0,4 секунды, и чтобы провернеуть мотор дальше, отправляет дополнительный импульс, который выпадает из алгоритма.

Такое может быть? Или у меня фантазия разыгралась уже?))))

VitalikV

Скетч от простейшего регулятора на Атмеге, может чем поможет …

// Управление бесколлекторным двигателем постоянного тока без датчиков на ATmega48 #include <avr/io.h> #include <avr/interrupt.h> #include <util/delay.h> #include <avr/wdt.h>

// Фаза U(Верхнее плечо) #define UH_ON TCCR2A |= (1 << COM2A1); #define UH_OFF TCCR2A &= ~(1 << COM2A1);

// Фаза U(Нижнее плечо) #define UL_ON PORTB |= (1 << PB5); #define UL_OFF PORTB &= ~(1 << PB5);

// Фаза V(Верхнее плечо) #define VH_ON TCCR1A |= (1 << COM1B1); #define VH_OFF TCCR1A &= ~(1 << COM1B1);

// Фаза V(Нижнее плечо) #define VL_ON PORTB |= (1 << PB4); #define VL_OFF PORTB &= ~(1 << PB4);

// Фаза W(Верхнее плечо) #define WH_ON TCCR1A |= (1 << COM1A1); #define WH_OFF TCCR1A &= ~(1 << COM1A1);

// Фаза W(Нижнее плечо) #define WL_ON PORTB |= (1 << PB0); #define WL_OFF PORTB &= ~(1 << PB0);

#define PHASE_ALL_OFF UH_OFF;UL_OFF;VH_OFF;VL_OFF;WH_OFF;WL_OFF;

#define SENSE_U ADMUX = 0; // Вход обратной ЭДС фазы U #define SENSE_V ADMUX = 1; // Вход обратной ЭДС фазы V #define SENSE_W ADMUX = 2; // Вход обратной ЭДС фазы W

#define SENSE_UVW (ACSR&(1 << ACO)) // Выход компаратора

#define START_PWM 50 // Минимальный ШИМ при запуске

unsigned char position, speed; volatile unsigned char commutation_step = 0; volatile unsigned char rotor_run = 0; // Счетчик импульсов обратной ЭДС

// Крутим по часовой стрелке void commutation(char startup) { switch (commutation_step) { case (0): if(!SENSE_UVW || startup) { UH_ON; // На фазе U - ШИМ WH_OFF; // Фаза W отключена SENSE_W; // Активируем вход фазы W commutation_step = 1; // Следующий шаг TCNT0 = 0; // Обнуляем счетчик T1 } break;

    case (1):
        if(SENSE_UVW || startup)
        {
            VL_OFF; // На фазе V - лог. 0
            WL_ON;  // На Фазе W - лог. 1
            SENSE_V; // Активируем вход фазы V
            commutation_step = 2;
            TCNT0 = 0; // Обнуляем счетчик T1
        }
        break;

    case (2):
        if(!SENSE_UVW || startup)
        {
            UH_OFF; // Фаза U отключена
            VH_ON;  // На фазе V - ШИМ
            SENSE_U; // Активируем вход фазы U
            commutation_step = 3;
            TCNT0 = 0; // Обнуляем счетчик T1
        }
        break;
 
    case (3):
        if(SENSE_UVW || startup)
        {
            UL_ON;  // На фазе U - лог. 1
            WL_OFF; // На Фаза W - лог. 0
            SENSE_W; // Активируем вход фазы W
            commutation_step = 4;
            TCNT0 = 0; // Обнуляем счетчик T1
        }
        break;

    case (4):
        if(!SENSE_UVW || startup)
        {
            VH_OFF;  // Фаза V отключена
            WH_ON;   // На фазе W - ШИМ
            SENSE_V; // Активируем вход фазы V
            commutation_step = 5;
            TCNT0 = 0; // Обнуляем счетчик T1
        }
        break;

    case (5):
        if(SENSE_UVW || startup)
        {
            UL_OFF; // На фазе U - лог. 0
            VL_ON;  // На Фазе V - лог. 1
            SENSE_U; // Активируем вход фазы U
            commutation_step = 0;
            TCNT0 = 0; // Обнуляем счетчик T1
        }
        break;
}

}

// Обработчик прерывания по компаратору. Детектор обратной ЭДС ISR(ANALOG_COMP_vect) { if(rotor_run == 200) commutation(0); rotor_run++; if(rotor_run > 200) { rotor_run = 200; wdt_reset(); } }

// Обработчик прерывания по переполнению Т0. Работа двигателя без сигналов обратной ЭДС ISR(TIMER0_OVF_vect) {
commutation(1); // Если сработало прерывание, есть пропуски импульсов обратной ЭДС rotor_run = 0; // Сбрасываем счетчик импульсов OCR1A = START_PWM; // ШИМ минимум OCR1B = START_PWM; OCR2A = START_PWM; }

int main( void ) { //Watchdog on wdt_enable(WDTO_1S);

// Порты ввода/вывода DDRB = 0xFF; // Порт B - выход PORTB = 0x00;

// T0 - для старта и работы двигателя без сигналов обратной ЭДС TCCR0A = 0; TCCR0B = 0; TCCR0B |= (1 << CS02)|(1 << CS00); // Предделитель на 1024 TIMSK0 |= (1 << TOIE0); // Разрешаем прерывание по переполнению T0

// T1 и T2 ШИМ TCCR1A |= (1 << WGM10); // Режим Fast PWM, 8-bit TCCR1B |= (1 << CS10)|(1 << WGM12); // Без предделителя

TCCR2A |= (1 << COM2A1)| // Сброс вывода OC2A при совпадении (1 << WGM21)|(1 << WGM20); // Режим Fast PWM TCCR2B |= (1 << CS20); // Без предделителя

PHASE_ALL_OFF; // Выключаем все фазы

ADCSRB |= (1 << ACME); // Отрицательный вход компаратора подключаем к выходу мультиплексора АЦП DIDR1 |= (1 << AIN0D);

sei(); // Глобально разрешаем прерывания

while(1) { cli(); position = ADMUX; // Сохраняем позицию ротора в буфер ADMUX = (1 << MUX1)|(1 << MUX0); // Вход ADC3
ADCSRA |= (1 << ADEN) | (1 << ADPS1)|(1 << ADPS0); // Разрешаем АЦП, предделитель на 8 ADCSRA |= (1 << ADSC); // Запускаем преобразование АЦП while(ADCSRA & (1 << ADSC)){}; // Ждем окончания преобразования speed = ADC/4; ADCSRA = 0; // Выключаем АЦП ADCSRB = 0; ADCSRB |= (1 << ACME); // Отрицательный вход компаратора подключаем к выходу мультиплексора АЦП ADMUX = position; sei();

if(speed > START_PWM) { ACSR |= (1 << ACIE); // Разрешаем прерывание от компаратора TIMSK0 |= (1 << TOIE0); // Разрешаем прерывание по переполнению T0

if(rotor_run == 200) { // Если импульсы обратной ЭДС присутствуют, крутим наполную OCR1A = speed; OCR1B = speed; // Изменяем ШИМ OCR2A = speed; } } else { PHASE_ALL_OFF; // Все фазы выключены ACSR &= ~(1 << ACIE); // Запрещаем прерывание от компаратора TIMSK0 &= ~(1 << TOIE0); // Запрещаем прерывание по переполнению T0 }

} }

Маркс

Это маловероятно,
я совсем забыл, что в моей схеме ОУ работает без обратной связи, в режиме насыщения,
с Ку (коэф. усиления) стремящемся к бесконечности (в идеале)
А некоторые ОУ в таком режиме, при стечении обстоятельств в виде совпадения “сигналов на входах”
могут кратковременно “переворачивать” (инвертировать) сигнал на выходе.

как варианты

  • забить и продолжить изыскания в области программной фильтрации ошибочных данных
  • взять другую модель ОУ, не факт что поможет, ЕМНИП в больше или меньшей степени этому подвержены все ОУ
  • добавить обратную связь, для уменьшения Ку, тогда придется сразу прикручивать и формирователь сигнала, потому как на выходе ОУ будет синусоида, что усложнит схему, но совсем не факт, что вылечит )

до весны еще далеко, а процесс на месте не стоит.
кучку деталек и кусок текстолита уже купил, так что новую плату сотворить не долго,
заодно дорисую место для установки модуля гироскопа

Маркс

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

и пронаблюдал траблу на осциллографе.

точно такая картинка наблюдается и на прототипе.
такие всплески с еще большей амплитудой проскакивают,
в том числе и на ниспадающем фронте и вызывают срабатывание прерывания.

на макетке купировать удалось, скорее всего не на 100 процентов,
но процентов 85 помех не пропустить на вход МК удалось,
а это значит, что количество ошибочных данных уменьшится на порядок.

Маркс

ну и вот, на выходе имеем первое приближение

Гувернер на базе Ардуино Нано.
Датчик оборотов пока собран на макетной плате.
Требуемые обороты в программе указываются в оборотах/минуту.

В программе установлено две полки оборотов, 2000 и 3000.
После старта гувернеру передается команда на установку оборотов 2000 об/минуту,
через пять секунд посылается новая команда - 3000 об/мин
и еще через пять секунд новая команда - 2000 об/минуту.
Все остальное делает программа.

2000 и 3000 проверял оптическим тахометром, все в пределах погрешности, заложенной в программе,
на данный момент это примерно 6 процентов, но что то мне подсказывает, что дельту можно убрать.

Сегодня поменяю конденсаторы на прототипе кросс платы и она должна заработать так же )

Собственно говоря, регулировка построена на изменении длительности сигнала PWM на входе регулятора,
на основании данных с датчика оборотов мотора, построенного на операционном усилителе.
Датчик фиксирует прохождение обмоток регулятора над магнитами.

Программа сравнивает текущие обороты мотора с требуемыми и в зависимости от результата сравнения
увеличивает или уменьшает длительность импульса сигнала PWM.

Маркс

в общем прототип тоже работает,
осталось причесать программу и можно встраивать в таймер

Маркс

рисую новую версию кросс-платы, появился вопрос.
может стоит на плате разместить кнопку управления и пару светодиод для индикации ?
пока на плате место есть

VitalikV

Пару диодов можно, а вот кнопку, которая со временем начнет звинеть, думаю не надо…

Маркс
VitalikV:

которая со временем начнет звинеть,

это маловероятное явление, звон возможен только в момент нажатия/отпускания,
кроме того, количество срабатываний на отказ у кнопок достаточно велико,
в том числе и у китайских.
у меня Уно уже лет десять работает, кнопку Reset топтал не меренное количество раз )

VitalikV

А зачем эта кнопка нужна на кросс плате? Есть штатная кнопка на ардуино. Так же кнопка нужна на корпусе модели, тем более если модель объемная и мотор под капотом.

И еще касательно прошивки, хорошо бы добавить возможность отключения кросс платы, отключения гироскопа, гувернера, акселерометра, чтобы можно было летать как в простом , так и в активном режиме, включая и отключая нужные датчики, по одному или все сразу.

VitalikV

Кстати на счет акселерометра, может имеет смысл, на кросс плате разместить место для него, вместо кнопки. Акселерометры периодически всплывают в продаже на али.

А вот гироскоп наверное имеет смысл размещать по центру тяжести модели. Хотя и не обязательно.

Маркс
VitalikV:

А зачем эта кнопка нужна на кросс плате? Есть штатная кнопка на ардуино.

штатная - RESET, от нее ни тепло ни холодно, да и закрыта она росс платой получается.
а нужна кнопка управления, старт-стоп ну и мало ли что еще.

VitalikV:

отключения гироскопа, гувернера

режим без GYRO и GOVER будет, как и без одного из них,
но предстоит разобраться с логикой

VitalikV:

Кстати на счет акселерометра

MPU6050 - это 3-х осевой гироскоп + 3-х осевой акселерометр

VitalikV:

А вот гироскоп наверное имеет смысл размещать по центру тяжести модели.

нет никакого смысла, его задача угол тангажа измерять не более того

VitalikV
Маркс:

MPU6050 - это 3-х осевой гироскоп + 3-х осевой акселерометр

Вот тогда было бы не плохо эти функции разделить, при необходимости.

Не факт, что гироскоп в полете заработает правильно… Ибо его еще надо правильно по осям установить. Или в программе пофиг , по какой оси меняется угол?

Маркс
VitalikV:

Или в программе пофиг , по какой оси меняется угол?

до гироскопа еще доберемся, в стоковой версии устройства он должен стоять по осям X/Y/Z.
изменение положения не предусматривалось

VitalikV

А теперь если он распаян на плате таймера, то будет проблема с расположением таймера строго по осям. Не всегда есть место, особенно если это конверсия модели из двс в электро. Поэтому гироскоп наверное лучше отдельно.

Или как то калибровку гироскопа делать…

Маркс

доберусь до гироскопа, буду думать, как вариант выбор при программировании расположения гироскопа.

Маркс

Плату нарисовал, завтра распечатаю, вытравлю и буду паять

Слева внизу SMD кнопка и SMD светодиод пусть будут, справа J3 и J4 место подключения MPU6050

Маркс

У меня есть только две платы Pro Mini
По порядку слева 8MHz 3.3V и вторая 16MHz 5V.

На третью можно внимания не обращать, это гироскоп.

Так вот косяк в том, что платы отличаются расположение контактов A4/A5,
а это выходы для подключения i2c в том числе и гироскопа.
Прототип сделан для установки как раз на первый тип Про Мини,
но 3.3V питания и 8 МГц это не то, что нужно.

Отсюда вопрос, под какой форм фактор Про Мини будем делать,
сразу скажу, платы будут очень сильно отличаться.