Сервообъект Arduino не работает в моей собственной библиотеке

Я написал библиотеку для кого-то еще, чтобы медленно перемещать сервоприводы из одного положения в другое. Это не сработало, как я хотел, и мне пришлось удалить сервообъекты из библиотеки. Вместо этого я позволяю новой версии вычислять положения сервоприводов и вместо этого возвращать эти значения. Тем не менее, я действительно хотел бы знать, почему это не работает.

Заголовочный файл с приватными объектами Servo

#include <Arduino.h>
#include <Servo.h>

class ServoSweep {

public:
    ServoSweep( byte _servoPin, byte _min, byte _max, byte _speed  ) ;        // constructor 1
    ServoSweep( byte _servoPin, byte _min, byte _max, byte _speed, byte _relayPin ) ;  // constructor 2
    void sweep( );
    void setState( uint8_t _state );

private:
    Servo servo ;
    unsigned long timeToRun ;
    byte pos ;
    byte state ;
    byte prevPos;
    byte servoPin ;
    byte servoSpeed ;
    byte servoMin ;
    byte servoMax  ;
    byte middlePosition ;
    byte relayPresent ;
    byte relayPin ;

} ;

И исходный файл:

#include "ServoSweep.h"

ServoSweep::ServoSweep( byte _servoPin, byte _min, byte _max, byte _speed ) {                   // constructor 1
    
    servoPin = _servoPin ;
    servoSpeed = _speed ;
    servoMin = _min ;
    servoMax = _max ;
   
    middlePosition = ( (long)servoMax - (long)servoMin ) / (long)2 + (long)servoMin ;               // start with middle position

    pos = middlePosition ;

    servo.write( pos ) ;
    servo.attach( servoPin ) ;
}

ServoSweep::ServoSweep( byte _servoPin, byte _min, byte _max, byte _speed, byte _relayPin ) {      // constructor 2
    
    servoPin = _servoPin ;
    servoSpeed = _speed ;
    servoMin = _min ;
    servoMax = _max ;

    middlePosition = ( (long)servoMax - (long)servoMin ) / (long)2 + (long)servoMin ;

    pos = middlePosition ;

    servo.write( pos ) ;
    servo.attach( servoPin ) ;

    relayPresent = 1;
    relayPin = _relayPin ;
    pinMode( relayPin, OUTPUT ) ;

}


void ServoSweep::sweep () {

    if( millis() > timeToRun ) {
        timeToRun = millis() + servoSpeed ;

        if( state ) {
            if( pos < servoMax ) pos ++ ;
        }
        else {
            if( pos > servoMin ) pos -- ;
        }

        if( prevPos != pos ) {
            prevPos  = pos ;

            if( relayPresent == 1 ) {
                if( pos < middlePosition ) digitalWrite( relayPin,  LOW ) ;
                else                       digitalWrite( relayPin, HIGH ) ;
            }
            servo.write( pos ) ;
        }
    }
}

void ServoSweep::setState( uint8_t _state ) {
    state = _state ;
}

Сигнал сервопривода был полным дрожанием, вызванным Arduino. Пример эскиза, который я использовал:


#include "ServoSweep.h"

const int inputButton = 12 ;
const int servoPin1 = 2 ;
const int servoPin2 = 3 ;

unsigned long prev ;
byte state ;

//                   pin   min max speed (bigger speed = slower movement ;
ServoSweep servo1(servoPin1, 10, 30, 50) ; 
ServoSweep servo2(servoPin2, 10, 30, 50) ; 

void setup() {
    pinMode( inputButton, INPUT_PULLUP ) ;
}

void loop() {
 
    servo1.sweep();
    servo2.sweep();

    if( digitalRead( inputButton ) ) servo1.setState( 1 ) ; 
    else                             servo1.setState( 0 ) ;

    if( digitalRead( inputButton ) ) servo2.setState( 0 ) ; 
    else                             servo2.setState( 1 ) ;
 
}

Даже если я закомментирую код внутри цикла, дрожание останется. Дрожание начинается, как только я создаю объекты ServoSweep.

Что я сделал не так с сервообъектами? Я предполагаю, что это должно быть возможно.


person bask185    schedule 30.08.2020    source источник


Ответы (1)


Проблема скорее всего в вашем конструкторе. Эти строки:

servo.write( pos ) ;
servo.attach( servoPin ) ;

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

Это распространенная проблема и распространенная ловушка для новичков. Конструкторы должны инициализировать переменные и устанавливать значения и прочее, но они не предназначены для работы с оборудованием. Для этого вам нужен метод begin() или init(), который вы можете вызвать из установки. Подумайте о том, как в библиотеке сервоприводов есть функция присоединения, которую вы должны вызывать из программы установки. Если бы это можно было сделать в конструкторе, конструктор взял бы номер вывода и сделал это. Подумайте о методе begin, который вы должны вызвать, чтобы Serial заработал. Это та же история, есть аппаратное обеспечение для настройки, и вы должны иметь возможность контролировать, когда это происходит.

Итак, сделайте еще один метод:

void ServoSweep::begin()  {
   servo.write( pos ) ;
   servo.attach( servoPin ) ;
}

И вызовите это из настройки для каждого объекта и удалите эти строки из конструктора.

person Delta_G    schedule 30.08.2020
comment
Я изменил код и проверю сегодня вечером. Это кажется очень логичным - person bask185; 31.08.2020