Go Down

Topic: RC Receiver: ENTWEDER Lenken ODER Gas geht/beides GLEICHZEITIG aber nicht (Read 211 times) previous topic - next topic

demcoderseinnachbar

Hallo zusammen,
ich habe inzwischen den Empfänger am Arduino und leite die Daten dann an Motor und Steuerungservo weiter. Das funktioniert allerdings nur solange ich ENTWEDER steuere ODER beschleunige. Lenken UND beschleunigen geht nicht.

Der Empfänger ist ein Jamara CCX/SCX 2,4 GHZ, Servo ist Jamara Aqua7 MG Ord.No. 074430, der Speedregler ist auch von Jamara Art-NR. 08 1468.

Schaltplan fürs Arduino: im Anhang.

Und der Code:

Code: [Select]
#define STEERING_SERVO_MAX_WAVELENGTH 3200
#define STEERING_SERVO_NEUTRAL_FREQUENCY 1500
#define STEERING_SERVO_OVERRIDE_FREQ_TOLERANCE 80
#define STEERING_SERVO_OVERRIDE_MIN -250
#define STEERING_SERVO_OVERRIDE_MAX 250
// Servo geht von 0 bis 180. Mittelstellung bei 90
#define STEERING_SERVO_MIN 30
#define STEERING_SERVO_MAX 150

// http://forum.arduino.cc/index.php?topic=4265.0
// http://rcarduino.blogspot.de/2012/01/how-to-read-rc-receiver-with.html
#define THROTTLE_SERVO_MAX_WAVELENGTH 3200 // warum? nur ausprobiet!
#define THROTTLE_SERVO_NEUTRAL_FREQUENCY 1500
#define THROTTLE_SERVO_OVERRIDE_FREQ_TOLERANCE 80

// input pins
#define STEERING_SERVO_OVERRIDE_PIN 9
#define THROTTLE_SERVO_OVERRIDE_PIN 8

// output pins
#define STEERING_SERVO_PIN 5
#define THROTTLE_SERVO_PIN 4

#include <Servo.h>

int pos = 0;    // variable to store the servo position
Servo throttle, steering;

// the setup function runs once when you press reset or power the board
void setup() {
 Serial.begin(9600);
 Serial.println("V1.0\n");

 steering.attach(STEERING_SERVO_PIN);
 throttle.attach(THROTTLE_SERVO_PIN);
 //throttle.attach(THROTTLE_SERVO_PIN, 0, THROTTLE_SERVO_MAX_WAVELENGTH);
}

void handleOverride()
{
 // handle override servo
 int servoFreq = pulseIn(STEERING_SERVO_OVERRIDE_PIN, HIGH, STEERING_SERVO_MAX_WAVELENGTH);
 if (servoFreq != 0) { //if you get 0, ignore it as it is between the pulses
   //Serial.print("servoFreq:"); Serial.println(servoFreq);
   int servoDiff = servoFreq - STEERING_SERVO_NEUTRAL_FREQUENCY;
   if (abs(servoDiff) < STEERING_SERVO_OVERRIDE_FREQ_TOLERANCE) {
     steering.write((STEERING_SERVO_MAX - STEERING_SERVO_MIN)*0.5);
   } else {
     Serial.print("servoDiff:"); Serial.println(servoDiff);
     int angle = (float(servoDiff - STEERING_SERVO_OVERRIDE_MIN) / (STEERING_SERVO_OVERRIDE_MAX - STEERING_SERVO_OVERRIDE_MIN)) * (STEERING_SERVO_MAX - STEERING_SERVO_MIN) +  STEERING_SERVO_MIN;
     steering.write(angle);
   }
 }

 // handle override throttle
 int throttleFreq = pulseIn(THROTTLE_SERVO_OVERRIDE_PIN, HIGH, THROTTLE_SERVO_MAX_WAVELENGTH);
 if (throttleFreq != 0) {
   //Serial.print("throttleFreq:"); Serial.println(throttleFreq);
   int throttleDiff = throttleFreq - THROTTLE_SERVO_NEUTRAL_FREQUENCY;
   if (abs(throttleDiff) < THROTTLE_SERVO_OVERRIDE_FREQ_TOLERANCE) {
     throttle.writeMicroseconds(THROTTLE_SERVO_NEUTRAL_FREQUENCY);
   } else {
     Serial.print("throttleFreq:"); Serial.println(throttleFreq);
     throttle.writeMicroseconds(throttleFreq);
   }
 }
}

// the loop function runs over and over again forever
void loop() {
 handleOverride(); //look for an override signal and if it exists disable bluetooth input
}


Hatte jemand das Problem oder eine Idee woran das liegt oder wie ich dem Problem auf die Schliche komme?

HotSystems

Hatte jemand das Problem oder eine Idee woran das liegt oder wie ich dem Problem auf die Schliche komme?
ja schon öfter...
Es kommen immer zu wenig Informationen.

Was sollen wir mit deinen Angaben anfangen ?
U-Boot bauen ?

Was für einen Arduino ?
Was für einen Empfänger ?
Was für einen Motor ?
Was für einen Servo ?
Was für einen Sketch ?

Den Sketch in Code-Tags posten.

Verwende dazu die Schaltfläche </> oben links im Editorfenster.
Das kannst du auch nachträglich machen.
Dazu den Sketch markieren und die Schaltfläche klicken.


Damit wird dieser für alle besser lesbar.

Für alles andere Links posten. Und wenn du schnelle Hilfe erwartest, dann bitte Hyperlinks verwenden.


I2C = weniger ist mehr: weniger Kabel, mehr Probleme. 8)

demcoderseinnachbar

Sorry, berechtigter Einwand. Informationen habe ich oben nachgetragen - hoffe es ist alles da um geholfen zu werden :)

HotSystems

Sorry, berechtigter Einwand. Informationen habe ich oben nachgetragen - hoffe es ist alles da um geholfen zu werden :)
Nein, leider fehlen die Links zu den Produkten.
So müssen wir alle für dich suchen.
I2C = weniger ist mehr: weniger Kabel, mehr Probleme. 8)

demcoderseinnachbar


uwefed

pulseIn() ist eine blockierende Funktion wie delay().

Du hast den Servo und den ESC an pins 8 und 9 hängen in dem Sketch aber auf pin 9 und 10.

Was ist falsch?

Grüße Uwe

demcoderseinnachbar

Ok, Pins sind im Schaltplan einfach anders als in echt. Habe ich umgesteckt und im Code angepasst, damit es stimmt.

Bezüglich pulseIn - ich verstehe dann, warum es nicht geht. Verstehe ich es richtig, dass genau aus diesem Grund hier http://rcarduino.blogspot.de/2012/01/how-to-read-rc-receiver-with.html davon abgeraten wird und man attachInterrupt() etc benutzen soll?

DrDiettrich

Kann es sein, daß die Batteriespannung zusammenbricht, sobald Servo und Motor angesteuert werden?

Whandall

Bezüglich pulseIn - ich verstehe dann, warum es nicht geht. Verstehe ich es richtig, dass genau aus diesem Grund hier http://rcarduino.blogspot.de/2012/01/how-to-read-rc-receiver-with.html davon abgeraten wird und man attachInterrupt() etc benutzen soll?
Ja.

Quote
Don't Use Pulse In !
Was hat dich auf die Idee gebracht, diese Information einfach zu ignorieren?
Zumal ja schon ein Beispiel für einen Channel dabei ist...
Ah, this is obviously some strange usage of the word 'safe' that I wasn't previously aware of. (D.Adams)

demcoderseinnachbar

Kann es sein, daß die Batteriespannung zusammenbricht, sobald Servo und Motor angesteuert werden?
Hatte ich auch schon überlegt. Allerdings ist es so, dass z.B. der Motor weiterläuft, wenn ich den laufen lasse und dann lenke. Nur das lenken geht dann nicht. Wenn die Spannung zusammenbrechen würde, würde ich erwarten, dass auch die Motoransteuerung nicht mehr funktioniert oder?

Soweit ich die anderen Kommentare richtig verstehe, scheint das Problem einfach zu sein, dass pulseIn einfach blockiert und damit der andere Servo nicht mehr zum Zug kommt.

Ja.

Was hat dich auf die Idee gebracht, diese Information einfach zu ignorieren?
Zumal ja schon ein Beispiel für einen Channel dabei ist...
Naja ich wollte erstmal alles einfach halten und habe daher versucht Komplexität zu vermeiden. Ich habe es zu dem Zeitpunkt auch  nicht genau verstanden - aber nun macht es an sich Sinn.

Whandall

Je nach zu messendem Signal kann man auch mit der blockierenden Natur von pulseIn leben,
aber die Fernsteuerungs-PWM ist dafür wahrscheinlich zu langsam.

Das Beispiel finde ich etwas unglücklich, da der Messwert nicht automatisch aktualisiert wird,
sondern erst, nachdem er gelesen/bestätigt wurde.
Auch wurde darauf verzichtet digitalPinToInterrupt() zu benutzen, aber das ist eher ein Detail.

Der erste Punkt wird in der Fortsetzung korrigiert:
http://rcarduino.blogspot.de/2012/04/how-to-read-multiple-rc-channels-draft.html
Ah, this is obviously some strange usage of the word 'safe' that I wasn't previously aware of. (D.Adams)

demcoderseinnachbar

Vielen Dank für eure Hilfe. Mit Interrupt funtzt es!

Hier der angepasste Code:

Code: [Select]
// input pins
// Assign your channel in pins, these are pin numbers for use in digitalRead
#define THROTTLE_SERVO_OVERRIDE_PIN 2 // Pin 2 = Interrupt 0
#define STEERING_SERVO_OVERRIDE_PIN 3 // Pin 3 = Interrupt 1

// output pins
#define THROTTLE_SERVO_PIN 4
#define STEERING_SERVO_PIN 5

#include <Servo.h>

Servo servoThrottle, servoSteering;

// These bit flags are set in bUpdateFlagsShared to indicate which
// channels have new signals
#define THROTTLE_FLAG 1
#define STEERING_FLAG 2

// holds the update flags defined above
volatile uint8_t bUpdateFlagsShared;

// shared variables are updated by the ISR and read by loop.
// In loop we immediatley take local copies so that the ISR can keep ownership of the
// shared ones. To access these in loop
// we first turn interrupts off with noInterrupts
// we take a copy to use in loop and the turn interrupts back on
// as quickly as possible, this ensures that we are always able to receive new signals
volatile uint16_t unThrottleInShared, unSteeringInShared;

// These are used to record the rising edge of a pulse in the calcInput functions
// They do not need to be volatile as they are only used in the ISR. If we wanted
// to refer to these in loop and the ISR then they would need to be declared volatile
uint32_t ulThrottleStart, ulSteeringStart;

// simple interrupt service routine
void calcThrottle() {
  // if the pin is high, its a rising edge of the signal pulse, so lets record its value
  if(digitalRead(THROTTLE_SERVO_OVERRIDE_PIN) == HIGH) {
    ulThrottleStart = micros();
  } else {
    // else it must be a falling edge, so lets get the time and subtract the time of the rising edge
    // this gives use the time between the rising and falling edges i.e. the pulse duration.
    unThrottleInShared = (uint16_t)(micros() - ulThrottleStart);
    // use set the throttle flag to indicate that a new throttle signal has been received
    bUpdateFlagsShared |= THROTTLE_FLAG;
  }
}

void calcSteering()
{
  if(digitalRead(STEERING_SERVO_OVERRIDE_PIN) == HIGH) {
    ulSteeringStart = micros();
  } else {
    unSteeringInShared = (uint16_t)(micros() - ulSteeringStart);
    bUpdateFlagsShared |= STEERING_FLAG;
  }
}

// the setup function runs once when you press reset or power the board
void setup() {
  Serial.begin(9600);
  Serial.println("V1.1\n");

  servoThrottle.attach(THROTTLE_SERVO_PIN);
  servoSteering.attach(STEERING_SERVO_PIN);

  // using the PinChangeInt library, attach the interrupts
  // used to read the channels
  attachInterrupt(digitalPinToInterrupt(THROTTLE_SERVO_OVERRIDE_PIN), calcThrottle, CHANGE);
  attachInterrupt(digitalPinToInterrupt(STEERING_SERVO_OVERRIDE_PIN), calcSteering, CHANGE);
}

void handleOverride()
{
  // create local variables to hold a local copies of the channel inputs
  // these are declared static so that thier values will be retained
  // between calls to loop.
  static uint16_t unThrottleIn;
  static uint16_t unSteeringIn;
  // local copy of update flags
  static uint8_t bUpdateFlags;

  // check shared update flags to see if any channels have a new signal
  if (bUpdateFlagsShared)
  {
    noInterrupts(); // turn interrupts off quickly while we take local copies of the shared variables

    // take a local copy of which channels were updated in case we need to use this in the rest of loop
    bUpdateFlags = bUpdateFlagsShared;
   
    // in the current code, the shared values are always populated
    // so we could copy them without testing the flags
    // however in the future this could change, so lets
    // only copy when the flags tell us we can.

    if (bUpdateFlags & THROTTLE_FLAG) {
      unThrottleIn = unThrottleInShared;
    }

    if (bUpdateFlags & STEERING_FLAG) {
      unSteeringIn = unSteeringInShared;
    }
   
    // clear shared copy of updated flags as we have already taken the updates
    // we still have a local copy if we need to use it in bUpdateFlags
    bUpdateFlagsShared = 0;

    interrupts(); // we have local copies of the inputs, so now we can turn interrupts back on
    // as soon as interrupts are back on, we can no longer use the shared copies, the interrupt
    // service routines own these and could update them at any time. During the update, the
    // shared copies may contain junk. Luckily we have our local copies to work with :-)
  }

  // do any processing from here onwards
  // only use the local values unThrottleIn and unSteeringIn, the shared
  // variables unThrottleInShared, unSteeringInShared are always owned by
  // the interrupt routines and should not be used in loop
 
  // the following code provides simple pass through
  // this is a good initial test, the Arduino will pass through
  // receiver input as if the Arduino is not there.
  // This should be used to confirm the circuit and power
  // before attempting any custom processing in a project.

  // we are checking to see if the channel value has changed, this is indicated
  // by the flags. For the simple pass through we don't really need this check,
  // but for a more complex project where a new signal requires significant processing
  // this allows us to only calculate new values when we have new inputs, rather than
  // on every cycle.
  if (bUpdateFlags & THROTTLE_FLAG) {
    if (servoThrottle.readMicroseconds() != unThrottleIn) {
      //Serial.print("unThrottleIn:"); Serial.println(unThrottleIn);
      servoThrottle.writeMicroseconds(unThrottleIn);
    }
  }
 
  if (bUpdateFlags & STEERING_FLAG) {
    if (servoSteering.readMicroseconds() != unSteeringIn) {
      //Serial.print("unSteeringIn:"); Serial.println(unSteeringIn);
      servoSteering.writeMicroseconds(unSteeringIn);
    }
  }

  bUpdateFlags = 0;
}

// the loop function runs over and over again forever
void loop() {
  handleOverride(); // look for an override signal
}

Go Up