Поворот на 180 градусов с использованием MPU6050.
Я хочу повернуть робота точно на 180 градусов с помощью MPU6050. Это код, который я пробовал. Может кто-нибудь мне помочь?
#include <MPU6050_tockn.h>
#include <Wire.h>
#define enA 9
#define in1 4
#define in2 5
#define enB 10
#define in3 6
#define in4 7
MPU6050 mpu6050(Wire);
void setup() {
Serial.begin(9600);
Wire.begin();
mpu6050.begin();
mpu6050.calcGyroOffsets(true);
setupmotor();
}
void setupmotor(){
pinMode(enA, OUTPUT);
pinMode(enB, OUTPUT);
pinMode(in1, OUTPUT);
pinMode(in2, OUTPUT);
pinMode(in3, OUTPUT);
pinMode(in4, OUTPUT);
}
void loop() {
updatempu();
while(mpu6050.getAngleZ()== 180 || mpu6050.getAngleZ()== -180 ){
turn();
}
}
void updatempu(){
mpu6050.update();
Serial.print("\tangleZ : ");
Serial.println(mpu6050.getAngleZ());
}
void turn(){
Serial.println("turn");
digitalWrite(in1, LOW);
digitalWrite(in2, HIGH);
digitalWrite(in4, LOW);
digitalWrite(in3, HIGH);
analogWrite(enA, 100); // Отправляем сигнал ШИМ на двигатель A
analogWrite(enB, 100);
}
void stp(){
Serial.println("stop");
digitalWrite(in1, LOW);
digitalWrite(in2, LOW);
digitalWrite(in4, LOW);
digitalWrite(in3, LOW);
}
@hasith_12, 👍0
Обсуждение1 ответ
Лучший ответ:
Насколько я понимаю, вы хотите, чтобы робот автоматически позиционировался под углом 180° или -180° и оставался там. Когда к роботу прилагается внешняя сила , выталкивающая его из целевых позиций, он должен снова попытаться достичь целевых позиций.
Первая проблема была отмечена в комментариях, и ваша собственная коррекция кода, похоже, подойдет для ее решения:
if(mpu6050.getAngleZ()== 180 || mpu6050.getAngleZ()== -180 ){
stp();
} else {
turn();
}
Но я вижу вторую проблему: в реальном мире датчики обычно имеют какой-то шум, наложенный на их сигнал (не обязательно имеющий в виду электрический шум). Например, если потрясти стол, на котором стоит робот. Или, что, на мой взгляд, более важно: двигатель, который вы используете, может останавливаться недостаточно быстро. MPU может возвращать значение 179° или 181°, тогда как должно быть 180°, потому что двигатель может остановить робота достаточно быстро (в пределах промежутка времени, необходимого для перемещения на 1°). В вашей текущей логике это вызовет еще одну команду поворота. Поскольку вы поворачиваетесь только в одном направлении, это может создать нестабильную систему, которая будет вращаться бесконечно.
Проблемы такого рода часто решаются с помощью управления с обратной связью (разумеется, в сочетании с возможностью управления/поворота в обе стороны). Хорошим и полезным примером является ПИД-регулятор (пропорциональный, интегральный, дифференциальный: так математически структурировано управление), для которого уже существуют библиотеки Arduino (например, этот). Если хотите проще, вы можете определить диапазон углов, приемлемый для вашего позиционирования (где оно должно остановиться) (например, от 175° до 185°). Размер необходимого вам диапазона будет зависеть от механики вашего робота и двигателя. Обратите внимание, что у этого метода также есть недостатки, но на данный момент это может быть проще, в зависимости от того, чего именно вы хотите достичь.
Как отметил Том в своем комментарии, у вас также могут возникнуть проблемы с первым подходом, если метод getAngleZ()
возвращает не целое число, а число с плавающей точкой, что действительно так. Вы можете увидеть это в исходном коде используемой библиотеки здесь. Линия
float getAngleZ(){ return angleZ; };
сообщает нам, что тип возвращаемого значения метода — float
. Проблема этого типа в том, что он не может представлять все рациональные значения внутри своего диапазона. Между двумя следующими значениями с плавающей запятой имеются пробелы. Значения внутри этого пробела не могут быть представлены с плавающей запятой. Вместо этого будет использоваться ближайшее значение (на самом деле я не уверен, как это было сделано. Вероятно, путем перехода к следующему меньшему значению, как с помощью int
). Это также означает, что не каждое целое число можно представить в виде числа с плавающей запятой. Даже если угол Z равен ровно 180°, значение с плавающей запятой может быть примерно таким: 179,98
. Но поскольку 179,98
не равно 180
, оператор
mpu6050.getAngleZ() == 180
никогда не станет правдой. Конечно, упомянутые выше решения применимы и здесь.
Я полностью согласен, и я бы также проверил, что getAngleZ() возвращает целое число, а не число с плавающей запятой или двойное число., @Tom
Вы правы, я об этом не подумал. Я добавлю это в ответ. спасибо, @chrisl
- Как очистить буфер FIFO на MPU6050?
- Как сгенерировать аппаратное прерывание в mpu6050 для пробуждения Arduino из режима SLEEP_MODE_PWR_DOWN?
- Понимание того, почему следует избегать «String» и альтернативных решений
- Объяснение кода MPU6050
- Изменение адреса I2C MPU-6050
- Снять гравитацию с акселерометра MPU-6050
- Скорость передачи данных акселерометра mpu6050 в Arduino Uno и частота дискретизации mpu6050
- Как соединить L293D и MPU6050 для совместной работы?
понимаете ли вы, что
while(mpu6050.getAngleZ()== 180 || mpu6050.getAngleZ()== -180 )
истинно, когда getAngleZ **IS** либо 180, либо -180? возможно, вы имели в видуwhile(mpu6050.getAngleZ()!= 180 && mpu6050.getAngleZ()!= -180 )
, @Jaromanda Xкогда mpu6050.getAglez() = 180 0r -180, робот должен остановиться. но этого не происходит. не останавливаясь, он поворачивается, @hasith_12
ваша логика *в ее нынешнем виде* такова: если
getAngleZ()
равен 180 ИЛИ -180, вызовите функциюturn
- но вы хотите повернуть, если getAngleZ НЕ 180 И НЕ -180 - это правильно, @Jaromanda Xif(mpu6050.getAngleZ()== 180 || mpu6050.getAngleZ()== -180 ){ стп(); } else { Turn();} так должно быть или нет??, @hasith_12
может быть, я не знаю, кажется, это правильно - ты пробовал?, @Jaromanda X
вы просите о помощи, но не говорите, в чем проблема. .... информация о том, что вы наблюдаете, должна быть в вопросе выше .... добавьте ее, пожалуйста, @jsotola