Проект MotorControlDemo для микроконтроллеров серии 1921ВК01
Модераторы: ea, dav, bkolbov, Alis, pip, _sva_
-
- Сообщения: 107
- Зарегистрирован: 15 фев 2017, 19:07
Re: Проект MotorControlDemo для микроконтроллеров серии 1921ВК01
Настраиваю регуляторы тока согласно описанию на ПО (п. 6.1.2.).
Заданный ток удержания 1А.
Хотя параметры ПИД-регулятора и влияют на результат, но при всех
настройках осциллограммы токов фаз В и С имеют форму как на картинке: В чём может быть проблема?
Заданный ток удержания 1А.
Хотя параметры ПИД-регулятора и влияют на результат, но при всех
настройках осциллограммы токов фаз В и С имеют форму как на картинке: В чём может быть проблема?
- Лашкевич
- Сообщения: 373
- Зарегистрирован: 13 май 2015, 13:10
- Предприятие: ООО "НПФ Вектор"
- Откуда: Москва
- Контактная информация:
Re: Проект MotorControlDemo для микроконтроллеров серии 1921ВК01
Да, есть такой эффект, связан, насколько я помню, с влиянием мёртвого времени при попытке приложить околонулевое напряжение вдоль одной из осей. Попробуйте сменить тип ШИМ на другой. Также попробуйте поменять частоту ШИМ - попробуйте 10кГц, 15кГц, посмотрите как влияет.
-
- Сообщения: 107
- Зарегистрирован: 15 фев 2017, 19:07
Re: Проект MotorControlDemo для микроконтроллеров серии 1921ВК01
В структуре TDrvParams базовая скорость хранится в явном виде в формате int16.
Рассчитанная скорость получается в формате int32 (_iq). Эта скорость в относительных единицах?
Если да, то где производится обратный пересчёт из относительной скорости?
Объясните смысл констант в строке в файле V_DPR_eCAP.c
и в строке
Рассчитанная скорость получается в формате int32 (_iq). Эта скорость в относительных единицах?
Если да, то где производится обратный пересчёт из относительной скорости?
Объясните смысл констант в строке в файле V_DPR_eCAP.c
Код: Выделить всё
p->TsNom = ((CORE_CLK / (drv_params.speed_nom * drv_params.p)) * 15*2);
Код: Выделить всё
p->TsNomMilsec = (60.0*1000 / (6*drv_params.speed_nom * drv_params.p));
-
- Сообщения: 107
- Зарегистрирован: 15 фев 2017, 19:07
Re: Проект MotorControlDemo для микроконтроллеров серии 1921ВК01
И ещё вопрос о запуске управления по двум каналам.
Как поступить?
Фактически код управления помимо дополнительных настроек портов должен быть продублирован.
А как поступать со словарём объектов в целевой программе и в UniCon-е.
Как поступить?
Фактически код управления помимо дополнительных настроек портов должен быть продублирован.
А как поступать со словарём объектов в целевой программе и в UniCon-е.
- Лашкевич
- Сообщения: 373
- Зарегистрирован: 13 май 2015, 13:10
- Предприятие: ООО "НПФ Вектор"
- Откуда: Москва
- Контактная информация:
Re: Проект MotorControlDemo для микроконтроллеров серии 1921ВК01
Да, в проекте всё в относительных единицах.petrovitch писал(а): ↑22 окт 2020, 23:14 В структуре TDrvParams базовая скорость хранится в явном виде в формате int16.
Рассчитанная скорость получается в формате int32 (_iq). Эта скорость в относительных единицах?
Обратный пересчёт из относительной скорости внутри программы не производится нигде, а для пользователя пересчёт производит программа UniCON, пользуясь выведенной в словарь объектов базовой скоростью (масштабирующий коэффициент 14, co2_vars.co_scaleNum14 = drv_params.speed_nom;).
Предпосчитанная константа TsNom нужна для быстрого расчёта частоты вращения в функции SpeedCalc. Она показывает количество тактов микроконтроллера между двумя фронтами одного канала датчика холла при номинальной скорости
Здесь speed_nom в об/мин, например, 3000, p число пар полюсов.
1/(speed_nom/60*p) даст время одного периода датчика холла, а так как скорость рассчитывается два раза на периоде (между каждыми двумя фронтами), то константа в два раза меньше (умножение на 30 вместо 60). CORE_CLK переводит время в процессорные такты
Про TsNomMilsec есть комментарий в коде, коэффициент для пересчета времени между метками в мс в скорость в об/мин. 60 - об/мин, 1000 мс в секунде, 6 меток на эл. оборот. Нужен тоже для экономии процессорного времени, но вместо процессорных тактов показывает количество миллисекунд одного электрического периода.
Интересует одновременно два работающих модуля ДПР Холла? Так как модуль сильно завязан на использование конкретных регистров периферии, то проще всего просто скопировать и сделать второй модуль под другим именем (типа V_DPR_eCAP1.c), там переназначить ножки и модули CAP, сделать ещё три перывания в файле main.c, пройти поиском по проекту на DPReCAP и везде аналогично повторить всё для DPReCAP1. Затем в программе CoodEdit скопировать весь целиком индекс с параметрами про DPReCAP на свободное место (из индекса 5155 в 5156, например), заменить в скопированном имена переменных с DPReCAP на DPReCAP1. Также можно для второго датчика сделать отдельную группу параметров в перичеслении 15, чтобы не путаться, и выставить эту группу новому индексу параметров 5156. Тогда после перепрошивки и обновления словаря и экспорта базы текстов из CoodEdit в UniCon всё появится в юниконе. Рекомендуется пройти лабораторную работу "Добавление параметра CANopen в программе COODEdit" из руководства Описание структуры ПО MotorControlDemo_v23.pdf.
-
- Сообщения: 107
- Зарегистрирован: 15 фев 2017, 19:07
Re: Проект MotorControlDemo для микроконтроллеров серии 1921ВК01
Спасибо за такой развёрнутый ответ.
Но по второму вопросу интересовал запуск двух двигателей с одного кристалла.
Но по второму вопросу интересовал запуск двух двигателей с одного кристалла.
- Лашкевич
- Сообщения: 373
- Зарегистрирован: 13 май 2015, 13:10
- Предприятие: ООО "НПФ Вектор"
- Откуда: Москва
- Контактная информация:
Re: Проект MotorControlDemo для микроконтроллеров серии 1921ВК01
Ну тогда надо мой ответ про модуль датчика положения расширить на все модули ПО, касающиеся управления двигателями.petrovitch писал(а): ↑23 окт 2020, 15:49 Но по второму вопросу интересовал запуск двух двигателей с одного кристалла.
Re: Проект MotorControlDemo для микроконтроллеров серии 1921ВК01
Здравствуйте!
Отлаживаясь на моделях, заметил проблему у себя: при моделировании СДПМ с количеством полюсов >1. виртуальный двигатель не выходит на рабочие обороты, будто слишком большой коэф.противоЭДС.
Начал копать по формулам и понял, что либо я что-то не понимаю, либо есть ошибка.
К сожалению, у меня пока нет платы с 1921, я отлаживаюсь на stm32f4, а для телеметрии, осциллографирования, настройки и прошивки использую свой "велосипед".
Однако, общая архитектура аналогична Вашей. Контур управления, регуляторы у меня аналогичны Вашим, а модель и обработчик энкодера используются непосредственно Ваши с минимальной адаптацией.
Берем первый мотор СДПМ из набора параметров. Видимо это Leadshine ACM601V36-T-2500. ЗПТ - 36В, амплитуды напряжений в модель доходят, весь контур векторного управления отлично замыкается, ток по оси d = 0, по оси q реагирует на момент. Но недобор скорости как раз раза в 4....
Я конечно могу подогнать действительное под желаемое, но хочется разобраться...
Возьмем куски кода:
Инит:
Тело:
Собственно говоря, при инициализации
А далее главный вопрос...
Не ясен механизм учёта количества пар полюсов. Т.к. все расчёты до вычисления электромагнитного момента производятся основываясь на частоту вращения вала p->motorInternals.omega (НЕ электрическую) и потокосцепление p->motorInternals.m, которое вроде тоже является суммой для всех пар полюсов.
Но если это суммарное потокосцепление и частота вращения вала, то тогда почему в расчёте момента учитывается кол-во пар полюсов? Буд-то это потокосцепления для одной пары полюсов до этого вычислялись...
У меня всё встало на свои места после того как в ините уменьшил присваеваемое потокосцепление от магнитов в кол-во пар полюсов раз и принял что расчёт идет для одной пары.
Типа так:
Хотя это кажется не верным, т.к. в расчётах продолжает использоваться частота вращения вала "s->Internals.omega"...
Почему мы, используя электрический угол для преобразований
,используем механическую частоту вращения при расчёте предикторов и изменений потокосцеплений?
К сожалению описанные в файле "Описание имитационных моделей электродвигателей v8.pdf" модели не соответствуют буквально тем, которые реализованы в коде c переходом в d-q и расчетом предикторов.
Так же отдельный вопрос по самому двигателю ACM601V36. Как был получен psi_pm = 0.162056937? Как Вы связывали его с паспортными параметрами Се = 3.03 V/RPM и Cm = 0.0866 Hm/A.
Т.к. у меня этого двигателя в живую нет, то не совсем ясно, что такое в понимании производителя 3.03 V/RPM, если обычно Сm численно равен Сe(В/(рад/сек)), а тут связь какая-то странная. И если по Сm я логику вижу, то Сe какой-то странный....
Отлаживаясь на моделях, заметил проблему у себя: при моделировании СДПМ с количеством полюсов >1. виртуальный двигатель не выходит на рабочие обороты, будто слишком большой коэф.противоЭДС.
Начал копать по формулам и понял, что либо я что-то не понимаю, либо есть ошибка.
К сожалению, у меня пока нет платы с 1921, я отлаживаюсь на stm32f4, а для телеметрии, осциллографирования, настройки и прошивки использую свой "велосипед".
Однако, общая архитектура аналогична Вашей. Контур управления, регуляторы у меня аналогичны Вашим, а модель и обработчик энкодера используются непосредственно Ваши с минимальной адаптацией.
Берем первый мотор СДПМ из набора параметров. Видимо это Leadshine ACM601V36-T-2500. ЗПТ - 36В, амплитуды напряжений в модель доходят, весь контур векторного управления отлично замыкается, ток по оси d = 0, по оси q реагирует на момент. Но недобор скорости как раз раза в 4....
Я конечно могу подогнать действительное под желаемое, но хочется разобраться...
Код: Выделить всё
Tsm_param SMDATA[] = {\
// |r_f |l_f |l_m |If |psi_pm |r_s |l_sd |l_sq |pp |j |qep |Power |Speed |Current
{0, 0, 0, 0, 0.162056937, 0.38, 0.91, 0.91, 4, 0.00001032, 2500, 0.1, 3000, 4},\
Инит:
Код: Выделить всё
if (MotorParametersValid){
p->motorInternals.r_f = SMDATA[p->MotorParametersNum-1].r_f; //сопротивление ОВ
p->motorInternals.l_f = SMDATA[p->MotorParametersNum-1].l_f; //индуктивность ОВ
p->motorInternals.l_m = SMDATA[p->MotorParametersNum-1].l_m; //коэффициент магнитного потока (взаимная индуктивность)
p->motorInternals.rs = SMDATA[p->MotorParametersNum-1].r_s; //сопротивление статора
p->motorInternals.lsd = SMDATA[p->MotorParametersNum-1].l_sd; //индуктивность статора
p->motorInternals.lsq = SMDATA[p->MotorParametersNum-1].l_sq; //индуктивность статора
p->motorInternals.pp = SMDATA[p->MotorParametersNum-1].pp; //число пар полюсов
p->motorInternals.j = SMDATA[p->MotorParametersNum-1].j; //момент инерции
p->motorInternals.QEPResolution = SMDATA[p->MotorParametersNum-1].qep; //разрешение энкодера
p->motorInternals.m = SMDATA[p->MotorParametersNum-1].psi_pm; //потокосцепление ротора равно потоку постоянных магнитов
p->motorInternals.RatedPower = SMDATA[p->MotorParametersNum-1].RatedPower; //номинальная мощность (справочная величина, не используется в расчетах)
p->motorInternals.RatedSpeed = SMDATA[p->MotorParametersNum-1].RatedSpeed; //номинальная скорость (справочная величина, не используется в расчетах)
p->motorInternals.RatedCurrent = SMDATA[p->MotorParametersNum-1].RatedCurrent; //номинальный действующий ток
p->motorInternals.RatedFluxCurrent = SMDATA[p->MotorParametersNum-1].RatedFluxCurrent; //номинальный ток ОВ
p->motorInternals.MechLoss = p->motorInternals.j * 10; //механические потери
}
Код: Выделить всё
// Если с постоянными магнитами, то поток ротора присвоился еще в ините и не меняется
// Расчет синуса и косинуса угла ротора
p->motorInternals.cosTetaR = _IQtoF(_IQcos(_IQ(p->motorInternals.tetaR)));//синус и косинус считаются с фиксированной точкой, т.к. флоатовские занимают тысячи тактов (видимо, какая-то медленная реализация, не использующая аппаратную поддержку).
p->motorInternals.sinTetaR = _IQtoF(_IQsin(_IQ(p->motorInternals.tetaR)));//если удастся найти быстрый плавающий синус и косинус, то их можно считать во флоате
// Поворот напряжений из осей альфа.бета в оси d,q
p->motorInternals.usd = p->motorInternals.usa * p->motorInternals.cosTetaR + p->motorInternals.usb * p->motorInternals.sinTetaR;
p->motorInternals.usq = -p->motorInternals.usa * p->motorInternals.sinTetaR + p->motorInternals.usb * p->motorInternals.cosTetaR;
// Расчет изменений потокосцеплений (предикторы)
p->motorInternals.dpsd = (p->motorInternals.usd - p->motorInternals.isd * p->motorInternals.rs + p->motorInternals.psq * p->motorInternals.omega);
p->motorInternals.dpsq = (p->motorInternals.usq - p->motorInternals.isq * p->motorInternals.rs - p->motorInternals.psd * p->motorInternals.omega);
// Расчет предикторов потокосцеплений
p->motorInternals.ppsd = p->motorInternals.psd + p->motorInternals.dpsd * p->motorInternals.t;
p->motorInternals.ppsq = p->motorInternals.psq + p->motorInternals.dpsq * p->motorInternals.t;
// Расчет токов для предикторного уравнения
p->motorInternals.isd = (p->motorInternals.ppsd - p->motorInternals.m) * p->motorInternals._1_lsd;
p->motorInternals.isq = p->motorInternals.ppsq * p->motorInternals._1_lsq;
// Расчет изменений потокосцеплений по Рунге-Кутта второго порядка
p->motorInternals.psd = p->motorInternals.psd + p->motorInternals.t2 * (p->motorInternals.dpsd + (p->motorInternals.usd - p->motorInternals.isd * p->motorInternals.rs + p->motorInternals.psq * p->motorInternals.omega));
p->motorInternals.psq = p->motorInternals.psq + p->motorInternals.t2 * (p->motorInternals.dpsq + (p->motorInternals.usq - p->motorInternals.isq * p->motorInternals.rs - p->motorInternals.psd * p->motorInternals.omega));
//если инвертор выключен и все токи пересекли ноль (колеблются около нуля, расфорсировка прошла)
//то выключаем расчет токов статора, чтобы не дергались (читерство, иначе сложный расчет будет)
if ((p->InvertorEna == 0) && (p->motorInternals.CurrentInvertedFlag == 7)) {
p->motorInternals.psd = p->motorInternals.m;
p->motorInternals.psq = 0;
}
// Расчет токов после уточнения изменения потокосцеплений
p->motorInternals.isd = (p->motorInternals.psd - p->motorInternals.m) * p->motorInternals._1_lsd;
p->motorInternals.isq = p->motorInternals.psq * p->motorInternals._1_lsq;
//поворот токов в оси альфа,бета (для вывода на АЦП)
p->motorInternals.isa = p->motorInternals.isd * p->motorInternals.cosTetaR - p->motorInternals.isq * p->motorInternals.sinTetaR;
p->motorInternals.isb = +p->motorInternals.isd * p->motorInternals.sinTetaR + p->motorInternals.isq * p->motorInternals.cosTetaR;
// Расчет момента
p->motorInternals.torque = 3.0 / 2.0 * p->motorInternals.pp * (p->motorInternals.psd * p->motorInternals.isq - p->motorInternals.psq * p->motorInternals.isd);
Собственно говоря, при инициализации
Код: Выделить всё
p->motorInternals.m = SMDATA[p->MotorParametersNum-1].psi_pm; //потокосцепление ротора равно потоку постоянных магнитов
Не ясен механизм учёта количества пар полюсов. Т.к. все расчёты до вычисления электромагнитного момента производятся основываясь на частоту вращения вала p->motorInternals.omega (НЕ электрическую) и потокосцепление p->motorInternals.m, которое вроде тоже является суммой для всех пар полюсов.
Но если это суммарное потокосцепление и частота вращения вала, то тогда почему в расчёте момента учитывается кол-во пар полюсов?
Код: Выделить всё
p->motorInternals.torque = 3.0 / 2.0 * p->motorInternals.pp * (p->motorInternals.psd * p->motorInternals.isq - p->motorInternals.psq * p->motorInternals.isd);
У меня всё встало на свои места после того как в ините уменьшил присваеваемое потокосцепление от магнитов в кол-во пар полюсов раз и принял что расчёт идет для одной пары.
Типа так:
Код: Выделить всё
s->Internals.pp = SMDATA[s->MotorParametersNum-1].pp;
s->Internals.m = SMDATA[s->MotorParametersNum-1].psi_pm/s->Internals.pp;
Почему мы, используя электрический угол для преобразований
Код: Выделить всё
p->motorInternals.cosTetaR = _IQtoF(_IQcos(_IQ(p->motorInternals.tetaR)));//синус и косинус считаются с фиксированной точкой, т.к. флоатовские занимают тысячи тактов (видимо, какая-то медленная реализация, не использующая аппаратную поддержку).
p->motorInternals.sinTetaR = _IQtoF(_IQsin(_IQ(p->motorInternals.tetaR)));//если удастся найти быстрый плавающий синус и косинус, то их можно считать во флоате
К сожалению описанные в файле "Описание имитационных моделей электродвигателей v8.pdf" модели не соответствуют буквально тем, которые реализованы в коде c переходом в d-q и расчетом предикторов.
Так же отдельный вопрос по самому двигателю ACM601V36. Как был получен psi_pm = 0.162056937? Как Вы связывали его с паспортными параметрами Се = 3.03 V/RPM и Cm = 0.0866 Hm/A.
Т.к. у меня этого двигателя в живую нет, то не совсем ясно, что такое в понимании производителя 3.03 V/RPM, если обычно Сm численно равен Сe(В/(рад/сек)), а тут связь какая-то странная. И если по Сm я логику вижу, то Сe какой-то странный....
- Disona
- Сообщения: 81
- Зарегистрирован: 06 дек 2016, 11:18
- Предприятие: НПФ Вектор
- Откуда: Москва
- Контактная информация:
Re: Проект MotorControlDemo для микроконтроллеров серии 1921ВК01
Добрый день.
На мой взгляд ошибка действительно закралась в расчёты потокосцеплений двигателей.
Вот здесь:
и вот здесь:
следует домножить скорость "motorInternals.omega" на количество пар полюсов, чтобы получилось соответственно так:
и так:
А потокосцепление постоянных магнитов нужно вернуть на место.
Можете попробовать и рассказать о результатах?
На вопрос про величины Ce/Cm я пока ответить не могу, возможно коллеги позже ответят.
На мой взгляд ошибка действительно закралась в расчёты потокосцеплений двигателей.
Вот здесь:
Код: Выделить всё
// Расчет изменений потокосцеплений (предикторы)
p->motorInternals.dpsd = (p->motorInternals.usd - p->motorInternals.isd * p->motorInternals.rs + p->motorInternals.psq * p->motorInternals.omega);
p->motorInternals.dpsq = (p->motorInternals.usq - p->motorInternals.isq * p->motorInternals.rs - p->motorInternals.psd * p->motorInternals.omega);
Код: Выделить всё
// Расчет изменений потокосцеплений по Рунге-Кутта второго порядка
p->motorInternals.psd = p->motorInternals.psd + p->motorInternals.t2 * (p->motorInternals.dpsd + (p->motorInternals.usd - p->motorInternals.isd * p->motorInternals.rs + p->motorInternals.psq * p->motorInternals.omega));
p->motorInternals.psq = p->motorInternals.psq + p->motorInternals.t2 * (p->motorInternals.dpsq + (p->motorInternals.usq - p->motorInternals.isq * p->motorInternals.rs - p->motorInternals.psd * p->motorInternals.omega));
Код: Выделить всё
p->motorInternals.dpsd = (p->motorInternals.usd - p->motorInternals.isd * p->motorInternals.rs + p->motorInternals.psq * p->motorInternals.omega * p->motorInternals.pp);
p->motorInternals.dpsq = (p->motorInternals.usq - p->motorInternals.isq * p->motorInternals.rs - p->motorInternals.psd * p->motorInternals.omega * p->motorInternals.pp);
Код: Выделить всё
p->motorInternals.psd = p->motorInternals.psd + p->motorInternals.t2 * (p->motorInternals.dpsd + (p->motorInternals.usd - p->motorInternals.isd * p->motorInternals.rs + p->motorInternals.psq * p->motorInternals.omega * p->motorInternals.pp));
p->motorInternals.psq = p->motorInternals.psq + p->motorInternals.t2 * (p->motorInternals.dpsq + (p->motorInternals.usq - p->motorInternals.isq * p->motorInternals.rs - p->motorInternals.psd * p->motorInternals.omega * p->motorInternals.pp));
Можете попробовать и рассказать о результатах?
На вопрос про величины Ce/Cm я пока ответить не могу, возможно коллеги позже ответят.
С уважением, Дмитрий Шпак
ООО "НПФ Вектор"
ООО "НПФ Вектор"
Re: Проект MotorControlDemo для микроконтроллеров серии 1921ВК01
Попробовал... Результат предсказуем. Домножение скоростей на частоту хх не влияет никак, влияет на момент по всё видимости, с ним надо отдельно разбираться. Подозрение, что всё же потокосцепление от магнитов надо делить на количество пар полюсов + скорости домножить..... После обеда проанализирую коэф. момента двигателя при разных комбинациях "деления" и "умножения".