Факультативная часть Главы 3

Механическое сопротивления вращению колёс

Внимательный читатель мог заметить локальную переменную, которая в исходном тексте драйвера управления моторами декларирована, но не используется:

int _motor_speed_minimum = 0;

Она нужна для учёта механических сопротивлений, которые возникают в приводах. Сначала немного поговорим о физической сути этого сопротивления.

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

На уроках физики Вам рассказывали о взаимодействии электрического тока и магнитного поля и показывали опыты, на которых проводник с током, помещённый в магнитное поле начинает двигаться. Это означает, что на него начинает действовать сила. В конструкции электродвигателя эта сила заставляет вращаться ротор.

К оси ротора механически подсоединён редуктор, уменьшающий скорость вращения.  А на оси редуктора находится колесо.

Робот стоит на колёсах и всем своим весом прижимает их к полу. Если колесо начинает вращаться, то между ним и полом возникает сила трения, которая толкает колесо, а с ним и робота вперёд или назад в зависимости от того, куда колесо закручено мотором. Колесо как бы отталкивается от пола, двигая робот. В этом случае сила трения колеса об пол – наш помощник, так как помогает двигать робот.

Но в механической системе – обмотка ротора двигателя + шестерёнки редуктора + колесо, прижатое к полу, действуют и другие силы трения, которые препятствуют вращению. Двигатель должен их преодолевать, чтобы робот, стоящий на полу мог двигаться.

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

С точки зрения программиста и его программы сила тока – это значения чисел, которые мы передаём в драйвер –

void DRIVER_Motor_Shield_Control (int _left_power,  int _right_power)

В принципе эти числа могут быть любыми в диапазоне от минус бесконечности до плюс бесконечности. Но наш драйвер устроен так, чтобы отсекать все отрицательные числа и числа, модуль которых больше чем _motor_speed_maximum. Таким образом, драйвер защищает моторы от перегрева и разрушения.

А что произойдёт, если числа будут маленькими?

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

Например DRIVER_Motor_Shield_Control (1, 1);

Откомпилируйте текст и загрузите программу. Скорее всего, колёса останутся неподвижными.

Почему? Ведь мы же дали в моторы ток!

Да, электрический ток мы дали, но он маленький. Сила его взаимодействия с магнитным полем статора слаба и не может преодолеть силы трения в шестерёнках редуктора. Кстати, в подшипниках самого двигателя тоже есть небольшая сила трения.

Попробуйте последовательно увеличивать числа, передаваемые в драйвер и заметить, при каких значениях колёса начнут вращаться. Это и будет то минимальное число, которое надо подать в драйвер при вызове, если мы хотим, чтобы колёса вращались. Не забывайте каждый раз перекомпилироваить программу и загружать её в робота.

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

Вопрос к Вам – почему минимальные числа могут быть разными для разных колёс?

Но это ещё не всё. Если Вы подадите в моторы это минимальное число, включите питание и поставьте робот на пол, то, скорее всего, он не поедет. Робот своим весом придавит колесо к полу, реакция колеса добавит трения в подшипниках и сопротивление вращению увеличится. То есть минимальное число надо увеличить.

Сделайте несколько попыток, постепенно увеличивая числа, подаваемые в драйвер. При каком-то числе робот начнёт медленно двигаться. Это и будет Ваше значение локальной переменной _motor_speed_minimum.

Правда, лучше его увеличить на 3-7%. Мы пишем универсальную программу, применимую ко всем роботам. А сила сопротивления вращению штука очень индивидуальная и немного меняется от экземпляра к экземпляру. Так что лучше заложить небольшой запас по мощности.

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

Учёт сопротивления вращению колёс

Постановка задачи. Наш новый драйвер должен делать следующее –

  1. Если модуль полученной мощности мотора превышает _motor_speed_maximum, то в мотор надо подать _motor_speed_maximum.
  2. Если модуль полученной мощности равен нулю, то в мотор надо подать ноль.
  3. Если модуль полученной мощности больше нуля и меньше _motor_speed_minimum, то в мотор надо подать _motor_speed_minimum.
  4. Если модуль полученной мощности больше _motor_speed_minimum и меньше _motor_speed_maximum, то в мотор надо подать именно эту мощность.

График учёта сопротивления вращению колёс

На рисунке выше отображено то, что сказано в пунктах 1-4. Стрелка и жирная точка на графике сообщают нам, что для входного сигнала, равного нулю у нас есть особое значение выходного сигнала – ноль.

Алгоритм драйвера управления моторами с учетом механического сопротивления
Алгоритм драйвера управления моторами с учетом механического сопротивления

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

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

Возможно, Вы уже знаете про встроенную функцию constrain. Если нет, самое время о ней поговорить. Эта функция берёт значение заданной Вами переменной и сравнивает её с заданными Вами ограничениями.

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

То есть мы можем записать в нашей программе следующую строчку –

_left_power_modul = constrain (_left_power_modul, _motor_speed_minimum, _motor_speed_maximum);

После отработки этой строчки в переменной _left_power_modul окажется –

  • _motor_speed_minimum, если до вызова функции переменная _left_power_modul была меньше, чем _motor_speed_minimum
  • _motor_speed_maximum, если до вызова функции переменная _left_power_modul была больше, чем _motor_speed_maximum
  • _left_power_modul, если до вызова функции переменная _left_power_modul находилась в промежутке между _motor_speed_minimum и _motor_speed_maximum

Эта операция делается и для левого и для правого моторов.

После этого необходимо проверить, равны ли входные параметры нашего драйвера нулю.

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

Исходный текст

Вот почти и всё. Осталось написать сам исходный текст драйвера, и руководство пользователя. Исходный текст для сравнения с Вашим есть в Ардуино файле –

Programm_modul_3_Motor_Shield_zero_power.ino

Руководство пользователя

ОПИСАНИЕ

DRIVER_Motor_Shield_Control_zero_power (int _left_power,  int _right_power)

Производит загрузку четырёх портов вывода платы Arduino UNO сигналами, обеспечивающими вращение колёс робота через плату управления MotorShield в соответствии с электрической разводкой этой платы. Задействуются следующие контакты платы ARDUINO UNO – 4, 5, 6 и 7. Использование этих контактов для других устройств запрещено.

СИНТАКСИС

DRIVER_Motor_Shield_Control_zero_power (value_1, value_2);   – где value_1 и value_2 это целые числа со знаком, обозначающие направление и скорость вращения колёс робота. Знак плюс соответствует движению вперёд, знак минус – назад, value_1 это скорость вращения левого колеса, value_2 – правого.

При превышении модуля value_1 или value_2 максимально возможного числа = 250, в моторы подаётся 250. Если модуль меньше 250, то в моторы подаётся модуль полученного числа.

Немного об отладке нового драйвера управления моторами. В принципе процедура такая же, как и для драйвера DRIVER_Motor_Shield_Control (int _left power, int _right_power).

Но есть небольшие добавления:

  • Необходимо убедится, что при подаче в какой-либо мотор нуля, он будет неподвижен.
  • Необходимо убедиться, что при подаче любого числа большего нуля, но меньшего _motor_speed_minimum, мотор будет крутиться со скоростью _motor_speed_minimum.

Вы уже догадались, как это сделать.

Так же как это делалось при наладке первого драйвера в основном тексте этой главы.

И ещё одно замечание. Если Вы подбирали _motor_speed_minimum на ровном твёрдом полу, то на мягкой поверхности (например, на ковре или траве) робот, скорее всего не поедет. Это потому, что сопротивление движению у жёсткого пола меньше всего.

Так что нам придётся смириться с тем, что наши роботы могут двигаться только по ровному жёсткому полу.  Для ковров, травы или земли надо менять конструкцию транспортной тележки – увеличивать диаметр колеса, ставить более мощные моторы и основную батарею.

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

Теперь действительно всё про драйвер управления моторами для платы MotorShield или её функциональных аналогов.

Драйвер, для ShieldBot

Следует отметить, что всё написанное ниже пока ещё не проверялось авторами “вживую”. Информация взята из источников в Интернете и дополнена в соответствии с нашими собственными представлениями.

Поэтому если Вы решите использовать ShieldBot, то рассматривайте нижеприведённый текст как теоретическое описание, которое необходимо проверить на практике.

Распределение портов ShieldBot отличается от распределения, принятого в роботах, построенных в нашем кружке на основе платы MotorShield.

Отличия следующие:

  • Аналоговые порты А0-А5 подключены к шести датчикам линии. Нам эти порты потребуются для подключения датчиков расстояния. К счастью на плате ShieldBot есть микропереключатели, которые позволяют отключить датчики линии и освободить порты А0-А5 для других дел.
  • Для управления моторами необходимо использовать шесть цифровых портов (5, 6, 7, 8, 9 и 10), а не четыре как в MotorShield (4, 5, 6, 7 и 8). Почему так сделано – точно не знаем. Возможно потому, что на плате ShieldBot рядом с моторами находятся светодиоды, показывающие своим свечением актуальное направление вращения моторов. И два порта задействованы для управления ими. При первоначальной настройке этих портов необходимо все шесть настроить на ВЫВОД.
    • Порт 6 задаёт скорость вращения Правого мотора. На него необходимо подавать широтно-модулированный сигнал командой analogWrite (address, value). Так же как и в случае MotorShield. Ограничения на значения value такие же.
    • Порт 9 – тоже, что и порт 6, но для Левого мотора.
    • Порты 5 и 7 определяют направление вращения Правого мотора.
      • Вперёд – digitalWrite (5, HIGH) и digitalWrite (7, LOW)
      • Назад – digitalWrite (5, LOW) и digitalWrite (7, HIGH)
    • Порты 8 и 10 определяют направление вращения Правого мотора.
      • Вперёд – digitalWrite (8, HIGH) и digitalWrite (9, LOW)
      • Назад – digitalWrite (8, LOW) и digitalWrite (9, HIGH)

Исходный текст драйвера void DRIVER_Motors_ShieldBot (int _left, int _right) – это попытка авторов написать драйвер управления моторами для ShiedBot.

Но необходимо отметить, что настоящего робота на базе ShieldBot у нас не было, поэтому реальную настройку и отладку этого драйвера мы пока не делали.

В случае, если Вы используете плату ShieldBot вместо MotorShield нужно заменить драйвер

void DRIVER_Motor_Shield_Control (int _left_power,  int _right_power)

на драйвер  void DRIVER_Motors_ShieldBot (int _left, int _right) в тексте программы.

Только надо иметь в виду, что:

  • Драйвер void DRIVER_Motors_ShieldBot (int _left, int _right) использует другие контакты портов платы Arduino UNO.
  • Так же как DRIVER_Motor_Shield_Control_zero_power (int _left_power, int _right_power) уже имеет встроенное ограничение учитывающее трение в редукторах.

Постановка задачи

То же, что и для драйвера DRIVER_Motor_Shield_Control_zero_power (int _left_power,  int _right_power)

Алгоритм

То же, что и для драйвера DRIVER_Motor_Shield_Control_zero_power (int _left_power,  int _right_power)

Исходный текст

В этом тексте уже учтены ограничения мощности с обеих сторон (сверху – 250 и снизу – 40)

//*********************************************************

void DRIVER_Motors_ShieldBot (int _left_power, int _right_power)

{

// Декларирование и назначение портов вывода

int Port_POWER_LEFT_MOTOR = 9;// Порт мощности на левый двигатель

int Port_POWER_RIGHT_MOTOR = 6;// Порт мощности на правый двигатель

int Port_DIRECTION_1_LEFT_MOTOR = 8;// Порт направления вращения левого_1

int Port_DIRECTION_2_LEFT_MOTOR = 10;// Порт направления вращения левого¬_2

int Port_DIRECTION_1_RIGHT_MOTOR = 5;// Порт направления вращения правого_1

int Port_DIRECTION_2_RIGHT_MOTOR = 7;// Порт направления вращения правого_2

 

// Декларирование и первоначальное назначение внутренних переменных управления двигателем

int  _left_direction_1 = HIGH;// направление вращения левого двигателя вперёд

int  _left_direction_2 =LOW ;//

int  _right_direction_1 = HIGH;// направление вращения правого двигателя вперёд

int  _right_direction_2 = LOW;//

int  _left_power_modul = 0;// мощность в левый двигатель

int  _right_power_modul = 0;// мощность в правый двигатель

 

// Декларирование и назначение ограничителей

int _motor_speed_minimum = 40;

int _motor_speed_maximum = 250;

 

// НАЧАЛО ИСПОЛНЯЕМЫХ ОПЕРАТОРОВ

 

// Настройка режимов портов вывода

  pinMode (Port_POWER_LEFT_MOTOR, OUTPUT); 

  pinMode (Port_POWER_RIGHT_MOTOR, OUTPUT);

  pinMode (Port_DIRECTION_1_LEFT_MOTOR, OUTPUT); 

  pinMode (Port_DIRECTION_2_LEFT_MOTOR, OUTPUT); 

  pinMode (Port_DIRECTION_1_RIGHT_MOTOR, OUTPUT);

 pinMode (Port_DIRECTION_2_RIGHT_MOTOR, OUTPUT);   

 

// Вычисление модулей int _left_power,  int _right_power

if (_left_power < 0) {_left_power_modul =  0 - _left_power;}  else {_left_power_modul =  _left_power;}

if (_right_power < 0) {_right_power_modul =  0 - _right_power;}  else {_right_power_modul =  _right_power;}

 

// Вычисление направления вращения двигателей

if (_left_power >= 0) {_left_direction_1 = HIGH; _left_direction_2 = LOW;}

else {_left_direction_1 = LOW; _left_direction_2 = HIGH;}

if (_right_power >= 0) { _right_direction_1 = HIGH; _right_direction_2 = LOW;}

else { _right_direction_1 = LOW; _right_direction_2 = HIGH;}

 

// Учёт ограничений на значение, подаваемое в моторы

_left_power_modul = constrain (_left_power_modul, _motor_speed_minimum,  _motor_speed_maximum);

_right_power_modul = constrain (_right_power_modul, _motor_speed_minimum,  _motor_speed_maximum);

 

analogWrite (Port_POWER_LEFT_MOTOR, _left_power_modul);

analogWrite (Port_POWER_RIGHT_MOTOR, _right_power_modul);

digitalWrite (Port_DIRECTION_1_LEFT_MOTOR, _left_direction_1);

digitalWrite (Port_DIRECTION_2_LEFT_MOTOR, _left_direction_2);

digitalWrite (Port_DIRECTION_1_RIGHT_MOTOR, _right_direction_1);

digitalWrite (Port_DIRECTION_2_RIGHT_MOTOR, _right_direction_2);

}

//*********************************************************

Руководство пользователя

ОПИСАНИЕ

При вызове драйвер void DRIVER_Motors_ShiedBot (int _left, int _right) производит загрузку шести портов вывода платы Arduino UNO сигналами, обеспечивающими вращение колёс робота через плату управления ShieldBot в соответствии с электрической разводкой этой платы. Задействуются следующие контакты платы Arduino UNO – 5, 6, 7, 8, 9 и 10. Использование этих контактов для других устройств запрещено.

СИНТАКСИС

DRIVER_Motors_ShiedBot (value_1, value_2);   – где value_1 и value_2 это целые числа со знаком, обозначающие направление и скорость вращения колёс робота. Знак плюс соответствует движению вперёд, знак минус – назад, value_1 это скорость вращения левого колеса, value_2 – правого. При превышении модуля value_1 или value_2 максимально возможного числа = 250, в моторы подаётся 250. Если модуль меньше 40, то в моторы подаётся 40. Если модуль полученного числа находится между 250 и 40, то в моторы подаётся модуль полученного числа.