ARDUINO Джип с NRF24L01. Нужна помощь

Demka777

✩✩✩✩✩✩✩
2 Ноя 2021
20
8
Здравствуйте, прошу помощи.
Собирал машинку, сначала из фанеры и пробок от бутылок.
Все отлично работало, моторчики слабенькие, ездила, крутилась. Выглядела так себе:)
захотелось перенести управление в старый и не рабочий джип, заменил моторы, поставил сервопривод.
В проекте использую:
1.ардуино нано;
2.Драйвер TB6612fng;
3. Понижайка xl4015;
4. Серва mg995;
5. Два мотора 370 на 12-24в.

Столкнулся с проблемой, если питать от 12в ( три банки 18650) машинку, возникает обратка от моторов. Первые запуски машинки были без платы защиты BMS, если резко сменить направление движения, машинка начинает дергаться и крайняя банка 18650 разряжалась в 0, но даже с убитой банкой она все равно едет, только уже примерно на 8,4в, банку в итоге не смог реанимировать.
Если питать от двух банок 18650 (8,4в) и резко менять направление(для быстрого разворота например), то рывки все равно появляются, но аккумулятор остается жив.

Один раз умирал сам драйвер для моторов.
Нашел информацию, что в библиотеке Гайвера есть команда deadtime, мне она не помогла. Нужно как-то в коде придумать паузу между движением вперед и назад.

Так как сам программированием занимаюсь пару месяцев, идей рабочих нет. Прошу помочь.
Представляю это так, если машинка едет вперед и жму назад, моторы останавливаются на пол секунды например и только потом происходило бы движение. При движении назад, аналогично.
A01394B9-4A56-4EF4-A025-7D7F018B07C3.jpeg
6771E212-55B5-49F9-95C8-24FFCF4DF1FE.jpeg
D7922B7F-16F7-44CB-851C-536AC5D19D50.jpeg
F1E7D438-22AC-4CA3-9F3D-EFF691332406.jpeg
CD76A3EE-737B-4511-A670-E6264F45AA22.jpeg
ВИДЕО -
Видео1
Видео2
Код джипа с библиотекой Гайвера
Код с библиотекой Гайвера:
#include <SPI.h>
#include "nRF24L01.h"
#include "RF24.h"

#include <Servo.h>
#include "GyverMotor.h"
GMotor motorR(DRIVER3WIRE, 4, 2, 3); //мотор 1
GMotor motorL(DRIVER3WIRE, 7, 8, 6); //мотор 2

RF24 radio(9, 10); // "создать" модуль на пинах 9 и 10

int recieved_data[2]; // массив принятых данных

int valX; // данные с джойстика по оси X
int valY; // данный с джойстика по оси Y
int valZ; // данные с джойстика
int sig = A1; // свет


Servo servo;

byte address[][6] = {"1Node", "2Node", "3Node", "4Node", "5Node", "6Node"}; //возможные номера труб

void setup() {
  // Пины D5 и D6 - 7.8 кГц
  TCCR0B = 0b00000010;  // x8
  TCCR0A = 0b00000011;  // fast pwm
  // Пины D3 и D11 - 62.5 кГц
  TCCR2B = 0b00000001;  // x1
  TCCR2A = 0b00000011;  // fast pwm
  Serial.begin(9600); //открываем порт для связи с ПК

  servo.attach(5);


  pinMode(sig, OUTPUT); // настроить пин для света как выход

  motorR.setDeadtime(5); // команда чтоб програмно была пауза между движением вперед и назад
  motorL.setDeadtime(5);

  motorR.setDirection(REVERSE); //реверс если машинка едет не в ту сторону изначально
  motorL.setDirection(REVERSE);
  motorR.setMode(AUTO); //режим движения
  motorL.setMode(AUTO);

     motorR.setSmoothSpeed(30); // шаг прибавления скорости
    motorL.setSmoothSpeed(30);


  radio.begin(); //активировать модуль
  radio.setAutoAck(1);         //режим подтверждения приёма, 1 вкл 0 выкл
  radio.setRetries(0, 15);    //(время между попыткой достучаться, число попыток)
  radio.enableAckPayload();    //разрешить отсылку данных в ответ на входящий сигнал
  radio.setPayloadSize(32);     //размер пакета, в байтах

  radio.openReadingPipe(1, address[0]);     //хотим слушать трубу 0
  radio.setChannel(0x60);  //выбираем канал (в котором нет шумов!)

  radio.setPALevel (RF24_PA_MAX); //уровень мощности передатчика. На выбор RF24_PA_MIN, RF24_PA_LOW, RF24_PA_HIGH, RF24_PA_MAX
  radio.setDataRate (RF24_250KBPS); //скорость обмена. На выбор RF24_2MBPS, RF24_1MBPS, RF24_250KBPS
  //должна быть одинакова на приёмнике и передатчике!
  //при самой низкой скорости имеем самую высокую чувствительность и дальность!!

  radio.powerUp(); //начать работу
  radio.startListening();  //начинаем слушать эфир, мы приёмный модуль

}

void loop() {
    byte pipeNo;
    while ( radio.available(&pipeNo)) {  // слушаем эфир со всех труб
        radio.read( &recieved_data, sizeof(recieved_data) );     // чиатем входящий сигнал
    }
    valX = recieved_data[0]; // назначить массив принятых данных 0 на данные с джойстика по оси Х
    valY = recieved_data[1]; // назначить массив принятых данных 1 на данные с джойстика по оси Y
    valZ = recieved_data[3]; // кнопка


    // джойстик на А0 и А1
    int dutyR = 255 - valX / 2; // 255 - 1023/2 (управление от минус 255 до плюс 255)

motorL.smoothTick(dutyR); //данные для движения
motorR.smoothTick(dutyR);
    valY = map(valY, 950, 0, 40, 122); // управление сервой центр сервы и углы ограничения движения
    servo.write(valY);
    }

Для джойстика:
#include <SPI.h>
#include "nRF24L01.h"
#include "RF24.h"

RF24 radio(9, 10); // CE и CSN


byte address[][6] = {"1Node", "2Node", "3Node", "4Node", "5Node", "6Node"};

int valX = A3;  // значения с джойстика по оси Х
int valY = A1; // значения с джойстика по оси Y
int valZ = 7; // кнопка


int transmit_data[3]; // массив, хранящий передаваемые данные ( 2 значения с джойстика )


void setup() {
  Serial.begin(9600); //открываем порт

   pinMode(valZ, INPUT);

  radio.begin(); //активировать модуль
  radio.setAutoAck(1);         //режим подтверждения приёма, 1 вкл 0 выкл
  radio.setRetries(0, 15);    //(время между попыткой достучаться, число попыток)
  radio.enableAckPayload();    //разрешить отсылку данных в ответ на входящий сигнал
  radio.setPayloadSize(32);     //размер пакета, в байтах

  radio.openWritingPipe(address[0]);   //мы - труба 0, открываем канал для передачи данных
  radio.setChannel(0x60);  //выбираем канал (в котором нет шумов!)

  radio.setPALevel (RF24_PA_MAX); //уровень мощности передатчика. На выбор RF24_PA_MIN, RF24_PA_LOW, RF24_PA_HIGH, RF24_PA_MAX
  radio.setDataRate (RF24_250KBPS); //скорость обмена. На выбор RF24_2MBPS, RF24_1MBPS, RF24_250KBPS
  //должна быть одинакова на приёмнике и передатчике!
  //при самой низкой скорости имеем самую высокую чувствительность и дальность!!

  radio.powerUp(); //начать работу
  radio.stopListening();  //не слушаем радиоэфир, мы передатчик
}

void loop() {

  transmit_data[0] = analogRead(valX); // присваиваем массиву 0 значение с джойстика по оси X
  transmit_data[1] = analogRead(valY); // присваиваем массиву 1 значение с джойстика по оси Y
transmit_data[3] = digitalRead(valZ); // присваиваем массиву 1 значение с джойстика по оси Y

    radio.write(&transmit_data, sizeof(transmit_data)); // отправить по радио

Serial.print(transmit_data[0]); Serial.println(transmit_data[1]);
}

Код, указанный ниже, уже не использую 👇.
Он был первым, понравилась библиотека Гайвера с плавным стартом и перешел на нее
Код первый:
#include <SPI.h>
#include "nRF24L01.h"
#include "RF24.h"
#include <Servo.h>


RF24 radio(9, 10); // пины для нрф24

int recieved_data[2]; // массив принятых данных

int valX; // данные с джойстика по оси X
int valY; // данный с джойстика по оси Y

byte motor1 = 3;  // скорость првого мотора
byte pered1 = 2;  // движение мотора 1 вперёд
byte nazad1 = 4;  // движение мотора 1 назад

byte motor2 = 6;  // скорость второго мотора
byte pered2 = 8;  // движение мотора 2 вперёд
byte nazad2 = 7;  // движение мотора 2 назад

Servo servo1;

byte address[][6] = {"1Node", "2Node", "3Node", "4Node", "5Node", "6Node"}; //возможные номера труб

void setup() {
  Serial.begin(9600); //открываем порт для связи с ПК

  servo1.attach(5);

  pinMode(motor1, OUTPUT); // назанчить пин выходом
  pinMode(pered1, OUTPUT); // назанчить пин выходом
  pinMode(nazad1, OUTPUT); // назанчить пин выходом

   pinMode(motor2, OUTPUT); // назанчить пин выходом
   pinMode(pered2, OUTPUT); // нахначить пин выходом
   pinMode(nazad2, OUTPUT); // назначить пин выходом

  radio.begin(); //активировать модуль
  radio.setAutoAck(1);         //режим подтверждения приёма, 1 вкл 0 выкл
  radio.setRetries(0, 15);    //(время между попыткой достучаться, число попыток)
  radio.enableAckPayload();    //разрешить отсылку данных в ответ на входящий сигнал
  radio.setPayloadSize(32);     //размер пакета, в байтах

  radio.openReadingPipe(1, address[0]);     //хотим слушать трубу 0
  radio.setChannel(0x60);  //выбираем канал (в котором нет шумов!)

  radio.setPALevel (RF24_PA_MAX); //уровень мощности передатчика. На выбор RF24_PA_MIN, RF24_PA_LOW, RF24_PA_HIGH, RF24_PA_MAX
  radio.setDataRate (RF24_250KBPS); //скорость обмена. На выбор RF24_2MBPS, RF24_1MBPS, RF24_250KBPS
  //должна быть одинакова на приёмнике и передатчике!
  //при самой низкой скорости имеем самую высокую чувствительность и дальность!!

  radio.powerUp(); //начать работу
  radio.startListening();  //начинаем слушать эфир, мы приёмный модуль
}

void loop() {
  byte pipeNo;
  while ( radio.available(&pipeNo)) {  // слушаем эфир со всех труб
    radio.read( &recieved_data, sizeof(recieved_data) );         // чиатем входящий сигнал

  valX = recieved_data[0]; // назначить массив принятых данных 0 на данные с джойстика по оси Х
  valY = recieved_data[1]; // назначить массив принятых данных 1 на данные с джойстика по оси Y

// ДВИЖЕНИЕ назад
if (valX >=0 && valX<=490){ // если данные с джойстика по оси Х в данном интервале то выполнить..
  valX = map(valX, 490, 0, 0, 255); // приравниваем значения
  valX = constrain(valX, 0, 255); // ограничиаем значения
  analogWrite(motor1, valX);  // подаём на мотор 1 указаную скорость
  digitalWrite(pered1, LOW);  // движения вперёд нет
  digitalWrite(nazad1, HIGH); // движения назад

  analogWrite(motor2, valX);  // подаём на мотор 2 указаную скорость
  digitalWrite(pered2, LOW);  // движения вперёд нет
  digitalWrite(nazad2, HIGH); // движения назад


  // ДВИЖЕНИЕ вперед
} else if (valX >=510 && valX <=1023){
  valX = map(valX, 510, 1023, 0, 255);
  valX = constrain(valX, 0, 255);
  analogWrite(motor1, valX);
  digitalWrite(pered1, HIGH);
  digitalWrite(nazad1, LOW);

  analogWrite(motor2, valX);
  digitalWrite(pered2, HIGH);
  digitalWrite(nazad2, LOW);


  // ДВИЖЕНИЕ СТОП
  }else if (valX >=490 && valX <=510){
    analogWrite(motor1, 0);
    digitalWrite(pered1, LOW);
    digitalWrite(nazad1, LOW);

    analogWrite(motor2, 0);
    digitalWrite(pered2, LOW);
    digitalWrite(nazad2, LOW);

  }

  valY = map(valY, 1023, 0, 39, 108); // НАСТРОЙКА СЕРВЫ
  servo1.write(valY);
}
}
 
Изменено:
  • Лойс +1
Реакции: Arhat109

te238s

★★✩✩✩✩✩
14 Ноя 2021
374
97
Может дело не в коде? С противо-ЭДС бороться надо схемотехнически. Одно из решений,если поверхностно,заключается в самоторможении путём замыкания двигателя на себя.
 

Геннадий П

★★★★★★✩
14 Апр 2021
1,955
625
44
В даташите ясно написаны все фазы включения/выключения двигателя.

1636985445885.png
 

te238s

★★✩✩✩✩✩
14 Ноя 2021
374
97
Хм. Я лично не изучал библиотеку Гайвера и каким образом реализуется деадтайм,но возможно драйвер не выдерживает тока торможения. Тогда,конечно,два варианта:1) менять драйвер на более мощный,2) в коде осуществлять паузу,как ты правильно написал. Но именно паузу когда моторы отключены и тормозятся силами трения механики. Я правильно понимаю?
 

Demka777

✩✩✩✩✩✩✩
2 Ноя 2021
20
8
мне советовали реле поставить в цепь, но не очень эта идея понравилась. Показалось что будет минимально затрат и возни если в коде все исправить. Но оказалось не все так просто.
В голове как бы идеи были, но на деле ноль. Думал сделать как в управлении светодиодом, запоминать предыдущее положение стика и если оно было вперед, а текущее будет назад, делать паузу. Или же какой-то таймер придумать когда направление меняется. Как в код это перевести🤷‍♂️.
 
Изменено:

Demka777

✩✩✩✩✩✩✩
2 Ноя 2021
20
8
@Геннадий П, как это сделать? В библиотеке на шаговый двигатель видел подобную команду.

// Плавная остановка с заданным ускорением
void stop();

// Жёсткая остановка
void brake();
 

Demka777

✩✩✩✩✩✩✩
2 Ноя 2021
20
8
Избыточное цитирование
Хм. Я лично не изучал библиотеку Гайвера и каким образом реализуется деадтайм,но возможно драйвер не выдерживает тока торможения. Тогда,конечно,два варианта:1) менять драйвер на более мощный,2) в коде осуществлять паузу,как ты правильно написал. Но именно паузу когда моторы отключены и тормозятся силами трения механики. Я правильно понимаю?
дедтайм задаётся в микросекундах и тип данных - uint16_t, т.е. макс значение 65'000 мкс, я пробовал ставить 50000, визуально ничего не поменялось, паузы не ощутил.

Мощнее драйвер взять это определенно выход, но хотелось бы оставить все как есть, в коде поправить и разобраться в этом.

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

Геннадий П

★★★★★★✩
14 Апр 2021
1,955
625
44
я пробовал ставить 50000, визуально ничего не поменялось, паузы не ощутил
А визуально и не поменяется ничего.
Остановка двигателя делается в два этапа:
Гашение индукционной ЭДС, которая обязательна и выполняется дедтаймом, ставится максимально возможный.
И гашение ЭДС возникшей в результате инерционного вращения ротора, в результате чего мотор работает как генератор, этим занимается команда break, которая по сути закорачивает двигатель в результате чего он тормозится. (яркий пример - это шуруповерт с тормозом, который почти сразу останавливается после отпускания курка и какая нть дрель которая продолжает вращаться некоторое время)

По сути нужно после окончания действия сигнала движения выполнять break (дедтайм выполняется автоматически) но выполнять его до момента фактической остановки двигателя. Т.к. обратной связи с двигателем нету чтобы определить остановился ли на самом деле двигатель, можно примерно рассчитать время остановки.
Более продвинутый вариант - это если во время процесса остановки двигателя пришла команда на движение в ту же сторону, то прервать процесс торможения и продолжить движение.
 

Demka777

✩✩✩✩✩✩✩
2 Ноя 2021
20
8
@Геннадий П, Идея отличная, даже если сделать остановку пару секунд, уже было бы лучше и визуально будет видно что все это работает, потом можно просто время подобрать нужное. Меньше секунды наверно и не ставил бы, все таки это игрушка. Можно даже убрать плавный разгон и торможение motor.setSmoothSpeed(30);, хотя команда нравится.

Могли бы помочь перевести это в код?
 
Изменено:

te238s

★★✩✩✩✩✩
14 Ноя 2021
374
97
@Геннадий П,думаю из-за токов торможения выгорает драйвер,а не из-за перенапряжения всё-таки. В
Думал сделать как в управлении светодиодом, запоминать предыдущее положение стика и если оно было вперед, а текущее будет назад, делать паузу. Или же какой-то таймер придумать когда направление меняется. Как в код это перевести🤷‍♂️.
В библиотеке GMotor функция Run именно так и делает. Если направление изменилось,то отключает двигатель на время в микросекундах.
Опять же,стоит попробовать поиграть настройкой setSmoothTicks(); При уменьшении динамики по логике и перегрузки снизятся.
 

leeroy

★✩✩✩✩✩✩
1 Окт 2019
19
16
Программно может и можно упростить, но я бы все таки решил проблему на схеме, тем более, если вывело из строя банку, нужно смягчить пульсации по питанию.
1.Во-первых, желательно все-таки использовать bms, так и заряжать батарею будет проще.
2. Добавить близко к контактам э/м керамику на 0.1 мкФ, а ближе к батарее электролит на 220-470 мкФ.
3. если драйвер сгорел, значит слишком большой стартовый ток (больше 3.2А), лучше его запараллелить хотя бы со вторым таким-же
 
Изменено:
  • Лойс +1
Реакции: te238s

Demka777

✩✩✩✩✩✩✩
2 Ноя 2021
20
8
@leeroy, бмс сейчас используется в цепи для двух банок 18650, тогда был пробный пуск, так же имеется бмс для 12в. На каждом моторе стоят 3 конденсатора керамических 0,1мкФ. Электролитический поставил на контакты питания ардуино (470мкФ)и драйвера (вроде 1000мкФ). Всего заказывал 3 драйвера tb6612fng, один сгорел. Так что есть возможность использовать два запараллельных драйвера, лишь бы точно знать что оба не погорят на этих опытах.
 

leeroy

★✩✩✩✩✩✩
1 Окт 2019
19
16
Так что есть возможность использовать два запараллельных драйвера, лишь бы точно знать что оба не погорят на этих опытах.
Замерить бы стартовый ток, тогда можно было бы и знать точно, хватит или нет. Где-то в 1.5 раза точно повысится порог ( до ~4.7-5 А - должно хватить). Могу лишь предположить, что увеличение мощности драйвера с большой вероятностью решит проблему, т.к. у меня практически идентичная связка, только драйверы запараллеленные, а код управления самый примитивный - и никаких проблем нет
 

Demka777

✩✩✩✩✩✩✩
2 Ноя 2021
20
8
@Геннадий П,думаю из-за токов торможения выгорает драйвер,а не из-за перенапряжения всё-таки.
Просто при торможении никаких сбоев не наблюдал. Видимо при смене направления к ним еще добавляются пусковые токи.

Пробовал ставить больше значение в
motor.setSmoothSpeed( ххххх );
визуально останавливается гораздо медленней. Но если резко сменить направление, работает как и раньше
 

Demka777

✩✩✩✩✩✩✩
2 Ноя 2021
20
8
Избыточное цитирование
Замерить бы стартовый ток, тогда можно было бы и знать точно, хватит или нет. Где-то в 1.5 раза точно повысится порог ( до ~4.7-5 А - должно хватить). Могу лишь предположить, что увеличение мощности драйвера с большой вероятностью решит проблему, т.к. у меня практически идентичная связка, только драйверы запараллеленные, а код управления самый примитивный - и никаких проблем нет
изначально планировал 3 драйвера параллелить, но когда после первого запуска умер аккумулятор, побоялся что сразу все драйверы могу убить.
мне не составит проблем еще один драйвер поставить в схему, лишь бы не погорели) место для двух есть.
3BAE3F7A-CBD8-4458-8E38-7256D13B7F40.jpeg
Какое питание, драйверы и моторы вы используете в своем проекте?
 

leeroy

★✩✩✩✩✩✩
1 Окт 2019
19
16
Какое питание, драйверы и моторы вы используете в своем проекте?
12v 3s 18650 c bms, драйверы такие же tb6612fng, моторы 390 с металлическим редуктором, но у меня 4 спаянных драйвера, чтобы прям с запасом) а то потребление от таких дур на большой вес значительное
2021-04-04 23-19-42.JPG
 

Demka777

✩✩✩✩✩✩✩
2 Ноя 2021
20
8
Избыточное цитирование
12v 3s 18650 c bms, драйверы такие же tb6612fng, моторы 390 с металлическим редуктором, но у меня 4 спаянных драйвера, чтобы прям с запасом) а то потребление от таких дур на большой вес значительное
Посмотреть вложение 31284
Смотрится очень красиво и компактно, по сравнению с моими косами)))

Попробую на 8в поставить два драйвера, вдруг и правда это и было решение. Жаль третий драйвер полу убитый стал, там в одну сторону крутит мотор с рывками, один транзистор наверно пробило. Единственное не помню на двух ли моторах. Там ведь два Н моста
 
Изменено:

Andre_L

✩✩✩✩✩✩✩
22 Окт 2021
9
8
@Demka777,
Если я правильно понял, проблемы при резком повороте сервомашинки. У меня была такая засада с роботом LAHU.
Все дело в серво mg995. Она дает дикие броски тока при резких изменениях направления.
Конденсаторы и прочее в цепях питания серво не помогают. Только отдельное силовое питание сервы или пауза на 40mS.
Или потратиться на дорогую серву.
 

Demka777

✩✩✩✩✩✩✩
2 Ноя 2021
20
8
Избыточное цитирование
@Demka777,
Если я правильно понял, проблемы при резком повороте сервомашинки. У меня была такая засада с роботом LAHU.
Все дело в серво mg995. Она дает дикие броски тока при резких изменениях направления.
Конденсаторы и прочее в цепях питания серво не помогают. Только отдельное силовое питание сервы или пауза на 40mS.
Или потратиться на дорогую серву.
Не, именно с моторов. Отключал серву, затыки оставались.
 

Первопечатник

✩✩✩✩✩✩✩
14 Ноя 2021
5
6
Всю тему не читал. Но по последним постам с резким поворотом сервопривода. У сервомотора фиксированная угловая скорость поворота. Поэтому, чтобы медленнее поворачивать, подавайте угол поворота не сразу весь, а короткими шажками с интервалами. Причем, можно сделать так называемую S-кривую скоростей, когда в начале поворота шаги даются короткие, в середине процесса поворота шаги длинные, а при подходе к завершающей фазе поворота шаги вновь становятся короткими. Длина шага и интервал между шагами должен быть такой, чтобы серва успевала повернуться на этот угол и поворот проходил более плавно.
Конечно, серва - это не шаговик, тут не выйдет совсем без рывков.
 

RG22EM

✩✩✩✩✩✩✩
22 Окт 2020
33
4
Библиотека Гайвера не умеет правильно работать с этим драйвером, так рассчитана максимум на трёхпроводное управление, а здесь нужна четырёхпроводная, для перевода мотора в режим изоляции.
Здесь наверно лучше бы подошёл VNH5019
 
Изменено:

Demka777

✩✩✩✩✩✩✩
2 Ноя 2021
20
8
@RG22EM,
Драйвер, который вы посоветовали, в 10 раз дороже стоит. Надо попробовать тогда свой скетч без библиотеки Гайвера доработать. Сам точно не смогу(
 

RG22EM

✩✩✩✩✩✩✩
22 Окт 2020
33
4
@Demka777, читайте даташит на свой драйвер, при 0 значении шима мотор переходит в торможении...
Я посоветовал то, что я использую
 

leeroy

★✩✩✩✩✩✩
1 Окт 2019
19
16
@Demka777 если я правильно понял, то предыдущий комментатор имеет в виду 4 провода управления, включая STBY - этот пин управляет состоянием драйвера вкл/выкл, если подать на него высокий и низкий сигнал соответственно. По факту этим драйвером можно управлять и 3 проводами, если подать постоянный высокий сигнал на STBY (соединить с линией +5V). Если это не поможет, попробуйте самый простой вариант управления без библиотеки Гайвера, который использую я в том числе:
C++:
//условное движение вперед на примере одного мотора
digitalWrite(STBY, HIGH);// STBY -здесь пин ардуины, подключенный к пину STBY драйвера, если задействуется пин управления вкл/выкл драйвера
digitalWrite(AIN1, LOW);// AIN1 - здесь пин ардуины, подключенный к пину AIN1 драйвера
digitalWrite(AIN2, HIGH);// AIN2 - здесь пин ардуины, подключенный к пину AIN2 драйвера]
analogWrite(PWMA, pwm);// PWMA - здесь пин ардуины (обязательно должен поддерживать ШИМ), подключенный к пину PWMA драйвера, pwm - значение в диапазоне 0-255(чем выше, тем больше скорость)

//условное движение назад на примере одного мотора
digitalWrite(STBY, HIGH);// если задействуется пин управления вкл/выкл драйвера
digitalWrite(AIN1, HIGH);
digitalWrite(AIN2, LOW);
analogWrite(PWMA, pwm);

//условный стоп на примере одного мотора
digitalWrite(AIN1, LOW);
digitalWrite(AIN2, LOW);
//или:
digitalWrite(STBY, LOW); //если используется пин
1637752850816.png