Conflitto interrupt libreria Servo - IRremote [Risolto in parte]

Chiedo aiuto per risolvere questo problema, ammettendo la mia ignoranza, nonostante alcuni tentativi infruttuosi per cambiare le cose nella libreria Servo.
Tutto nasce da un mio progetto per un piccolo robot dove uso i motori servo a rotazione continua e voglio comandarlo con un telecomando da Tv.
La cosa funziona , per modo di dire, do un comando tipo avanti , esegue correttamente il comando ma non riceve più lo stop se non dopo diversi tentativi.
Monitorando da seriale , il comando viene recepito , ma con un codice sbagliato e da quando ho letto in altri thread, la libreria servo e la IRremote usano lo stesso interrupt 1 , quindi immagino sia quello.
Dato che ho una formazione di linguaggi ad alto livello, purtroppo nonostante i miei tentativi non sono riuscito ad individuare nel modo corretto la possibilità di variare l'interrupt o in una o nell'altra.
E' almeno possibile ?
Grazie

Ho dato un'occhiata alla Servo ma sull'Atmega328 usa un interrupt agganciato al timer 1, mentre la IRremote usa un interrupt agganciato al timer 2.

Non vedo l'uso dell'interrupt 1, che poi è un interrupt esterno, l'INT1, agganciato cioè ad un pin del micro,

Scrivi: "...a cosa funziona , per modo di dire, do un comando tipo avanti , esegue correttamente il comando ma non riceve più lo stop..."
Hai inserito nel codice il comando irrecv.resume(); ?

Come dice @leo, la IRremote usa il timer2, mentre la servo il timer1.
Però per capire la sequenza del comando da telecomando è importante la tempistica. Magari il tuo codice impegna troppo l'Arduino e "sballa" la tempistica.

Nella libreria Servo, puoi variare il timer usato facendo:
#define _useTimer4
In questo caso il 4, ma puoi fare 3,4 o 5 su Arduino Mega. Sulla Uno il timer è già diversa da IRremote.

La IRremote ha dato problemi (non risolti) anche a me usando la libreria TVout per pilotare una TV. Anche lì i timer sono diversi ma la tempistica è critica sia per generare il segnale per la TV che per interpretare correttamente il comando da remote. Infatti il segnale TV era sballato (immagine non perfetta) e i comandi da remote arrivano ma sballati, mal interpretati (anche @leo mi aiuto e mi disse che la tempistica era critica).

Purtroppo sì, quando si ha a che fare con segnali generati da una ISR qualunque cosa che interrompe la ISR altera questi segnali, e più l'applicazione è legata alla precisione di essi e meno devi interrompere la ISR.

Grazie per le sollecite risposte, ho avuto anch’io problemi di tempistica critica illustrati qui:

dove interpretavo un comando ir e trasmettevo un comando diverso, risolto mettendo opportuni delay
ma qui non riesco proprio a capire.
Il problema del timer è un po’ sviante infatti, ma mi sembrava fosse quello il nesso.
Allego la parte di decodifica IR dello sketch

// robot remote commands

#include <IRremote.h>                // IR remote control library

IRrecv irrecv(irReceivePin);

decode_results results;

// Command constants 

const char MOVE_FORWARD = 'f'; // move forward
const char MOVE_BACK    = 'b'; // move backward
const char MOVE_LEFT    = 'l'; // move left
const char MOVE_RIGHT   = 'r'; // move right 
const char PIVOT_CCW    = 'C'; // rotate 90 degrees CCW
const char PIVOT_CW     = 'c'; // rotate 90 degrees CW
const char PIVOT        = 'p'; // rotation angle (minus rotates CCW)
const char HALT         = 'h'; // stop

// not used in this example
const char MOVE_SPEED        = 's'; 
const char MOVE_SLOWER       = 'v'; // reduce speed 
const char MOVE_FASTER       = '^'; // increase speed 

//IR remote keycodes:
const long IR_MOVE_FORWARD = 16216207;
const long IR_MOVE_BACK    = 16220287;
const long IR_MOVE_LEFT    = 16187647;
const long IR_MOVE_RIGHT   = 16224367;
const long IR_PIVOT_CW     = 16208047;
const long IR_PIVOT_CCW    = 16203967;
const long IR_HALT         = 16232527;


int commandState = MOV_STOP;    // what robot is told to do

void remoteBegin(byte irPin)
{
  irrecv.enableIRIn(); // Start the receiver
}

void remoteService()
{
  if (irrecv.decode(&results)) 
  {
    if (results.decode_type != UNKNOWN)
    {
      Serial.println(results.value); // uncomment to see raw result
      convertIrToCommand(results.value);
    }
    irrecv.resume(); // Receive the next value
    }  
}

void convertIrToCommand(long value)
{
  {
   switch(value)
   {
    case  IR_MOVE_LEFT    :  processCommand(MOVE_LEFT);    break;
    case  IR_MOVE_RIGHT   :  processCommand(MOVE_RIGHT);   break;
    case  IR_MOVE_FORWARD :  processCommand(MOVE_FORWARD); break;
    case  IR_MOVE_BACK    :  processCommand(MOVE_BACK);    break;
    case  IR_PIVOT_CCW    :  processCommand(PIVOT_CCW);    break;
    case  IR_PIVOT_CW     :  processCommand(PIVOT_CW);     break;
    case  IR_HALT         :  processCommand(HALT);         break;
//    case  IR_SLOWER       :  processCommand(SLOWER);       break;
//    case  IR_FASTER       :  processCommand(FASTER);       break;
   }  
  }
} 
 
void changeCmdState(int newState)
{
  if(newState != commandState)
  {
    Serial.print("Changing Cmd state from "); Serial.print( states[commandState]);
    Serial.print(" to "); Serial.println(states[newState]);
    commandState = newState;
  } 
}

void processCommand(int cmd)
{
  int val = 0;
//  if( cmd == MOVE_SPEED) {
//    val =  Serial.parseInt();
//  }
//  else if( cmd == PIVOT) {
//    val =  Serial.parseInt();
//  }
  processCommand(cmd, val);
}

void processCommand(int cmd, int val)
{
  byte speed;
  //Serial.write(cmd); // uncomment to echo
  switch(cmd)
  { 
   case MOVE_LEFT    : changeCmdState(MOV_LEFT);    moveLeft();      break;
   case MOVE_RIGHT   : changeCmdState(MOV_RIGHT);   moveRight();     break;
   case MOVE_FORWARD : changeCmdState(MOV_FORWARD); moveForward();   break;
   case MOVE_BACK    : changeCmdState(MOV_BACK);    moveBackward();  break;
   case PIVOT_CCW    : changeCmdState(MOV_ROTATE);  moveRotate(-90); break;
   case PIVOT_CW     : changeCmdState(MOV_ROTATE);  moveRotate(90);  break;
   case PIVOT        : changeCmdState(MOV_ROTATE);  moveRotate(val); break; 
   case HALT         : changeCmdState(MOV_STOP);    moveStop();      break;
//   case MOVE_SPEED   : speed = val;    moveSetSpeed(speed);         break;
//   case SLOWER       : moveSlower(speedIncrement);                  break;
//   case FASTER       : moveFaster(speedIncrement);                  break;
   case '\r' : case '\n': break; // ignore cr and lf
   default :  Serial.print('['); Serial.write(cmd); Serial.println("] Ignored");  break;
  }    
}

spero sia interpretabile.
Premetto che sto usando delle librerie parametrizzate, prendendo spunto da questo libro:
Make an Arduino-Controlled Robot
Autonomous and Remote-Controlled Bots on Wheels
By Michael Margolis

dato che è interessante come propone l’uso delle librerie, volevo percorrere questa strada

Se non ho capito male, il primo comando lo capisce, il secondo è problematico.
Mi viene da pensare che dopo il primo comando di sicuro "attivi" o comunque "piloti" il servo, mentre prima del primo comando rispetto al servo non fai nulla.

Guardando dentro la libreria Servo, sembra che il write non agisce subito, ma imposta il valore in un vettore.
Poi, questo valore viene mandato al/ai servo quando scatta l'interrupt del timer1.
Se mentre scatta questo timer scatta anche il timer2 del IRremote, ho paura che ci siano difficoltà.

Infatti il primo comando lo becca subito, sono i seguenti che prende un po' a caso, alcune volte anche al primo impulso, altrimenti dopo vari tentativi.
Mi sa che i problemi sono troppi, le 2 librerie proprio non si "annusano" :smiley:

Ho risolto, non usando la libreria IRremote, ma usando del codice per soli telecomandi in modalità Sony, ho anche modificato la gestione della movimantazione dei motori,quindi pubblico lo sketch:

/*
 * Sony_IR_Shield_MioBot
 */
                                                                                
#include <Servo.h>                           // Include servo library
 
Servo servoLeft;                             // Declare left and right servos
Servo servoRight;
 
const int ServoLeftPin = 9;                 // I/O pin constants 
const int ServoRightPin =10;
const int IrDetPin = 11;
const int BeeperPin = 4;


const byte Enter = 11;                       // Non-alpha remote button constants
const byte ChUp = 16;
const byte ChDn = 17;
const byte VolUp = 18;
const byte VolDn = 19;
const byte Power = 21;

 
int irPulse;                                 // Stores pulses from IR detector
int remoteCode;                              // Stores code from remote
int mode = 1;                                // Stores mode

void setup()                                 // Setup runs once then loop takes over
{
  tone(BeeperPin, 3000, 1000);               // Play tone for 1 second
  delay(1000);                               // Delay to finish tone
 
}

void loop()                                  // Auto-repeats after setup
{
  int remoteCode = GetIrCode();              // Get code from remote
  
  // Note, detaching servos is nice because they stay still regardless of
  // whether or not they are calibrated.  This prevents them from turning 
  // gradually if they are out of calibration.
  if(remoteCode == -1)                       // If nothing, detach servos
  {
    if((servoLeft.attached()==true) && (servoRight.attached()==true))
    {
      servoLeft.detach();
      servoRight.detach();
    }
  }
  else                                       // Otherwise, remote code received,
  {                                          // so attach/re-attach them.
    if((servoLeft.attached()==false) && (servoRight.attached()==false))
    {
      servoLeft.attach(ServoLeftPin);
      servoRight.attach(ServoRightPin);
    }
  }  
  // Padding to ignore end of remote code before attempting to detect objects.
  // This sketch only collects first 7 of 12 remote bits.  So delay for the 
  // rest of the remote message is required before attempting object detection.
  // Otherwise, the remote's signaling would interfere with the IR object detection.
  delay(10); 
  
 // Decide what to do with the remote code.  Implement number pad control
  // and equivalent channel/volume control.
  switch(remoteCode)                         
  {
    case 1:                                  // 1 -> pivot left
       maneuver(0, 200, 20);               // Execute maneuver for at least 20 ms
      break;                                // If this case, then done, skip other cases.
      
    case 2:                                 // 2 button
    case ChUp:                              // or Channel up button
        maneuver(200, 200, 20);
      break;
      
    case 3:                                // 3 button
        maneuver(200, 0, 20);              // Pivot right for at least 20 ms
      break;
      
    case 4:                                // 4 button pressed
    case VolDn:                            // Or volume down button pressed
      maneuver(-200, 200, 20);             // Rotate left in place for at least 20 ms
      break;
      
    case 5:                                // 5 button pressed
      maneuver(0, 0, 20);                  // Stay still for at least 20 ms
      break;
      
    case 6:                                // 6 button pressed
    case VolUp:                            // or volume up button pressed
      maneuver(200, -200, 20);             // Rotate right in place at least 20 ms
      break;
      
    case 7:                                // 7 button pressed
      maneuver(0, -200, 20);               // Pivot backward-left for at least 20 ms
      break;
      
    case 8:                                // 8 button pressed
    case ChDn:                             // or channel down button pressed
      maneuver(-200, -200, 20);            // Back up for at least 20 ms
      break;
      
    case 9:                                // 9 button pressed
      maneuver(-200, -0, 20);              // Pivot backward-right for at least 20 ms
      break;
      
    // Whoa, somebody pressed power, to select a new mode.
    // Back to outer switch...case.  Take no action if timeout (-1) or any non mapped remote
    // code is received.
    default:                               
      servoLeft.detach();                
      servoRight.detach();
      break;
  }   
}                                          // Loop function auto-repeats at this point

/*
 * Check for and decode SONY TV remote messages coming from the IR TV detector in a TV set.
 * Returns: Code for button pressed on remote, or -1 if timeout (no code received).
 * Source: http://www.parallax.com/tabid/768/ProductID/149/Default.aspx
 * Modified for Arduino.
 */ 
int GetIrCode(){
  unsigned long irPulse = -1;                // Local variables    
  int irCode = 0;
  do{
    // Use pulseIn with 15 ms timeout if mode is roaming or following, or 50 ms timeout for control by TV remote.
    if((mode==3)||(mode==2)) irPulse = pulseIn(IrDetPin, LOW, 15000); else irPulse = pulseIn(IrDetPin, LOW, 50000); 
    // If timeout, return -1.
    if(irPulse==0) return -1;
  }while((irPulse <= 2000) || (irPulse >= 2800));
  // While condition filters for valid pulses and filters fluorescent ballast interference 
  
  // Capture first 7 of 12 bits from the remote.
  for(int i = 0; i <= 6; i++)
  {
    irPulse = pulseIn(IrDetPin, LOW, 2000);
    if((irPulse > 1000) && (irPulse < 1400)) bitSet(irCode, i);
  }

  // Convert alphanumeric codes to their corresponding button values.  
  if(irCode <= 9) irCode++;
  if(irCode == 10) irCode = 0;

  return irCode;
}

/*
 * Control BOE Shield-Bot servo direction, speed, set and forget version.
 * Parameters: speedLeft - left servo speed
 *             speedRight - right servo speed
 *             Backward  Linear  Stop  Linear   Forward
 *             -200      -100......0......100       200
 */ 
void maneuver(int speedLeft, int speedRight)
{
  // Call maneuver with just 1 ms blocking; servos will keep going indefinitely.
  maneuver(speedLeft, speedRight, 1);              
}

/*
 * Control BOE Shield-Bot servo direction, speed and maneuver duration.   
 * Parameters: speedLeft - left servo speed
 *             speedRight - right servo speed
 *             Backward  Linear  Stop  Linear   Forward
 *             -200      -100......0......100       200
 *             msTime - time to block code execution before another maneuver
 * Source:     http://learn.parallax.com/ManeuverFunction
 */ 
void maneuver(int speedLeft, int speedRight, int msTime)
{
  servoLeft.writeMicroseconds(1500 + speedLeft);   // Set Left servo speed
  servoRight.writeMicroseconds(1500 - speedRight); // Set right servo speed
  if(msTime==-1)                                   // if msTime = -1
  {                                  
    servoLeft.detach();                            // Stop servo signals
    servoRight.detach();   
  }
  delay(msTime);                                   // Delay for msTime
}