Управление NEMA 17 с ПИД на TB6600, двигатель слишком медленный
Я пишу здесь, поскольку отчаялся найти решение после многочисленных попыток, как с онлайн-решениями, так и с ChatGPT, так что, возможно, кто-то здесь сможет помочь.
Мой проект довольно прост: я пытаюсь сделать перевёрнутый маятник с помощью Arduino, NEMA 17 и контроллера TB6600. Угол наклона маятника задаётся энкодером, который работает очень хорошо. Моя механическая система тоже работает отлично, никаких проблем.
Моя проблема в том, что я не могу правильно управлять двигателем, чтобы он реагировал на быстрые команды. Я хочу, чтобы двигатель вращался в соответствии с базовым выходным сигналом ПИД-регулятора, и пока ПИД-регулятор не настроен, я не могу добиться достаточно быстрого вращения двигателя. Как бы я ни настраивал ПИД-регулятор, двигатель не будет достаточно быстрым, чтобы удерживать маятник в вертикальном положении. В противном случае двигатель вращается правильно: вправо, когда маятник падает справа, и влево, когда он падает слева, поэтому у меня нет проблем с управлением направлением двигателя. Кроме того, я знаю, что мои кабели должны быть в порядке, так как перед использованием ПИД-регулятора у меня есть фаза инициализации, где я помещаю маятник в середину направляющих, что требует перемещения двигателя. И я могу сделать это очень быстро с помощью библиотеки AccelStepper, поэтому я знаю, что моего оборудования достаточно для моих нужд.
TB6600 настроен на полный шаг и допускает до 3 А, чего, как я знаю, более чем достаточно, как я уже говорил ранее.
Вот код, который я использую:
#include <AccelStepper.h>
#include <Encoder.h>
//################# CONNECTION HARDWARE ################
// Connection encoder
#define enc_green_pin 2
#define enc_white_pin 3
// Connection motor
#define motor_dirPin 8 // Connected to DIR+(+5V)
#define motor_stepPin 9 // Connected to PUL+(+5V)
#define motorInterfaceType 1 // stepper driver
// Create a new instance of the AccelStepper class:
AccelStepper stepper = AccelStepper(motorInterfaceType, motor_stepPin, motor_dirPin);
// Encoder
Encoder encod(enc_green_pin,enc_white_pin);
void setup() {
Serial.begin (115200);
// motor settings
stepper.setMaxSpeed(5000);
stepper.setAcceleration(50000);
delay(2000); // seconds to wait before starting
initialisation();
}
// Initialisation, moves stepper and init encoder
void initialisation(){
Serial.print("Position before : ");
Serial.println(stepper.currentPosition());
// Moves stepper to the middle
stepper.moveTo(-1000);
stepper.runToPosition();
Serial.print("Position : ");
Serial.println(stepper.currentPosition());
stepper.setCurrentPosition(0);
delay(2000); // seconds to wait before starting
}
void loop() {
// Read encoder and convert angle
long pos_brut = encod.read();
float angle_deg = int(conv_angle(pos_brut));
int error = -(180-angle_deg); // error : setpoint=180
/*
float error =-5*(180 - angle_deg_int);
errSum += (error * 0.01);
float dErr = (error - lastErr) / 0.01;
output = Kp * error + Ki * errSum + Kd * dErr;
lastErr = error;
// Limits output
if (output > 255) output = 255;
if (output < -255) output = -255;
*/
// Method 1
if (error > 0) {
digitalWrite(motor_dirPin, HIGH);
analogWrite (motor_stepPin,error);
}
else {
digitalWrite(motor_dirPin, LOW);
analogWrite (motor_stepPin,-error);
}
/* Method 2
if (output > 0) {
digitalWrite(motor_dirPin, HIGH);
stepMotor(output );
} else {
digitalWrite(motor_dirPin, LOW);
stepMotor(-output );
}
*/
}
void stepMotor(int steps) {
for (int i = 0; i < steps; i++) {
digitalWrite(motor_stepPin, HIGH);
delayMicroseconds(500);
digitalWrite(motor_stepPin, LOW);
delayMicroseconds(500);
}
}
// Convert angle from encoder
float conv_angle(long compteur) {
float val_deg;
val_deg = float(compteur) * 180./1200.;
return (val_deg);
}
Как видите, я пробовал разные подходы:
Для контрольного вывода я попробовал:
Вычисляю ошибку самостоятельно (используется в коде)
Использование самодельного PID, найденного в Интернете (прокомментировано в коде)
Использование библиотеки PID_V2 Arduino (не видно в коде)
Для управления двигателем я попробовал:
Использование библиотеки AccelStepper с
moveTo()иrun()(не видно в коде)Использование
digitalWrite/analogWriteнепосредственно в цикле (используется в коде)Использование цикла
forдляdigitalWrite(закомментировано в цикле)
Я попробовал поиграть со всеми указанными выше значениями и добавить задержки тут и там.
Боюсь, я не до конца понимаю, как должен управляться степпер, но все эти испытания основаны на том, что я видел в интернете.
@ColChope, 👍-2
Обсуждение1 ответ
Я вижу две возможные проблемы.
Когда мотор меняет направление, вы можете потерять как минимум один переход.
Большинство задержек — блокирующие, то есть весь код перестаёт работать. Попробуйте использовать версии, которые не блокируют.
- Шаговый двигатель работает не так, как ожидалось
- Подать нулевое напряжение на определенные серводвигатели за определенное время.
- Какой-нибудь совет, который вы можете дать мне по моему коду шагового двигателя?
- Управление скоростью вентилятора с помощью библиотеки Arduino PID
- Изменение ШИМ на Arduino Mega, контакты 9 и 10 на 20–25 кГц
- Шаговый двигатель не работает с платой A4988
- Как запустить шаговый двигатель через последовательную связь
- Справка по библиотеке AccelStepper - Одновременное управление двигателем
angle_deg_intне определено.angle_degопределено, но не используется. Так что, вероятно, у вас опечатка. А наблюдаемое вами движение, вероятно, связано с арифметикой с плавающей запятой., @rzicklerВы можете интегрировать библиотеку PID_v1.h с библиотекой AccelStepper для ПИД-регулирования. Библиотека AccelStepper хорошо подходит для управления шаговыми двигателями, и её лучше использовать для управления скоростью и ускорением, а не напрямую вызывать digitalWrite или analogWrite. Это обеспечит более плавное и точное движение. Вот ссылка на PID_v1.h: https://github.com/br3ttb/Arduino-PID-Library/blob/master/PID_v1.h, @tepalia
Думаю, можно попробовать с PID_v1, но сомневаюсь, что проблема в этом. Как я уже говорил, я пробовал разные PID, а также своё значение и множество других комбинаций. Кроме того, как и было написано, я пробовал использовать библиотеку AccelStepper с moveTo() и run(), но это не сработало. Возможно, я делаю что-то не так, но не понимаю, что именно. Я убедился, что moveTo() и run() находятся в одном цикле while и вызываются каждый раз., @ColChope
Извините, это тип, который я упростил, чтобы опубликовать здесь. Код работает хорошо, я просто выполнил операцию int(), используя ещё одну переменную, которую я убрал здесь, но забыл изменить. Что вы имеете в виду по поводу чисел с плавающей точкой? Я не особо обращал внимание на типы переменных, так что, возможно, стоит обратить на это внимание., @ColChope