Servo Position-Halten - Adruino Nano

CubaLibreee
Beiträge: 1947
Registriert: 08.09.2013 15:35:26

#61 Re: Servo Position-Halten - Adruino Nano

Beitrag von CubaLibreee »

Funzt! :mrgreen:
Benutzeravatar
frankyfly
Beiträge: 12239
Registriert: 09.07.2006 20:47:03

#62 Re: Servo Position-Halten - Adruino Nano

Beitrag von frankyfly »

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 .
CubaLibreee
Beiträge: 1947
Registriert: 08.09.2013 15:35:26

#63 Re: Servo Position-Halten - Adruino Nano

Beitrag von CubaLibreee »

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
Beiträge: 1947
Registriert: 08.09.2013 15:35:26

#64 Re: Servo Position-Halten - Adruino Nano

Beitrag von CubaLibreee »

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, HIGH, 35000); //Aufnahme der RC-Pulsweite
if(currPulse == 0)
{
currPulse = 1500; //Ausgabe des Neutralwertes, wenn kein gültiger Puls vorhanden
}


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

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


if ( abs (prevPulse - actPulse) <= 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;
}
Benutzeravatar
telicopter
Beiträge: 1864
Registriert: 09.12.2009 20:04:50
Wohnort: NRW, Krefeld...

#65 Re: Servo Position-Halten - Adruino Nano

Beitrag von telicopter »

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!
Thorsten S
Beiträge: 1
Registriert: 18.04.2017 22:34:34

#66 Re: Servo Position-Halten - Adruino Nano

Beitrag von Thorsten S »

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;
}


RC-Freak92
Beiträge: 1
Registriert: 17.10.2019 09:20:15

#67 Re: Servo Position-Halten - Adruino Nano

Beitrag von RC-Freak92 »

Hallo Leute
Ich habe mich mal etwas mit dem Arduino angefreundet.
Mein Vorhaben ist ein Bruder Minibagger mit Servos umzubauen.
Ein Bruder Bobcat habe ich schon mit anderen Modulen umgebaut.
Wenn Interesse besteht, dann stelle ich gerne ein paar Infos und Bilder ein.

Ich habe den Code von euch für 4 Servos umgewandelt, was auch alles klappt.
Im Moment kann man nur den Servoweg aller Servos verstellen.
Jetzt zur eigentlichen Frage: Gibt es eine Möglichkeit die Servowege für jedes Servo einzeln einstellen (Pulslänge)?
Z.B. Servo 1 MIN 950 MAX 1950
und Servo 2 MIN 1100 MAX 1800 usw.

Gruß Fabian
Wollus
Beiträge: 1
Registriert: 12.11.2019 21:33:44

#68 Re: Servo Position-Halten - Adruino Nano

Beitrag von Wollus »

Hallo Fabian,

bitte außerhalb von ebay meine mail ist wollus666@gmail.com.
Antworten

Zurück zu „Servos“