RHF Test www.brushlesstuning.de

Servo Position-Halten - Adruino Nano

Re: Servo Position-Halten - Adruino Nano

Beitrag #61 von CubaLibreee » 09.08.2018 17:14:23

Funzt! :mrgreen:
CubaLibreee
Benutzeravatar

 
Beiträge: 1934
Registriert: 8.9.2013
Danke gegeben: 23
Danke bekommen: 115

Re: Servo Position-Halten - Adruino Nano

Beitrag #62 von frankyfly » 28.08.2018 23:06:54

scheint ja soweit zu funktionieren. Sorry das ich aus Zeitmangel nichts Sinnvolles dazu beitragen konnte.

Ich habe aber noch eine Anmerkung zum Thema "in Hardware Umsetzen"

Der pfiffigste Weg währe hier vermutlich der abschied von Arduino IDE und deren doch recht eingeschränkten Bildbibliotheken und die direkte Verwendung der im Controller verbauten Peripherie wie Timer/Counter, Interrupt-System und DMA-Controller, allerdings ist der Atmega 328P damit nicht gerade reich bestückt (DMA: gar nicht, Timer: 2x8Bit und 1x16bit mit je 2x Output Compare Register, IRQ-System vorhanden) und gerade die 8Bit Counter dürften die Sache dann doch von der Funktionalität etwas einschränken .
frankyfly
Benutzeravatar
Mahatma Gandhi
Mahatma Gandhi
 
Beiträge: 17600
Alter: 36
Registriert: 9.7.2006
Wohnort: Freudenberg (NRW
Danke gegeben: 16
Danke bekommen: 56

Re: Servo Position-Halten - Adruino Nano

Beitrag #63 von CubaLibreee » 30.08.2018 05:54:12

frankyfly hat geschrieben:scheint ja soweit zu funktionieren. Sorry das ich aus Zeitmangel nichts Sinnvolles dazu beitragen konnte.

Ich habe aber noch eine Anmerkung zum Thema "in Hardware Umsetzen"

Der pfiffigste Weg währe hier vermutlich der abschied von Arduino IDE und deren doch recht eingeschränkten Bildbibliotheken und die direkte Verwendung der im Controller verbauten Peripherie wie Timer/Counter, Interrupt-System und DMA-Controller, allerdings ist der Atmega 328P damit nicht gerade reich bestückt (DMA: gar nicht, Timer: 2x8Bit und 1x16bit mit je 2x Output Compare Register, IRQ-System vorhanden) und gerade die 8Bit Counter dürften die Sache dann doch von der Funktionalität etwas einschränken .
Danke Frankyfly, ich versteh davon leider nur Bahnhof. Steuerung ist ganz cool, macht Spaß damit auf dem Tisch sich an die Steuerung zu gewoehnen. Brauch nur etwas granulat zum echten baggern.

Grüße aus Kuredu Island... :-)
CubaLibreee
Benutzeravatar

 
Beiträge: 1934
Registriert: 8.9.2013
Danke gegeben: 23
Danke bekommen: 115

Re: Servo Position-Halten - Adruino Nano

Beitrag #64 von CubaLibreee » 22.06.2019 16:25:48

Cuba braucht mal wieder Hilfe.

Auf dem Arduino Nano hat der scetch ja prima funktioniert. Jetzt hätte ich gerne eine abgespeckte Version mit:

-1 LED ON/OFF
-1 Servo Position halten

Und wenn das geht auf einem Arduino Micro: Klick

So sieht das für meine 2 Funktionen aktuell auf dem Nano aus:

#include <Servo.h>

#define LED_RC_PIN 4 //Empfänger LED-Steuerkanal D4
#define RC1_PIN 5 //Empfänger Steuer-Kanal D5 Lenkung
#define RC2_PIN 6 //Empfänger Steuer-Kanal D6
#define RC3_PIN 7 //Empfänger Steuer-Kanal D7

#define SERVO1_PIN 8 //Servosteuerleitung D8 Lenkung
#define SERVO2_PIN 9 //Servosteuerleitung D9
#define SERVO3_PIN 10 //Servosteuerleitung D10
#define LED_OUT_PIN 11 //LED Plus Steuerleidung D11

#define RC_MIN 1000 //Maximale und minimale Pulslänge
#define RC_MAX 2000
#define MAX_SPEED 15 //Maximale Geschwindigkeit bei Knüppelvollausschlag (Microsekunden-Inkrement je Berechnungsschritt)
#define RC_TOTZONE 50 //Totzone um die Knüppelmitte
#define RC_INPUT_TOLERANCE 35 //35 Toleranzbereich der RC-EIngangssignale in Microsekunden
#define LM_SIZE 2 //Breite des Laufenden Mittelwert-Filters

Servo servo_1;
Servo servo_2;
Servo servo_3;


unsigned int prevPulse [4] = {0, 0, 0, 0}; //letzte berechnete Pulsweite
unsigned int actPulse [4] ={0, 0, 0, 0}; //aktuelle berechnete Pulsweite
unsigned int LM[LM_SIZE][4]; // Letzte Messungen
unsigned int sum [4]= {0, 0, 0, 0}; //Summe aller Messungen
int channelPin[4] = {RC1_PIN, RC2_PIN, RC3_PIN, LED_RC_PIN}; //Array mit den Servobelegungen
unsigned int servoPosition[4] = {1500, 1500, 1500, 1500}; //aktuelle Servoposition als Pulsweite
byte index = 0; //Position im Array der Messwerte



void setup()
{
servo_1.attach(SERVO1_PIN);
servo_2.attach(SERVO2_PIN);
servo_3.attach(SERVO3_PIN);

InitializeLMArray(); //Initialisierung der Filterfunktion
pinMode (LED_OUT_PIN, OUTPUT);

Serial.begin(115200);
}


void loop()
{
readChannelFiltered();
LEDcontrol(actPulse[3]);
}



/*****************************************************************************************************************************
// Funktion zum Simulieren der Hydraulik-Eigenschaften
//
*****************************************************************************************************************************/
unsigned int Hydraulik(int pulse, int servoNr )
{
if (abs( pulse - 1500) <= RC_TOTZONE) //Anpassung der RC-Totzone in der Knüppelmitte
{
pulse = 1500;
}

int correction = map(pulse, RC_MIN, RC_MAX, -MAX_SPEED, MAX_SPEED);
servoPosition[servoNr] += correction;

if ( servoPosition[servoNr] <= RC_MIN )
{
servoPosition[servoNr] = RC_MIN;
}
if ( servoPosition[servoNr] >= RC_MAX)
{
servoPosition[servoNr] = RC_MAX;
}
return servoPosition[servoNr];
}



/*****************************************************************************************************************************
// Funktion zum Auslesen und Filtern der RC-Eingangskanäle mithilfe eines laufenden Mittelwertfilters
//
*****************************************************************************************************************************/
void readChannelFiltered()
{
unsigned int currPulse;

for (int i = 0; i <= 3 ; i++)
{
currPulse = pulseIn(channelPin[i], HIGH, 35000); //Aufnahme der RC-Pulsweite
if(currPulse == 0)
{
currPulse = 1500; //Ausgabe des Neutralwertes, wenn kein gültiger Puls vorhanden
}


sum [i] -= LM[index][i]; //Berechnung des gleitenden Mittelwertes
LM[index][i] = currPulse;
sum[i] += LM[index][i];

actPulse[i] = sum [i] / LM_SIZE; //Gleitender Mittelwert wird zur aktuellen Pulsweite


if ( abs (prevPulse[i] - actPulse[i]) <= RC_INPUT_TOLERANCE) //Unterdrückung von Servozittern durch die Einführung eines Toleranzbereiches
{ //Wenn neuer Wert innerhalb der Toleranz liegt, wird der alte Wert weiterverwendet
actPulse[i] = prevPulse[i];
}

prevPulse[i] = actPulse[i];

servo_1.writeMicroseconds(Hydraulik(actPulse[0], 0)); //Möglichst häufige Ansteuerung der Servos für einen flüssigeren Lauf
servo_2.writeMicroseconds(Hydraulik(actPulse[1], 1));
servo_3.writeMicroseconds(Hydraulik(actPulse[2], 2));
}

index++;
index = index % LM_SIZE;
}



/*****************************************************************************************************************************
// Funktion zum Ansteuern einer LED
//
*****************************************************************************************************************************/
void LEDcontrol(unsigned int LEDpulse)
{


if (LEDpulse >= 1500)
{
digitalWrite (LED_OUT_PIN, HIGH);
}
else
{
digitalWrite (LED_OUT_PIN, LOW);
}
}



/*****************************************************************************************************************************
// Initialisierungsfunktion zum Auffüllen aller Arraywerte
//
*****************************************************************************************************************************/
void InitializeLMArray()
{
while ( index < LM_SIZE)
{
unsigned int currPulse;

for (int i = 0; i <= 3 ; i++)
{

currPulse = pulseIn(channelPin[i], HIGH, 25000); //Aufnahme der RC-Pulsweite
if(currPulse == 0)
{
currPulse = 1500; //Ausgabe des Neutralwertes, wenn kein gültiger Puls vorhanden
}

sum [i] -= LM[index][i]; //Berechnung des gleitenden Mittelwertes
LM[index][i] = currPulse;
sum[i] += LM[index][i];

actPulse[i] = sum [i] / (index + 1 ); //Gleitender Mittelwert wird zur aktuellen Pulsweite


if ( abs (prevPulse[i] - actPulse[i]) <= RC_INPUT_TOLERANCE) //Unterdrückung von Servozittern durch die Einführung eines Toleranzbereiches
{ //Wenn neuer Wert innerhalb der Toleranz liegt, wird der alte Wert weiterverwendet
actPulse[i] = prevPulse[i];
}

prevPulse[i] = actPulse[i];
}

servo_1.writeMicroseconds(1500); //Servoposition in Neutrallage halten bis Initialisierung beendet
servo_2.writeMicroseconds(1500);
servo_3.writeMicroseconds(1500);

index++;
}
index = 0;
}
CubaLibreee
Benutzeravatar

 
Beiträge: 1934
Registriert: 8.9.2013
Danke gegeben: 23
Danke bekommen: 115

Re: Servo Position-Halten - Adruino Nano

Beitrag #65 von telicopter » 24.06.2019 22:44:34

Hi,
ich kann mir das die Tage mal anschauen. Leider kann der Code nicht 1 zu 1 auf den ATTiny85 übertragen werden, da der Controller durch seinen 8bit Timer nicht die verwendete Servo Library unterstützt. Ich hatte mir vorhin schon mal einen ATTiny und das Oszi geschnappt, um etwas Alternatives auszuprobieren, aber das hat leider noch nicht geklappt.

Viele Grüße
Tim
Grüße Tim

Jeder LOGO hat ein "LOGO" Logo, ...ist doch logo!
Never run a changing System!
telicopter
Benutzeravatar

 
Beiträge: 1864
Alter: 23
Registriert: 9.12.2009
Wohnort: NRW, Krefeld...
Danke gegeben: 0
Danke bekommen: 18

Re: Servo Position-Halten - Adruino Nano

Beitrag #66 von Thorsten S » 25.09.2019 16:48:35

Hi Tim!

Wir kennen uns noch nicht. Ich bin allerdings auf der Suche nach einer Arduino Lösung für meine Baustelle über deinen Beitrag gestolpert.
Dein Beitrag lässt mich darauf schließen das du dich wohl ziemlich gut mit der Materie auskennst. Vielleicht hast du ja lust mal über die folgende Frage nachzudenken.
Wenn du das programmieren kannst finden wir sicher irgendwie zusammen.

In meinem Fall geht es um das Schild einer Pistenraupe und dies hat 6 Funktionen. (6 Servos die wie Hydraulikzilinder arbeiten)

Dein Code für die "Hydraulik" ist genau was ich brauche, aber mit zwei Kanälen, auf drei ebenen.

Der Kreuzknüppel steuert die Servos.
Arduino Eingangskanal 1 - Kreuzknüppel Links Rechts
Arduino Eingangskanal 2 - Kreuzknüppel Hoch Runter

Ein dritter Eingangskanal am Arduino bekommt Schaltinformationen von einem Ein Aus Ein Schalter. Dieser definiert also die drei ebenen.

Schalter oben - Kreuzknüppel steuert Servo 3 und Servo 4
Schalter mitte- Kreuzknüppel steuert Servo 1 und Servo 2
Schalter unten- Kreuzknüppel steuert Servo 5 und Servo 6

Würde mich freuen wenn ich mit dir eine Lösung für mein Projekt gefunden habe.

Freue mich auf deine Antwort.
LG

Thorsten



telicopter hat geschrieben:Ich habe das Ganze jetzt doch mal mit der Standard Servo Library durchgezogen. Mit ein wenig Filterung der Eingangswerte ist auf jeden Fall schon mal Ruhe bei den Servos. Das ganze geht natürlich etwas auf Kosten der Reaktionsfreudigkeit, aber da es sich um einen Bagger und keinen 3D-Heli handelt, sollte das wohl zu verkraften sein. :wink: Die Fahrgeschwindigkeit ist abhängig vom Knüppelausschlag ( Alle Einstellungen können in den Defines gemacht werden). Ich habe zwar versucht, die Servoposition möglichst oft zu aktualisieren, aber da die Ablaufgeschwindigkeit des Programms hier der begrenzende Faktor ist und die Positionsaktualisierung mit diskreten Werten erfolgt, lässt sich ein leichtes Ruckeln nicht verhindern. Je langsamer der Ausleger bewegt wird bzw. je langsamer das Servo reagiert, desto geringer ist das Ruckeln natürlich. Um hier noch zu optimieren, müsste der Code an gewissen Stellen noch etwas eingestampft und gesäubert werden, um die Updaterate entsprechend zu erhöhen. Oder einfach langsame Analogservos benutzen. :mrgreen:

Ihr könnt ja mal probieren, ob es bei euch auch läuft.


Grüße
Tim


Code: Alles auswählen

#include <Servo.h>

#define RC1_PIN 5       //Empfänger Steuer-Kanal D5
#define RC2_PIN 6       //Empfänger Steuer-Kanal D6
#define RC3_PIN 7        //Empfänger Steuer-Kanal D7
#define SERVO1_PIN 8    //Servosteuerleitung D8
#define SERVO2_PIN 9    //Servosteuerleitung D9
#define SERVO3_PIN 10    //Servosteuerleitung D10

#define RC_MIN  1000      //Maximale und minimale Pulslänge
#define RC_MAX  2000
#define MAX_SPEED 50      //Maximale Geschwindigkeit bei Knüppelvollausschlag (Microsekunden-Inkrement je Berechnungsschritt)
#define RC_TOTZONE 10     //Totzone um die Knüppelmitte
#define RC_INPUT_TOLERANCE 35     //Toleranzbereich der RC-EIngangssignale in Microsekunden
#define LM_SIZE 2         //Breite des Laufenden Mittelwert-Filters

Servo servo_1;
Servo servo_2;
Servo servo_3;

unsigned int prevPulse [3] = {0, 0, 0};    //letzte berechnete Pulsweite
unsigned int actPulse [3] ={0, 0, 0};      //aktuelle berechnete Pulsweite
unsigned int LM[LM_SIZE][3];              // Letzte Messungen
unsigned int sum [3]= {0, 0, 0};          //Summe aller Messungen
int channelPin[3] = {RC1_PIN, RC2_PIN, RC3_PIN};       //Array mit den Servobelegungen
unsigned int servoPosition[3] = {1500, 1500, 1500};   //aktuelle Servoposition als Pulsweite
byte index = 0;     //Position im Array der Messwerte



void setup()
{
  servo_1.attach(SERVO1_PIN);
  servo_2.attach(SERVO2_PIN);
  servo_3.attach(SERVO3_PIN);

  InitializeLMArray();    //Initialisierung der Filterfunktion
 
  Serial.begin(115200);
}

void loop()
{
  readChannelFiltered();
}

/*****************************************************************************************************************************
// Funktion zum Simulieren der Hydraulik-Eigenschaften
//
*****************************************************************************************************************************/
unsigned int Hydraulik(int pulse, int servoNr )
{
  if (abs( pulse - 1500) <= RC_TOTZONE)   //Anpassung der RC-Totzone in der Knüppelmitte
  {
    pulse = 1500;
  }
 
  int correction = map(pulse, RC_MIN, RC_MAX, -MAX_SPEED, MAX_SPEED);
  servoPosition[servoNr]  +=  correction;

  if ( servoPosition[servoNr] <= RC_MIN  )
  {
    servoPosition[servoNr] = RC_MIN;
  }
  if ( servoPosition[servoNr] >= RC_MAX)
  {
     servoPosition[servoNr] = RC_MAX;
  }
  return servoPosition[servoNr];
}

/*****************************************************************************************************************************
// Funktion zum Auslesen und Filtern der RC-Eingangskanäle mithilfe eines laufenden Mittelwertfilters
//
*****************************************************************************************************************************/
void readChannelFiltered()
{

   for (int i = 0; i <= 2 ; i++)
   {
      unsigned int currPulse = pulseIn(channelPin[i], HIGH, 25000);  //Aufnahme der RC-Pulsweite
      if(currPulse == 0)
      {
        currPulse = 1500;  //Ausgabe des Neutralwertes, wenn kein gültiger Puls vorhanden
      }
 
 
      sum [i] -= LM[index][i];    //Berechnung des gleitenden Mittelwertes
      LM[index][i] = currPulse;
      sum[i] += LM[index][i];

      actPulse[i] =  sum [i] / LM_SIZE;   //Gleitender Mittelwert wird zur aktuellen Pulsweite
     
     
      if ( abs (prevPulse[i] - actPulse[i]) <= RC_INPUT_TOLERANCE)    //Unterdrückung von Servozittern durch die Einführung eines Toleranzbereiches
      {                                                               //Wenn neuer Wert innerhalb der Toleranz liegt, wird der alte Wert weiterverwendet
         actPulse[i] = prevPulse[i];
      }
     
      prevPulse[i] = actPulse[i];
     
     servo_1.writeMicroseconds(Hydraulik(actPulse[0], 0)); //Möglichst häufige Ansteuerung der Servos für einen flüssigeren Lauf
     servo_2.writeMicroseconds(Hydraulik(actPulse[1], 1));
     servo_3.writeMicroseconds(Hydraulik(actPulse[2], 2));
   }
   
   index++;
   index = index % LM_SIZE;
}

/*****************************************************************************************************************************
// Initialisierungsfunktion zum Auffüllen aller Arraywerte
//
*****************************************************************************************************************************/
void InitializeLMArray()
{
  while ( index < LM_SIZE)
  {
   for (int i = 0; i <= 2 ; i++)
   {
   
      unsigned int currPulse = pulseIn(channelPin[i], HIGH, 25000);  //Aufnahme der RC-Pulsweite
      if(currPulse == 0)
      {
        currPulse = 1500;   //Ausgabe des Neutralwertes, wenn kein gültiger Puls vorhanden
      }
 
      sum [i] -= LM[index][i];    //Berechnung des gleitenden Mittelwertes
      LM[index][i] = currPulse;
      sum[i] += LM[index][i];

      actPulse[i] =  sum [i] / (index + 1 );   //Gleitender Mittelwert wird zur aktuellen Pulsweite
     
     
      if ( abs (prevPulse[i] - actPulse[i]) <= RC_INPUT_TOLERANCE)    //Unterdrückung von Servozittern durch die Einführung eines Toleranzbereiches
      {                                                               //Wenn neuer Wert innerhalb der Toleranz liegt, wird der alte Wert weiterverwendet
         actPulse[i] = prevPulse[i];
      }
     
      prevPulse[i] = actPulse[i];
   }

    servo_1.writeMicroseconds(1500); //Servoposition in Neutrallage halten bis Initialisierung beendet
    servo_2.writeMicroseconds(1500);
    servo_3.writeMicroseconds(1500);
   
   index++;
  }
  index = 0;
}


Thorsten S

 
Beiträge: 1
Registriert: 18.4.2017
Danke gegeben: 0
Danke bekommen: 0

Vorherige


RSS-Feed

Zurück zu Servos

Wer ist online?

Mitglieder in diesem Forum: 0 Mitglieder und 0 Gäste

cron