Паук на ИК не реагирует на вторую команду

Ddt
Offline
Зарегистрирован: 07.12.2019

Добрый день.

решил повторить проект ringo.

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

собрал на nano, датчик висит на 2м пине (у автора аналоговый вход - у меня цифровой и датчик немного другой). команды принимает нормально если без двигателей смотреть на порту.

помогите понять что не так.

пробовал с прерываниями (поэтому на 2й линии оставил датчик - не как у автора), робот уже слушается команд но с переменным успехом.

хотелось бы понять что не так с оригинальным кодом.

 

*******************************************************

Клапауций 003
Offline
Зарегистрирован: 20.07.2019

вот эти библиотеки

#include "IRremote.h"
#include <Servo.h>

конфликтуют - подробности в тырнетах

Ddt
Offline
Зарегистрирован: 07.12.2019

Клапауций 003 пишет:

вот эти библиотеки

#include "IRremote.h"
#include <Servo.h>

конфликтуют - подробности в тырнетах

 

спасибо за быстрый ответ. поищу.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Ddt пишет:

хотелось бы понять что не так с оригинальным кодом.

Он неправильно вставлен в сообщение.

Ddt
Offline
Зарегистрирован: 07.12.2019
[code]



#include <IRremote.h>

// EN: We use special library to receive and decode commands from IR remote.
// RU: Подключаем специальную библиотеку, предоставляющую функции
//     приёма и передачи ИК-команд. Сайт проекта:
//     https://github.com/shirriff/Arduino-IRremote


#include "ir_command_codes.h"

#include <Servo.h>

// EN: Analog pin where IR detector is pluged in.
// RU: Аналоговый вход контроллера, к которму подключен ИК-приёмник.
const int IR_PIN = 2;

// EN: Servo pins.
// RU: Цифровые выводы контролера, к которым подключены серводвигатели.
const int LEFT_SERVO_PIN = 3;
const int CENTRAL_SERVO_PIN = 4;
const int RIGHT_SERVO_PIN = 7;

// EN: Servo "zero" angle positions.
// RU: Центральное ("нулевое") положение серводвигателей в градусах.
const long LEFT_SERVO_ZERO_VALUE = 90;
const long RIGHT_SERVO_ZERO_VALUE = 90;
const long CENTRAL_SERVO_ZERO_VALUE = 90;

// EN: Amplitude of left and right servos.
// RU: Амплитула левого и правого серводвигателей.
const long SIDE_SERVOS_FULL_AMPLITUDE = 30;
// EN: Half amplitude of left and right servos. Is used when robot is turning
//     left or right while moving forward or backward.
// RU: Уменьшенная амплитула левого и правого серводвигателей. Используется
//     при поворотах совмещённых с движением вперёд или назад.
const long SIDE_SERVOS_HALF_AMPLITUDE = 15;
// EN: Amplitude of central servo.
// RU: Амплитула центрального серводвигателя.
const long CENTRAL_SERVO_AMPLITUDE = 20;

// EN: Periods for different speeds.
// RU: Периоды колебаний для различных скоростей.
const long STEP_PERIOD_VERY_SLOW = 2000;
const long STEP_PERIOD_SLOW = 1500;
const long STEP_PERIOD_FAST = 1000;
const long STEP_PERIOD_VERY_FAST = 500;

long lastMillis;
long globalPhase;
float angleShiftLeftServo;
float angleShiftRightServo;
float angleShiftCentralServo;
long stepPeriod;
long amplitudeLeftServo;
long amplitudeRightServo;
long irkod;
boolean isAttached;
boolean isStopped;

// EN: IRrecv class performs the decoding.
// RU: Создаём объект ИК-приёмник. Этот объект принимает и декодирует ИК-сигналы от пульта.
IRrecv irrecv(IR_PIN);

Servo LeftServo;
Servo RightServo;
Servo CentralServo;

void attachServos() {
  if (!isAttached) {
    LeftServo.attach(LEFT_SERVO_PIN);
    RightServo.attach(RIGHT_SERVO_PIN);
    CentralServo.attach(CENTRAL_SERVO_PIN);
    isAttached = true;
  }
}

// EN: In some positions servos can make noise and vibrate.
//     To avoid this noise and vibration detach servos when robot is stopped.
// RU: В некоторых положениях серводвигатели могут вибрировать и шуметь.
//     Чтобы это избежать во время остановок робота, сервы надо отключать.
void detachServos() {
  if (isAttached) {
    LeftServo.detach();
    RightServo.detach();
    CentralServo.detach();
    isAttached = false;
  }
}

void setup() {
  // EN: Start the IR receiver.
  // RU: Начинаем прослушивание ИК-сигналов.
  irrecv.enableIRIn();
  Serial.begin(9600);   
  attachServos();
  isStopped = true;
  lastMillis = millis();

  angleShiftLeftServo = 0;
  angleShiftRightServo = 0;
  angleShiftCentralServo = 0;
  
  stepPeriod = STEP_PERIOD_FAST;
}

// EN: Gets angle for servo.
//     Param amplitude - amplitude of oscillating process,
//     param phaseMillis - current duration of oscillating,
//     param shiftAndle - phase of oscillating process.
// RU: Получение угла для серводвигателя.
//     Параметр amplitude - амплитуда колебаний,
//     Параметр phaseMillis - текущая продолжительность колебаний,
//     Параметр shiftAndle - фаза колебаний.
int getAngle(long amplitude, long phaseMillis, float shiftAngle) {
  float alpha = 2 * PI * phaseMillis / stepPeriod + shiftAngle;
  float angle = amplitude * sin(alpha);
  return (int)angle;
}

template<typename T,size_t N>
boolean hasCode(T (&commandCodes)[N], long code) {
  for (int i = 0; i < N; i++) {
    if (commandCodes[i] == code) {
      return true;
    }
  }
  return false;
}

void loop() {
  
  long millisNow = millis();
  long millisPassed = millisNow - lastMillis;
  if (isStopped) {
    // EN: We should wait for half a second. After that we think that servos are in zero
    //     position and we can detach them.
    // RU: Ждём полсекунды, чтобы серводвигатели вышли в нулевое положение и отключаем их.
    if (millisPassed >= 500) {
      lastMillis = 0;
      detachServos();
    }

    globalPhase = 0;
  } else {
    lastMillis = millisNow;
    
    globalPhase += millisPassed;
    globalPhase = globalPhase % stepPeriod;
  }
  
  // EN: Declaration of the structure that is used for received and decoded IR commands.
  // RU: Описываем структуру results, в которую будут помещаться
  //     принятые и декодированные ИК-команды:
  decode_results results;
  
  // EN: We can handle IR command if it is received and decoded successfully.
  // RU: Если команда успешно принята и декодирована, то мы можем её обрабатывать.
 
  if (irrecv.decode(&results)) {
    irkod=results.value;
    
    if (irkod > 0 && irkod < 0xFFFFFFFF) 
    { 
    if (hasCode(IR_COMMAND_FORWARD_CODES, irkod) ||
        hasCode(IR_COMMAND_FORWARD_LEFT_CODES, irkod) ||
        hasCode(IR_COMMAND_FORWARD_RIGHT_CODES, irkod)) {
    
      attachServos();
      isStopped = false;
      angleShiftLeftServo = 0;
      angleShiftRightServo = 0;
      angleShiftCentralServo = PI/2;
        
      amplitudeLeftServo = SIDE_SERVOS_FULL_AMPLITUDE;
      amplitudeRightServo = SIDE_SERVOS_FULL_AMPLITUDE;
      if (hasCode(IR_COMMAND_FORWARD_LEFT_CODES, irkod)) {
        amplitudeLeftServo = SIDE_SERVOS_HALF_AMPLITUDE;
      } else if (hasCode(IR_COMMAND_FORWARD_RIGHT_CODES, irkod)) {
        amplitudeRightServo = SIDE_SERVOS_HALF_AMPLITUDE;
      }
    } else if(hasCode(IR_COMMAND_BACKWARD_CODES, irkod) ||
              hasCode(IR_COMMAND_BACKWARD_LEFT_CODES, irkod) ||
              hasCode(IR_COMMAND_BACKWARD_RIGHT_CODES, irkod)) {

      attachServos();
      isStopped = false;
      angleShiftLeftServo = 0;
      angleShiftRightServo = 0;
      angleShiftCentralServo = -PI/2;

      amplitudeLeftServo = SIDE_SERVOS_FULL_AMPLITUDE;
      amplitudeRightServo = SIDE_SERVOS_FULL_AMPLITUDE;
      if (hasCode(IR_COMMAND_BACKWARD_LEFT_CODES, irkod)) {
        amplitudeRightServo = SIDE_SERVOS_HALF_AMPLITUDE;
      } else if (hasCode(IR_COMMAND_BACKWARD_RIGHT_CODES, irkod)) {
        amplitudeLeftServo = SIDE_SERVOS_HALF_AMPLITUDE;
      }
    } else if (hasCode(IR_COMMAND_TURN_LEFT_CODES, irkod)) {
      attachServos();
      isStopped = false;
      angleShiftLeftServo = 0;
      angleShiftRightServo = PI;
      angleShiftCentralServo = -PI/2;
      amplitudeLeftServo = SIDE_SERVOS_FULL_AMPLITUDE;
      amplitudeRightServo = SIDE_SERVOS_FULL_AMPLITUDE;
    } else if (hasCode(IR_COMMAND_TURN_RIGHT_CODES, irkod)) {
      attachServos();
      isStopped = false;
      angleShiftLeftServo = 0;
      angleShiftRightServo = PI;
      angleShiftCentralServo = PI/2;
      amplitudeLeftServo = SIDE_SERVOS_FULL_AMPLITUDE;
      amplitudeRightServo = SIDE_SERVOS_FULL_AMPLITUDE;
    } else if (hasCode(IR_COMMAND_STOP_CODES, irkod)) {
      attachServos();
      isStopped = true;
      angleShiftLeftServo = 0;
      angleShiftRightServo = 0;
      angleShiftCentralServo = 0;
      amplitudeLeftServo = SIDE_SERVOS_FULL_AMPLITUDE;
      amplitudeRightServo = SIDE_SERVOS_FULL_AMPLITUDE;
    } else if (hasCode(IR_COMMAND_VERY_SLOW_CODES, irkod)) {
      // EN: globalPhase correction to save servo positions when changing period.
      // RU: Корректировка globalPhase чтобы сохранить положение серв при смене периода колебаний ног.
      globalPhase = globalPhase * STEP_PERIOD_VERY_SLOW / stepPeriod;
      stepPeriod = STEP_PERIOD_VERY_SLOW;
    } else if (hasCode(IR_COMMAND_SLOW_CODES, irkod)) {
      globalPhase = globalPhase * STEP_PERIOD_SLOW / stepPeriod;
      stepPeriod = STEP_PERIOD_SLOW;
    } else if (hasCode(IR_COMMAND_FAST_CODES, irkod)) {
      globalPhase = globalPhase * STEP_PERIOD_FAST / stepPeriod;
      stepPeriod = STEP_PERIOD_FAST;
    } else if (hasCode(IR_COMMAND_VERY_FAST_CODES, irkod)) {
      globalPhase = globalPhase * STEP_PERIOD_VERY_FAST / stepPeriod;
      stepPeriod = STEP_PERIOD_VERY_FAST;
    }
    // EN: Once a code has been decoded, the resume() method must be called to resume receiving codes.
    // RU: После декодирования кода для продолжения приёма должен вызаваться метод resume().
   Serial.println(irkod);
   
    }
    irrecv.resume();
   
  }
   
  if (isAttached) {
    LeftServo.write(LEFT_SERVO_ZERO_VALUE + getAngle(amplitudeLeftServo, globalPhase, angleShiftLeftServo));
    RightServo.write(RIGHT_SERVO_ZERO_VALUE + getAngle(amplitudeRightServo, globalPhase, angleShiftRightServo));
    CentralServo.write(CENTRAL_SERVO_ZERO_VALUE + getAngle(CENTRAL_SERVO_AMPLITUDE, globalPhase, angleShiftCentralServo));
    if (irkod > 0 && irkod < 0xFFFFFFFF) { Serial.println(irkod);}
    
  }
 
}


[/code]

 

Ddt
Offline
Зарегистрирован: 07.12.2019

вот посмотрел код из библиотеки irremote- в методе irrecv

/ Interrupt Service Routine - Fires every 50uS
#ifdef ESP32
	// ESP32 has a proper API to setup timers, no weird chip macros needed
	// simply call the readable API versions :)
	// 3 timers, choose #1, 80 divider nanosecond precision, 1 to count up
	timer = timerBegin(1, 80, 1);
	timerAttachInterrupt(timer, &IRTimer, 1);
	// every 50ns, autoreload = true
	timerAlarmWrite(timer, 50, true);
	timerAlarmEnable(timer);
#else

тут используют для irremote.h таймер 2 а в серво

// Say which 16 bit timers can be used and in what order
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
#define _useTimer5
#define _useTimer1
#define _useTimer3
#define _useTimer4
typedef enum { _timer5, _timer1, _timer3, _timer4, _Nbr_16timers } timer16_Sequence_t;

#elif defined(__AVR_ATmega32U4__)
#define _useTimer1
typedef enum { _timer1, _Nbr_16timers } timer16_Sequence_t;

#elif defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB1286__)
#define _useTimer3
#define _useTimer1
typedef enum { _timer3, _timer1, _Nbr_16timers } timer16_Sequence_t;

#elif defined(__AVR_ATmega128__) || defined(__AVR_ATmega1281__) || defined(__AVR_ATmega1284__) || defined(__AVR_ATmega1284P__) || defined(__AVR_ATmega2561__)
#define _useTimer3
#define _useTimer1
typedef enum { _timer3, _timer1, _Nbr_16timers } timer16_Sequence_t;

#else  // everything else
#define _useTimer1
typedef enum { _timer1, _Nbr_16timers } timer16_Sequence_t;
#endif

у меня - Nano значит таймер 1.

получается не пересекаются таймеры и не должно быть конфликта?

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Не понял, сначала приводите код для ESP32, потом говорите, что у Вас Nano. Как-то в показаниях путаетесь.

Ddt
Offline
Зарегистрирован: 07.12.2019

ЕвгенийП пишет:

Не понял, сначала приводите код для ESP32, потом говорите, что у Вас Nano. Как-то в показаниях путаетесь.

ага не туда посмотрел

а какой таймер тогда далее  используется?

void  IRrecv::enableIRIn ( )
{
// Interrupt Service Routine - Fires every 50uS
#ifdef ESP32
	// ESP32 has a proper API to setup timers, no weird chip macros needed
	// simply call the readable API versions :)
	// 3 timers, choose #1, 80 divider nanosecond precision, 1 to count up
	timer = timerBegin(1, 80, 1);
	timerAttachInterrupt(timer, &IRTimer, 1);
	// every 50ns, autoreload = true
	timerAlarmWrite(timer, 50, true);
	timerAlarmEnable(timer);
#else
	cli();
	// Setup pulse clock timer interrupt
	// Prescale /8 (16M/8 = 0.5 microseconds per tick)
	// Therefore, the timer interval can range from 0.5 to 128 microseconds
	// Depending on the reset value (255 to 0)
	TIMER_CONFIG_NORMAL();

	// Timer2 Overflow Interrupt Enable
	TIMER_ENABLE_INTR;

	TIMER_RESET;

	sei();  // enable interrupts
#endif

2й? по комментариям вижу а где смотреть аналогичную функцию не понятно. подскажите плз.

Ddt
Offline
Зарегистрирован: 07.12.2019

а все нашел.- таймер 2

Ddt
Offline
Зарегистрирован: 07.12.2019

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

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

См. макрос TIMER_CONFIG_NORMAL. А, Вы уже посмотрели. Понятно.

Почему? Разве Servo не первый таймер использует?

Ddt
Offline
Зарегистрирован: 07.12.2019

да в серво 1 в ремот- 2. получается все ок - нет конфликта.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Так ото ж.

Ddt
Offline
Зарегистрирован: 07.12.2019

ЕвгенийП пишет:

Так ото ж.

а чего тогда не так с кодом?

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Не знаю.

Ddt
Offline
Зарегистрирован: 07.12.2019

ЕвгенийП пишет:

Не знаю.

тему можно закрыть. все заработало когда я стал использовать аналоговый порт контроллера. на цифровом порту наводилось все подряд в момент работы серв.возможно можно было бы подтянуть резисторы к цифровому порту для однозначного состояния его (0 или 1).