Выходной вывод Arduino выводит случайную активность

Я работаю над проектом Arduino, контролирующим самодельный RC- грузовик, который считывает выходные выводы RC-приемника и, соответственно, должен ШИМ на пару контактов. Штыри подключены к контроллеру двигателя, который принимает ШИМ.

Вот тут и возникает проблема. Мой реверс работает отлично, но на выводе, который работает вперед, я получаю только случайную активность. Я использую Arduino Mega 2560.

Вот код Проблема была опубликована ниже:

#include <Servo.h>

//Create variables for three channels
int RXCH[3];
volatile int RXSG[3];
int RXOK[3];
int PWMSG[3];

byte vooruit;
byte achteruit;

Servo stuur;

int mv = 13;
int ma = 10;

void setup() {
    Serial.begin(115200);
    stuur.attach(8);

    //Assign PPM input pins. The receiver output pins are conected as below to non-PWM Digital connectors:
    RXCH[0] = 6;  //Throttle
    RXCH[1] = 7;  //Steering
    //RXCH[2] = 5;  //Nothing yet
    //RXCH[3] = 2;  //Nothing yet
    //RXCH[4] = 7;  //Nothing yet
    //RXCH[5] = 8;  //Nothing yet

    for (int i = 0; i < 3; i++){
        pinMode(RXCH[i], INPUT);
    }

    //TCCR1B = TCCR1B & 0b11111000 | 0x01;
    //TCCR2B = TCCR2B & 0b11111000 | 0x01;
}

void loop() {
    // Read RX values
    for (int i = 0; i < 3; i++){                 //For each of the 6 channels:
        RXSG[i] = pulseIn(RXCH[i], HIGH, 20000); //Read the receiver signal
        if (RXSG[i] == 0) {                      //Error catching
            RXSG[i] = RXOK[i];
        } else {
            RXOK[i] = RXSG[i];
        }
        //Substitute the high values to a value between -255 and 255
        PWMSG[0] = map(RXSG[0], 1000, 2000, -255, 255);
        //Servo values, calibrated according to my steering servo.
        PWMSG[1] = map(RXSG[1], 1000, 2000, 24, 169);
        //Make sure that the value stays within the desired boundaries.
        constrain (PWMSG[i], -255, 255);

        //For debugginf purposes
        Serial.print(" ||   Ch: ");
        Serial.print(i);
        Serial.print(" / PWMSG: ");
        Serial.print(PWMSG[i]);
    }
    delay (5);

    // Car goes forwards
    if (PWMSG[0] > 40)
    {
        MV();
    }

    // Car goes backwards
    if (PWMSG[0] < -40)
    {
        MA();
    }

    // Car stops
    else
    {
        stopmotor();
    }

    stuur.write(PWMSG[1]);
    Serial.println();
}

void MV()
{
    vooruit = PWMSG[0];
    analogWrite (mv, vooruit);
    digitalWrite (ma, LOW);
    Serial.print("    vooruit: ");
    Serial.print(vooruit);
}

void MA()
{
    achteruit = abs(PWMSG[0]);
    analogWrite (ma, achteruit);
    digitalWrite (mv, LOW);
    Serial.print("    achteruit: ");
    Serial.print(achteruit);
}

void stopmotor()
{
    digitalWrite (ma, LOW);
    digitalWrite (mv, LOW);
}

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

Это один из моих первых проектов, которые я попытался сделать правильно, комментировать и все такое, вся хорошо прокомментированная критика приветствуется.

Что должен делать код:

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

Проблема:

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

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

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

#include <Servo.h>

//Create variables for channels

Servo wheel;

int MFORWARD_PIN = 13;
#define MBACKWARD_PIN 10
#define WHEEL_PIN 8

#define THROTTLE_PIN 6
#define STEERING_PIN 7

void setup() {
    Serial.begin(115200);
    wheel.attach(WHEEL_PIN);

    pinMode(THROTTLE_PIN, INPUT);
    pinMode(STEERING_PIN, INPUT);

    pinMode(MFORWARD_PIN, OUTPUT);
    pinMode(MBACKWARD_PIN, OUTPUT);

    //TCCR1B = TCCR1B & 0b11111000 | 0x01;
    //TCCR2B = TCCR2B & 0b11111000 | 0x01;
}

void loop() {
    int throttle = read_throttle();
    int steering = read_steering();
    delay (5);
    throttle_handle(throttle);
    steering_handle(steering);
}

// Read RX values
int read_throttle(){
    int throttle = pulseIn(THROTTLE_PIN, HIGH, 20000);
    throttle = map(throttle, 1000, 2000, -255, 255);    //Substitute the high values to a value between -255 and 255.
    constrain (throttle, -255, 255);                    //Make sure that the value stays within the desired boundaries.
    //Serial.println(throttle);
}

int read_steering() {
     int steering = pulseIn(STEERING_PIN, HIGH, 20000);
     steering = map(steering, 1000, 2000, 24, 169);     //Servo values, calibrated according to my steering servo.
     constrain (steering, 24, 169);                     //Make sure that the value stays within the disired boundaries.
     //Serial.println("steering");
}

void move_forward(int val) {
    analogWrite (MFORWARD_PIN, val);
    digitalWrite (MBACKWARD_PIN, LOW);
    Serial.print("    vooruit: ");
    Serial.print(val);
}

void move_backward(int val)
{
    val = abs(val);
    analogWrite (MBACKWARD_PIN, val);
    digitalWrite (MFORWARD_PIN, LOW);
    Serial.print("    achteruit: ");
    Serial.print(val);
}

void move_stop()
{
    digitalWrite (MFORWARD_PIN, LOW);
    digitalWrite (MBACKWARD_PIN, LOW);
}

void throttle_handle(int throttle) {
    //Serial.print("throttle");
    if (throttle > 40) {
        move_forward(throttle);
    }

    if (throttle < -40) {
        move_backward(throttle);
    }
    else {
        move_stop();
    }
}

void steering_handle(int steering) {
    wheel.write(steering);
    // Serial.println("steering:");
    // Serial.print(steering);
}

1 ответ

Решение
  • Неиспользованный индекс:

Везде вы перебираете три значения, а в массиве используете только два элемента. Так что вам лучше изменить все ваши размеры на 2 вместо 3, или вы можете определить NB_INPUT константа в верхней части исходного кода, которую вы можете легко изменить для большей гибкости:

#define NB_INPUT 2
...

for (int i = 0; i<NB_INPUT; ++i) {
...
  • RXOK в setup():

Ваш комментарий о массивах оправдан, первая ошибка, которую я вижу в вашем коде, это то, что вы читаете из RXOK массив, тогда как вы не поместили в него никаких значений. Если вы уверены, что RXSG получает только нули от pulseIn() на первом проходе Read RX values цикл это может быть хорошо, но я сомневаюсь, что это так. например:

for (int i=0; i<3; ++i)
    RXOK[i] = 0;

Таким образом, вы должны положить значения в RXOK значения в setup(),

  • постоянные индексы в цикле for:

Затем вы map() значения от 1000->2000 до -255->255 для RXSG[0] а также RXSG[1] внутри цикла for, что будет сделано за три итерации. Я не уверен, что вы хотите там, но если вы хотите сделать это для постоянных индексов, вам лучше сделать это вне цикла. Но поскольку вы проверяете ограничение на домен -255->255 для каждого значения цикла итерации, я думаю, что вы можете сделать это для относительных значений:

PWMSG[i] = map(RXSG[i], 1000, 2000, -255, 255);

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

#define THROTTLE_IDX 0
#define STEERING_IDX 1

и положить свой map() в операторе if:

if (i == THROTTLE_IDX)
    PWMSG[i] = map(RXSG[i], 1000, 2000, -255, 255);
elif (i == STEERING_IDX)
    PWMSG[i] = map(RXSG[i], 1000, 2000, 24, 169);
# add a else statement if you need to do a map for the other values of the array
constrain(PWMSG[i], -255, 255)
  • общий алгоритм

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

#define THROTTLE_PIN 6
#define STEERING_PIN 7
#define WHEEL_PIN    8
#define MFORWARD_PIN 13
#define MBACKWARD_PIN 10

Servo wheel;

// sets up the arduino
void setup() {
    Serial.begin(115200);
    wheel.attach(WHEEL_PIN);
    pinMode(THROTTLE_PIN, INPUT);
    pinMode(STEERING_PIN, INPUT);
}

// input data handling
int read_throttle() {
    int throttle = pulseIn(THROTTLE_PIN, HIGH, 20000);
    return map(throttle, 1000, 2000, -255, 255);
}

int read_steering() {
    int steering = pulseIn(STEERING_PIN, HIGH, 20000);
    return map(throttle, 1000, 2000, 24, 169);
}

// output actions handling
void move_forward(int val) {
    analogWrite(MFORWARD_PIN, val);
    digitalWrite(MBACKWARD_PIN, LOW);
    // Serial.print...
}

void move_backward(int val) {
    analogWrite(MFORWARD_PIN, val);
    digitalWrite(MBACKWARD_PIN, LOW);
    // Serial.print...
}

void stop_motor() {
    digitalWrite(MFORWARD_PIN, LOW);
    digitalWrite(MBACKWARD_PIN, LOW);
}

void handle_throttle(int throttle) {
    if (throttle > 40)
        move_forward(throttle);
    elif (throttle < -40)
        move_backward(throttle);
    else
        stop_motor();
}

// general algorithm
void loop() {
    int throttle = read_throttle();
    delay(5);
    handle_throttle(throttle);
}

Дублирования кода больше, но иногда лучше продублировать код, чем сделать код практически нечитаемым и трудным для отладки, не предлагая какой-либо гибкости / модульности. И вот несколько других вещей, которые я нашел в вашем коде, которые следует исправить:

  • Соглашение об именах: попробуйте использовать хорошие имена для своих функций (переменные из двух букв или голландские переменные не очень хорошая идея, я не являюсь носителем английского языка, и я всегда избегаю использовать в коде собственные имена, основанные на языке, даже для кода, который я не использую) t, вы никогда не знаете, кто будет читать ваш код через 2 дня, 2 месяца или 2 года).

  • глобальные: старайтесь избегать использования глобальных переменных в максимально возможной степени. Объявите только константу в глобальной области видимости: const int foo = 1; или препроцессор определяет #define foo 1, чтобы вы не тратили слишком мало места в оперативной памяти вашего arduino. Единственное исключение из этого правила, которое очень специфично для разработки Arduino, это объекты (например, Servo в вашем коде), что вам нужно объявить глобально, чтобы вы могли настроить их в setup() и использовать их в loop() функция.

Если я экстраполирую то, что вы написали, вы можете добавить handle_steering() функция, такая как:

void handle_steering(int steering) {
    if (steering > NN)
        turn_left(steering);
    elif (steering < NN)
        turn_right(steering);
    else
        keep_straight();
}

и измените цикл () на:

void loop() {
    int throttle = read_throttle();
    int steering = read_steering();
    delay(5);
    handle_throttle(throttle);
    handle_steering(steering);
}

Чтобы сделать более общий случай динамической и гибкой обработки ряда функций, вы можете сохранить несколько массивов:

  • PIN[]: содержащий штифты,
  • DOM_MIN[]: содержит минимум домена объектов (для карты),
  • DOM_MAX[]: содержит максимум домена объектов (для карты),
  • BOUND_MIN[]: содержит минимальные границы (для условия handle_steering),
  • BOUND_MAX[]: содержит максимальные границы (для условия handle_steering),
  • ACTION[]Содержит указатели на функции.

и тогда ваш алгоритм будет выглядеть так:

int read_input(int i) {
    int value = pulseIn(PIN[i], HIGH, 20000);
    return map(value, 1000, 2000, DOM_MIN[i], DOM_MAX[i]);
}

int handle_action(int i, int value) {
    if (value > BOUND_MIN[i])
        *(ACTION[i])(value);
    elif (value < BOUND_MAX[i])
        *(ACTION[i])(value);
    else
        *(ACTION[i])(-1);
}

void loop() {
    for (int i=0; i<NB_INPUTS; ++i) {
        int value = read_input(i);
        delay(5);
        handle_action(i, value);
    }
}

но так как вы все еще не чувствуете себя уверенно с массивами (и я предполагаю, что указатели тоже), я бы не советовал идти дальше таким образом в настоящее время. Сначала сделайте это просто и заставьте это работать, а затем вы можете попытаться факторизовать это, следуя идее, которую я раскрываю здесь. Но вы создаете встроенное программное обеспечение, в котором ОЗУ встречается редко, а вычислительная мощность мала, а объем вашего кода низок. Так что это один из немногих случаев, когда вам лучше захотеть сделать более избыточный код, который будет оставаться в программном пространстве, тогда как вы хотите манипулировать как маленькими символами в ОЗУ. Вот почему я не показываю вам, как массивы объявляются / определяются и как обрабатывать указатели функций, потому что я не думаю, что решение (куда вы направлялись) - это правильный способ сделать то, что вы хотите.

Всегда помните, чем проще, тем лучше!

НТН

Другие вопросы по тегам