Как перемещать сервопривод с помощью функции

В настоящее время я перемещаю сервопривод с одной стороны на другую, используя типичный цикл for, подобный этому:

int lightON = 180;
int lightOFF = 90;

if (buttonState == HIGH) {

  digitalWrite(LED, HIGH);
  for (pos1 = lightOFF; pos1 <= lightON; pos1 += 1) {
    servo1.write(pos1);
    delay(15);
  }
  digitalWrite(LED, LOW);

}

Это означало бы перемещение сервопривода в одну сторону, и если я снова нажму кнопку, сервопривод переместится в другую сторону.

if (buttonState == LOW) {

  digitalWrite(LED, HIGH);
  for (pos1 = lightON; pos1 >= lightOFF; pos1 -= 1) {
    servo1.write(pos1);
    delay(15);
  }
  digitalWrite(LED, LOW);

}

Дело в том, что у меня есть тот же самый код в 3 других сервоприводах, и я не хочу повторять один и тот же код с 2 разными переменными (pos и сервопривод) снова и снова, поэтому я попытался

void runServoLight(int pos, int light1, int light2, Servo servo, int state) { 

  if (state == 1) {

  digitalWrite(LED, HIGH);

  for (pos = light1; pos <= light2; pos += 1) {
     servo.write(pos);
     delay(15);
  }

  digitalWrite(LED, LOW);

  } else if (state == 0) {

  digitalWrite(LED, HIGH);

  for (pos = light2; pos >= light1; pos -= 1) {
    servo.write(pos);
    delay(15);
  }

  digitalWrite(LED, LOW);

  }

}

Теперь вместо запуска всего кода цикла for я запускаю только:

runServoLight(pos1, lightON, lightOFF, servo1, 1);

Проблема в том, что это, похоже, не работает, и я могу понять, почему, возможно, я неправильно пишу функцию, но я не совсем уверен. Я был бы очень признателен за некоторую помощь. Спасибо!

, 👍3

Обсуждение

В вашей функции light1 должен быть ниже, чем light2. Похоже, вы их перепутали в звонке., @Mat


2 ответа


1

Вы написали:

void runServoLight(
        int pos, int light1, int light2, Servo servo, int state)

Здесь вы приводите список параметров, используемых функцией. В C++ параметры по умолчанию передаются по значению. Это означает, что при вызове функции аргументы, переданные в вызове, копируются в перечисленные здесь параметры, которые являются локальными переменными функции. Изменения этих параметров не будут распространяться на аргументы, предоставленные вызывающим.

Это может быть проблемой для объекта сервопривода. Этот объект сохраняет некоторое внутреннее состояние, в котором хранится память о текущей конфигурации таймеров. Поскольку вы работаете с копией предоставленного объекта, исходный объект не обновляется при работе с копией. Я не знаю , приводит ли это к неправильному поведению вашей программы, но было бы безопаснее передать объект Servo по ссылке:

void runServoLight(
        int pos, int light1, int light2, Servo &servo, int state)

Таким образом, объект не будет скопирован: вместо этого функция будет работать с исходным объектом, предоставленным вызывающим.

То же самое может относиться и к параметру pos. Самое первое, что функция делает с этим параметром, - это перезаписывает его. Тогда нет смысла получать это значение от вызывающего абонента. Вместо этого вы можете удалить параметр и создать локальную переменную с тем же именем:

void runServoLight(int light1, int light2, Servo &servo, int state) {
    int pos;  // локальная переменная
    ...
}

Если вы хотите, чтобы версия вызывающей переменной была обновлена, вы можете передать ее по ссылке, как и объект Servo. Однако более эффективно сохранить переменную локальной и заставить функцию возвращать конечную позицию. Тогда вызов будет выглядеть следующим образом:

pos1 = runServoLight(lightON, lightOFF, servo1, 1);

Один последний момент, который не виден в показанных вами фрагментах: вы выполняете обнаружение краев на кнопках? Обнаружение границ означает, что вы действуете по изменению состояния кнопок, а не по самим состояниям. Например, вы переходите от lightOFF к Lightton не тогда, когда состояние кнопки ВЫСОКОЕ, а когда оно становится ВЫСОКИМ.

,

0

Это не решение, однако, путем рафторинга оно делает ваш скетч более удобным для обслуживания, так как дублированный код удаляется:

void runServoLight(int pos, int light1, int light2, Servo servo, int state) 
{ 
  if (state == 1) {
    process(light1, light2, +1, servo);
  } 
  else if (state == 0) {
    process(light2, light1, -1, servo);
  }
}

def process(int this_light, int other_light, int delta, Servo servo)
{
  digitalWrite(LED, HIGH);
  for (pos = this_light; pos >= other_light; pos += delta) {
    servo.write(pos);
    delay(15);
  }
  digitalWrite(LED, LOW); 
}

Вместо целого числа состояния более понятно использовать перечисление и использовать оператор switch.

#include "Servo.h"

const int LED = 13;

enum EServoState { LEFT, RIGHT };

void runServoLight(int light1, int light2, Servo servo, EServoState state);

void setup() 
{
}

void loop() 
{
  int light1 = 1;
  int light2 = 2;
  EServoState state;
  Servo servo;
  runServoLight(light1, light2, servo, state);
}

void runServoLight(int light1, int light2, Servo servo, EServoState state) 
{ 
  switch (state)
  {
  case LEFT:
    process(light1, light2, +1, servo);
    break;
    
  case RIGHT:
    process(light2, light1, -1, servo);
    break;
  
  //default:
   // Handle program error
  }
}

void process(int this_light, int other_light, int delta, Servo servo)
{
  digitalWrite(LED, HIGH);
  for (int pos = this_light; pos >= other_light; pos += delta) 
  {
    servo.write(pos);
    delay(15);
  }
  digitalWrite(LED, LOW); 
}
,