Skip to content

JV4K/STM32_Motor_control

Repository files navigation

STM32_Motor_control

Модуль для регулирования коллекторного двигателя с энкодером.

Возможности

  • Использование одного/двух/трех контуров управления (по положению, угловой скорости и току)
  • Регулирование как положения, так и угловой скорости (при наличии контура скорости)
  • Встроен алгоритм управления каналом таймера в режиме генерации ШИМ, а также выбором направления вращения мотора с помощью двух GPIO
  • Встроен опрос энкодера, расчет относительного положения и угловой скорости

Внимание: данные для контура тока необходимо вводить самостоятельно, т.е. вам нужно самим настроить АЦП или получение данных о токе из внешнего источника

Содержание

Установка

Распаковать архив _servocontrol.zip из релиза в папку проекта.

В файлах main.c и stm32...xx_it.c включить следующий файл:

/* USER CODE BEGIN Includes */
#include <servocontroller.h>
/* USER CODE END Includes */

Настройка проекта

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

1. Таймер в режиме энкодера, к каналам которого необходимо подключить энкодер.

Preview1


После этого в функцию int main() файла main.c нужно добавить следующее (пример для таймера TIM1):

/* USER CODE BEGIN 2 */
__HAL_TIM_CLEAR_IT(&htim1, TIM_IT_UPDATE);
HAL_TIM_Encoder_Start(&htim1, TIM_CHANNEL_ALL);
/* USER CODE END 2 */

Убедитесь, что вызываете эти методы перед бесконечным циклом while(1) - в указанном выше плейсхолдере для пользовательского кода


2. Канал другого таймера в режиме генерации ШИМ, к пину которого подключаем вывод PWM драйвера.

Частоту работы ШИМ необходимо выбирать исходя из характеристик драйвера. Например, если в характеристиках драйвера указано до 20 кГц, стоит установить 18 кГц (небольшой запас прочности). Частота от 18 кГц наиболее оптимальна, т.к. это за пределами порога слышимости большинства людей.

Preview1


После этого в функции int main() файла main.c нужно включить ШИМ на используемых каналах другого таймера (пример для TIM3):

/* USER CODE BEGIN 2 */
HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_1);
HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_2);
/* USER CODE END 2 */

Убедитесь, что вызываете эти методы перед бесконечным циклом while(1) - в указанном выше плейсхолдере для пользовательского кода


  1. Два GPIO в режиме output для управления направлением вращения мотора с помощью драйвера.

Объявление экземпляра структуры

Для каждого контролируемого привода необходимо объявить экземпляр типа servocontrol_t в файлах main.c:

/* USER CODE BEGIN PV */
servocontrol_t servo1;
/* USER CODE END PV */

и stm32...xx_it.c:

/* USER CODE BEGIN EV */
extern servocontrol_t servo1;
/* USER CODE END EV */

Инициализация

Теперь необходимо проинициализировать отдельные компоненты модуля необходимыми настройками.

Внимание: servocontrol_t *servo во всех функциях - указатель на экземпляр структуры, т.е. первым аргументом вы подаете: &yourServoName. Далее это объясняться не будет.

Спойлер: инициализация компонентов
void servo_baseInit(servocontrol_t *servo, enum loops servoLoops, float motorSpeed, float gearRatio,
		uint8_t reverse);
// servoLoops - количество используемых контуров управления
//   Single - регулирование по углу положения вала
//   Double - подчиненное регулирование по положению и угловой скорости
//   Triple - подчиненное регулирование по положению, угловой скорости и току (пропорционален моменту)


// motorSpeed - скорость привода до редуктора в РАД/С
// gearRatio - передаточное число редуктора. Например, если передаточное число 1:21.3, передайте 21.3.
// 	Если редуктора нет, или хотите регулировать до привод без учета редукции
//	(бывает полезно при большом влиянии вязкого трения редуктора на работу привода), передайте 1.
// reverse - определяет направление вращения, передайте 0 или 1


void servo_encoderInit(servocontrol_t *servo, TIM_HandleTypeDef *htim, uint16_t CPR);
// htim - указатель на обработчик таймера, например &htim1, если используется TIM1
// CPR - количество счетов таймера за один оборот мотора (если использованы два канала, CPR=(PPR*4)-1.
//		PPR можно узнать из характеристик энкодера.


void servo_driverInit(servocontrol_t *servo, TIM_HandleTypeDef *htim, uint8_t timerChannel,
		GPIO_TypeDef *dir1_Port, uint32_t dir1_Pin, GPIO_TypeDef *dir2_Port, uint32_t dir2_Pin,
		uint16_t minDuty, uint16_t maxDuty);
// htim - обработчик таймера, генерирующего ШИМ-сигнал.
// timerChannel - номер канала таймера, который контролирует скорость данного привода (числом: 1/2/3/4)
// Далее пины, управляющие направлением вращения привода через драйвер (с указанием портов)
// minDuty - минимальное значение шим, отличное от нуля, которое будет выдавать микроконтроллер (обычно 0)
// maxDuty - максимальное значение шим, которое будет выдавать микроконтроллер.
//		Рекомендую взять значение, равное ARR-1, где ARR - arr регистр таймера
//		Стоит уменьшить его на единицу, так как при полном заполнении есть риск перегрева мосфетов.
Спойлер: инициализация контуров управления
//------------------------ Следующие инициализаторы - настройки контуров управления ------------------------
//------------ Рекомендуется инициализировать только те контуры, которые будут использоваться --------------

// kp, ki, kd - коэффициенты ПИД регулятора контура
// dt - период работы каждого контура в секундах (очень важно соблюдать эту величину)
// kt - коэффициент алгоритма anti-windup. При отсутствии интегральной составляющей оставить 0

void servo_positionInit(servocontrol_t *servo, float kp, float ki, float kd, float dt, float kt);
void servo_velocityInit(servocontrol_t *servo, float kp, float ki, float kd, float dt, float kt);
void servo_currentInit(servocontrol_t *servo, float ratedCurrent, float kp, float ki, float kd, float dt,
		float kt);
// ratedCurrent - номинальный ток мотора в амперах

Опрос данных и расчет контуров регулирования

Для опроса данных с энкодера и расчёта необходимых для регулирования величин, в модуле предусмотрено 3 метода:

void servo_positionLoop(servocontrol_t *servo); // Контур положения
void servo_velocityLoop(servocontrol_t *servo); // Контур угловой скорости
void servo_currentLoop(servocontrol_t *servo, float currentFeedback); // Контур тока.
// currentFeedback - текущий ток (А)

Используйте только те контуры, которые вы указали в servo_baseInit.

Каждый из вышеперечисленных методов должен вызываться с определенной частотой. Ранее в методах servo_positionInit, servo_velocityInit и servo_currentInit вы указали период интегрирования dt для каждого контура. Величина, равная 1/dt - и есть частота, с которой должен вызываться метод расчета соответствующего контура. Т.е. если для контура положения был указан dt = 0.01, то метод servo_positionLoop должен вызываться с частотой 100 Гц.

Совет 1: Выбор частот

Выбор частоты опроса контуров

  • Ток: функция для расчёта регулятора тока в идеале должна вычисляться с частотой соответствующей обновлению задания для ШИМ силовых ключей. Чтобы для каждой новой коммутации ШИМ уже было рассчитано обновлённое значение на выходе регулятора тока. Но допускается кратно снижать частоту в несколько раз. Чем больше частота расчета контура тока - тем лучше, но необходимо учитывать вычислительные возможности процессора, АЦП и другие факторы. Обычно частоты для вызова регулятора тока - несколько килогерц.
  • Угловая скорость: - для контура скорости обычно достаточно частоты 50-200 Гц, но опять же, частота должна быть кратно меньше частоты обновления контура тока. При отстутствии контура тока, частота должна быть кратно меньше частоты ШИМ. Примечание: чем больше разрешение вашего энкодера, тем больше вы можете устанавливать частоту расчёта скорости.
  • Положение - контур положения стоит обновлять с той же частотой, что и контур скорости (при его наличии). При остутствии контура скорости, необходимо рассчитать частоту исходя из максимальной скорости вращения вала привода.
Совет 2: Возможная реализация

Способ вызова функций с необходимой частотой

Самый простой способ обеспечить кратность частот ШИМ и контуров - использовать прерывания по переполнению счетчика таймера, генерирующего ШИМ и программный счётчик. Данный метод не самый "элегантный", если есть достаточное число таймеров для всех контуров, то лучше настроить прерывания с их помощью (при этом наибольший приоритет прерываний должен быть у контура тока, а наименьший у контура положения). Но в случае нехватки таймеров, данный метод тоже сработает. Сначала включаем прерывания на таймере, который генерирует ШИМ-сигнал:

Preview1

В main.c в функции int main() не забываем запустить прерывания:

/* USER CODE BEGIN 2 */
HAL_TIM_Base_Start_IT(&htim3);
/* USER CODE END 2 */

Теперь в файле stm32..xx_it.c создаем целочисленную переменную-счетчик (для примера возьмем int counter) и находим обработчик прерываний (в случае TIM3 это void TIM3_IRQHandler(void)). В обработчик пишем конструкцию вида:

/* USER CODE BEGIN TIM3_IRQn 0 */
counter++;
if (counter >= 180) {
	servo_velocityLoop(&servo1);
	counter = 0;
}
/* USER CODE END TIM3_IRQn 0 */

Таким образом исходная частота была поделена на 180

Регулирование

На данный момент предусмотрено два вида регулирования - положения и скорости. Для этого существуют соответствующие методы:

void servo_controlPosition(servocontrol_t *servo, float setpoint); // setpoint - угол в радианах
void servo_controlVelocity(servocontrol_t *servo, float setpoint); // setpoint - скорость в рад/с

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

Прочий функционал

void servo_setPositionTolerance(servocontrol_t *servo, float tolerance);
// Устанавливает допустимую погрешность положения вала в радианах (+-tolerance)

int servo_getState(servocontrol_t *servo);
// Возвращает 0, если нет ошибки по положению, и 1, если ошибка не нулевая

int servo_getDirection(servocontrol_t *servo);
// Возвращает текущее направление вращения вала привода в формате -1/0/1 (0 - нет движения)
// Данные о направлении берутся с энкодера

Пример

В папке Servo_Controller_f103 находится пример использования модуля для управления двумя приводами jga25-371 (PPR = 12?, RPM=11500, Gear ratio = 1:21.3). На данный момент пример без контура тока (still in progress). Пример написан для микроконтроллера stm32f103c8t6 (отладочная плата bluepill)

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Packages

No packages published

Languages