Акклерометр arduino с серводвигателем
В настоящее время я работаю над проектом по управлению тремя двигателями при отправке значения акселерометра на компьютер через модуль Bluetooth. Я хочу, чтобы работа двигателя и передача значений работали отдельно. Но когда работают двигатели, трансмиссия останавливается. Я использовал библиотеку ArduinoThread, но так как я не понимаю всего использования, у нее все еще есть какая-то задержка. Кроме того, я хочу, чтобы два двигателя работали сначала(только один раз), а другой работал через определенное время(также только один раз). Но первая настройка двух двигателей, а вторая не работает. Пожалуйста, проверьте мой код и дайте мне несколько советов. Спасибо!
#include <Wire.h>
#include <SoftwareSerial.h>
#include <Servo.h>
#include <Thread.h>
const int MPU_addr=0x68; // MPU-6050 I2C address
int16_t AcX,AcY,AcZ,GyX,GyY,GyZ;
SoftwareSerial BTSerial(3,2); // TX,RX
Servo servoMini;
Servo servoUp;
Servo servoDown;
int pinMini = 6;
int pinUp = 9;
int pinDown = 10;
int i = 1;
unsigned long tPrev, tNow = 0;
Thread myThread = Thread();
void readAcc(){
Wire.endTransmission(true);
Wire.beginTransmission(MPU_addr);
Wire.write(0x3B); // starting with register 0x3B (ACCEL_XOUT_H)
Wire.endTransmission(false);
Wire.requestFrom(MPU_addr,14,true); // request a total of 14 registers // 14bit??
AcX=Wire.read()<<8|Wire.read(); // 0x3B (ACCEL_XOUT_H) & 0x3C (ACCEL_XOUT_L)
//AcY=Wire.read()<<8|Wire.read(); // 0x3D (ACCEL_YOUT_H) & 0x3E (ACCEL_YOUT_L)
//AcZ=Wire.read()<<8|Wire.read(); // 0x3F (ACCEL_ZOUT_H) & 0x40 (ACCEL_ZOUT_L)
//GyX=Wire.read()<<8|Wire.read(); // 0x43 (GYRO_XOUT_H) & 0x44 (GYRO_XOUT_L)
//GyY=Wire.read()<<8|Wire.read(); // 0x45 (GYRO_YOUT_H) & 0x46 (GYRO_YOUT_L)
//GyZ=Wire.read()<<8|Wire.read(); // 0x47 (GYRO_ZOUT_H) & 0x48 (GYRO_ZOUT_L)
BTSerial.println(AcX); // 16bit
Serial.println(AcX);
// delay(25);
}
void setup(){
// I2C
Wire.begin();
Wire.beginTransmission(MPU_addr);
Wire.write(0x6B); // PWR_MGMT_1 register
Wire.write(0); // set to zero (wakes up the MPU-6050)
// serial, bluetooth
Serial.begin(9600);
BTSerial.begin(9600);
Serial.println("CLEARDATA");
Serial.println("ONLY AcX");
// servo
servoMini.attach(pinMini);
servoUp.attach(pinUp);
servoDown.attach(pinDown);
pinMode(pinMini, OUTPUT);
pinMode(pinUp, OUTPUT);
pinMode(pinDown, OUTPUT);
servoMini.write(145);
servoUp.write(180);
servoDown.write(0);
// Thread(MPU-6050)
myThread.onRun(readAcc);
myThread.setInterval(20);
}
void loop(){
while(i == 1){
tNow = millis();
myThread.run();
servoUp.attach(pinUp);
servoDown.attach(pinDown);
servoUp.write(60);
servoDown.write(120);
if((tNow - tPrev)>= 1000){
servoMini.attach(pinMini);
servoMini.write(180);
i++;
}
}
servoMini.detach();
myThread.run();
}
@John Cho, 👍2
Обсуждение2 ответа
Лучший ответ:
Вот окончательная форма моего проекта. Я добавил функцию отсоединения двигателя, так как он все еще немного дрожит.
#include <SoftwareSerial.h>
#include <Servo.h>
const int MPU_addr=0x68; // MPU-6050 I2C address
int16_t AcX,AcY,AcZ,GyX,GyY,GyZ;
SoftwareSerial BTSerial(3, 2); // TX, RX
Servo servoMini;
Servo servoUp;
Servo servoDown;
const byte pinMini = 6;
const byte pinUp = 9;
const byte pinDown = 10;
// Timings for each event.
const unsigned long ACC_INTERVAL = 50;
const unsigned long INTERVAL = 1000;
const unsigned long INTERVAL_FIN = 2000;
const unsigned long GRIPPER_INTERVAL = 2000;
const unsigned long GRIPPER_INTERVAL_FIN= 3000;
const unsigned long LED_INTERVAL = 250;
// Keep track of timestamps for each event.
unsigned long prev_led_timestamp;
unsigned long prev_acc_timestamp;
unsigned long servo_timestamp;
unsigned long servo_timestamp_fin;
unsigned long gripper_timestamp;
unsigned long gripper_timestamp_fin;
// Flags to indicate completion of "just once" events.
bool servo = false;
bool servo_fin = false;
bool gripper = false;
bool gripper_fin = false;
// State of blinking LED.
bool led_state = false;
void readAcc(){
Wire.beginTransmission(MPU_addr);
Wire.write(0x3B); // starting with register 0x3B (ACCEL_XOUT_H)
Wire.endTransmission(false);
Wire.requestFrom(MPU_addr,14,true); // request a total of 14 registers // 14bit??
AcX=Wire.read()<<8|Wire.read(); // 0x3B (ACCEL_XOUT_H) & 0x3C (ACCEL_XOUT_L)
//AcY=Wire.read()<<8|Wire.read(); // 0x3D (ACCEL_YOUT_H) & 0x3E (ACCEL_YOUT_L)
//AcZ=Wire.read()<<8|Wire.read(); // 0x3F (ACCEL_ZOUT_H) & 0x40 (ACCEL_ZOUT_L)
//GyX=Wire.read()<<8|Wire.read(); // 0x43 (GYRO_XOUT_H) & 0x44 (GYRO_XOUT_L)
//GyY=Wire.read()<<8|Wire.read(); // 0x45 (GYRO_YOUT_H) & 0x46 (GYRO_YOUT_L)
//GyZ=Wire.read()<<8|Wire.read(); // 0x47 (GYRO_ZOUT_H) & 0x48 (GYRO_ZOUT_L)
BTSerial.println(AcX); // 16bit
//Serial.println(AcX);
}
void setup(){
//Serial.begin(9600);
BTSerial.begin(9600);
// For blink without delay.
pinMode(LED_BUILTIN, OUTPUT);
// I2C
Wire.begin();
Wire.beginTransmission(MPU_addr);
Wire.write(0x6B); // PWR_MGMT_1 register
Wire.write(0); // set to zero (wakes up the MPU-6050)
Wire.endTransmission(true);
// servo
servoMini.attach(pinMini);
servoUp.attach(pinUp);
servoDown.attach(pinDown);
// Perform first move.
servoMini.write(145);
servoUp.write(180);
servoDown.write(0);
// Initialise all timestamps with the same value with a single call to millis().
prev_led_timestamp =
prev_acc_timestamp =
servo_timestamp = servo_timestamp_fin =
gripper_timestamp = gripper_timestamp_fin = millis();
}
void loop(){
unsigned long current_timestamp = millis();
// TASK 1: Read acc.
if (current_timestamp - prev_acc_timestamp >= ACC_INTERVAL){
// Read acc.
readAcc();
prev_acc_timestamp += ACC_INTERVAL;
}
// TASK 2: Just once.
if (!servo && current_timestamp - servo_timestamp >= INTERVAL) {
//Serial.print("Running just once... ");
servoUp.attach(pinUp);
servoDown.attach(pinDown);
servoUp.write(60);
servoDown.write(120);
// retract speed control
servo = true;
//Serial.println("Done.");
}
if (!servo_fin && current_timestamp - servo_timestamp_fin >= INTERVAL_FIN){
servoUp.detach();
servoDown.detach();
servo_fin = true;
}
// TASK 3: Also just once.
if (!gripper && current_timestamp - gripper_timestamp >= GRIPPER_INTERVAL) {
// Perform third move.
//Serial.print("Running also just once... ");
servoMini.write(180);
gripper = true;
//Serial.println("Done.");
}
if (!gripper_fin && current_timestamp - gripper_timestamp_fin >= GRIPPER_INTERVAL_FIN){
servoMini.detach();
gripper_fin = true;
}
// TASK 4: Blink without delay.
if (current_timestamp - prev_led_timestamp >= LED_INTERVAL){
// Toggle LED state.
led_state = !led_state;
digitalWrite(LED_BUILTIN, led_state);
prev_led_timestamp += LED_INTERVAL;
}
}
Я думаю, вам нужно что-то вроде Мигания Без задержки, но с большим количеством задач.
Вот моя интерпретация вашего описания, которая без промедления расширяет Blink, добавляя еще три задачи:
- считайте показания акселерометра
- выполните "всего один раз"
- выполните "также только один раз"
Я добавил несколько операторов Serial.print ()
, чтобы дать развернутый комментарий о том, что происходит, для целей отладки.
#include <Wire.h>
#include <SoftwareSerial.h>
#include <Servo.h>
SoftwareSerial BTSerial(3, 2); // TX, RX
Servo servoMini;
Servo servoUp;
Servo servoDown;
const byte pinMini = 6;
const byte pinUp = 9;
const byte pinDown = 10;
// Timings for each event.
const unsigned long READ_ACCELEROMETER_INTERVAL = 50;
const unsigned long JUST_ONCE_INTERVAL = 1000;
const unsigned long ALSO_JUST_ONCE_INTERVAL = 2000;
const unsigned long LED_BLINK_INTERVAL = 200;
// Keep track of timestamps for each event.
unsigned long previous_blink_timestamp;
unsigned long previous_accelerometer_timestamp ;
unsigned long just_once_timestamp;
unsigned long also_just_once_timestamp;
// Flags to indicate completion of "just once" events.
bool just_once = false;
bool also_just_once = false;
// State of blinking LED.
bool led_state = false;
void setup()
{
Serial.begin(115200);
Serial.println("\n\nAccelerometer with Servo Test\n");
// For blink without delay.
pinMode(LED_BUILTIN, OUTPUT);
// servo
servoMini.attach(pinMini);
servoUp.attach(pinUp);
servoDown.attach(pinDown);
// Perform first move.
servoMini.write(145);
servoUp.write(180);
servoDown.write(0);
// Initialise all timestamps with the same value with a single call to millis().
previous_blink_timestamp =
previous_accelerometer_timestamp =
just_once_timestamp =
also_just_once_timestamp = millis();
}
void loop()
{
unsigned long current_timestamp = millis();
//
// TASK 1: Read accelerometer.
//
if (current_timestamp - previous_accelerometer_timestamp >= READ_ACCELEROMETER_INTERVAL)
{
// Read accelerometer.
Serial.print("Reading accelerometer... ");
readAcc();
previous_accelerometer_timestamp += READ_ACCELEROMETER_INTERVAL;
Serial.println("Done.");
}
//
// TASK 2: Just once.
//
if (!just_once && current_timestamp - just_once_timestamp >= JUST_ONCE_INTERVAL)
{
// Perform second move.
Serial.print("Running just once... ");
servoUp.write(60);
servoDown.write(120);
just_once = true;
Serial.println("Done.");
}
//
// TASK 3: Also just once.
//
if (!also_just_once && current_timestamp - also_just_once_timestamp >= ALSO_JUST_ONCE_INTERVAL)
{
// Perform third move.
Serial.print("Running also just once... ");
servoMini.write(180);
also_just_once = true;
Serial.println("Done.");
}
//
// TASK 4: Blink without delay.
//
if (current_timestamp - previous_blink_timestamp >= LED_BLINK_INTERVAL)
{
// Toggle LED state.
led_state = !led_state;
digitalWrite(LED_BUILTIN, led_state);
previous_blink_timestamp += LED_BLINK_INTERVAL;
}
}
Ух ты! Это именно то, чего я хотел. Я никогда не думал об использовании логического типа. Большое спасибо! Кстати, могу я спросить вас, почему вы добавляете мигающий светодиод в конце?, @John Cho
@JohnCho, мигание светодиода не является существенным, но оно полезно для целей отладки, чтобы показать, что микроконтроллер не застыл - известный как [сигнал сердцебиения](https://en.wikipedia.org/wiki/Heartbeat_(вычисление)) или сигнал о признаке жизни. Кроме того, я опирался на пример _Blink Без задержки_, чтобы показать, как добавлять параллельные неблокирующие задачи., @tim
Спасибо! Теперь я лучше понимаю параллельные задачи. Кстати, извините за поздний комментарий., @John Cho
- Можно ли измерить скорость акселерометром? Насколько точно?
- Сервомотор и модуль Bluetooth блокируют друг друга
- Акселерометр Интернета вещей
- Сервопривод сохраняет свою позицию каждый раз, когда я отправляю какое-то значение
- Как создать несколько запущенных потоков?
- OVF в последовательном мониторе вместо данных
- Как заставить сервопривод вращаться на угол больше 180°
- Модуль Bluetooth HC-05 мигает красным светом - Arduino Uno
Ваша функция "loop ()" для меня не имеет смысла. Каковы ваши намерения в отношении этого кода?, @Majenko
Чтобы считывать значение с акселерометра (шина I2C) и обрабатывать/использовать эти показания для управления сервоприводом (bluetooth, возможно, в противоположном направлении?), @Pieterjan
Я думаю, вам, вероятно, придется взглянуть на DSP (цифровая обработка сигналов). Возможно [что-то вроде этого](https://www.dsprelated.com/freebooks/pasp/Time_Varying_Delay_Effects.html), но в последнее время я такими вещами не занимался. Вы действительно можете использовать поток для считывания значений и сохранения их в переменных, другой поток для dsp для задержки сигнала и третий для управления сервоприводом., @Pieterjan
@Majenko Я хочу, чтобы два двигателя, которые являются "servoUp" и "servoDown", двигались первыми только один раз. И через 1 секунду другой двигатель должен двигаться один раз. Поэтому я использовал " пока(я ==1)". Так как нужно проверить значение с помощью акклерометра, поэтому я снова использовал " MyThread.run ()", но я не уверен., @John Cho
@Pieterjan Акселерометр и двигатель не имеют значимой связи. Значение с датчика отправляется на компьютер и изменяется для отдельного анализа. Я собираюсь изменить угол, под которым движется двигатель, и скорость сервомотора, чтобы проверить разницу в ускорении., @John Cho