PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Minimallösung: Servo-Sensor



radbruch
08.02.2008, 00:32
Hallo

Die Idee: Was macht die Signalleitung des Servos, wenn kein Impuls ansteht?

Das Ergebniss: Mein RP6 erkennt, wenn ich mit dem Daumen gegen das Servohorn drücke:

http://i.ytimg.com/vi/fPnOa-c63zY/3.jpg (http://www.youtube.com/watch?v=fPnOa-c63zY) http://i.ytimg.com/vi/ADkI8TLyGUY/2.jpg (http://www.youtube.com/watch?v=ADkI8TLyGUY) http://i.ytimg.com/vi/RDQ292-rrWc/2.jpg (http://www.youtube.com/watch?v=RDQ292-rrWc)
http://www.youtube.com/watch?v=fPnOa-c63zY
http://www.youtube.com/watch?v=ADkI8TLyGUY
http://www.youtube.com/watch?v=RDQ292-rrWc

Als Timer für das Servo dient der ADC-Interrupt. Die Steuerleitung des Servos hängt an E_INT (XBUS Pin8) mit 10K gegen GND. Nach dem Impuls wird der Pin auf Eingang geschaltet und etwas verzögert wird dann der Wert eingelesen:

// Servo-Lastmessung am Steuerpin 7.2.2008 mic

// In der 20ms-Signalpause wird die Spannung am Steuerpin des Servos gemessen
// und ausgewertet. (Servoansteuerung kompatibel zur RP6-Lib durch ADC-ISR)

#include "RP6RobotBaseLib.h"

uint8_t adc_pos, adc_count; // Position des Servos, Belastungszähler
uint16_t adc_servo; // Messwert der Signalleitung

void servo_ON(void) // Servo-ISR starten
{
cli();
// Freeruning, 5V-Ref, ISR enable, prescale /16
// AVCC with external capacitor at AREF pin, Ergebniss rechtsbündig, Kanal ADC4 (E_INT)
ADMUX = (0<<REFS1) | (1<<REFS0) | (0<<ADLAR) | 4;
// setzte free running triggern
SFIOR = (0<<ADTS2) | (0<<ADTS1) | (0<<ADTS0);
// Interrupt ein, Wandler einschalten, prescaller /16
ADCSRA = (1<<ADIE) | (1<<ADEN) | (1<<ADPS2) | (0<<ADPS1) | (0<<ADPS0);
// Autotriggern bedeutet jetzt free running aktivieren, altes Flag löschen
ADCSRA |= (1<<ADATE) | (1<<ADIF);
// Initialisierung starten
ADCSRA |= (1<<ADSC);
// und noch die wohl eher unnötige Initiallesung
while (!(ADCSRA & (1<<ADIF)));
ADCSRA |= (1<<ADIF);
sei();
}

void servo_OFF(void) // Servo-ISR stoppen
{
cli();
// Initialize ADC: (Defaultsetup der RP6-Library)
ADMUX = 0; //external reference
ADCSRA = (0<<ADIE) | (0<<ADEN) | (1<<ADPS2) | (1<<ADPS1) | (1<<ADIF);
SFIOR = 0;
sei();
}

int main(void)
{
initRobotBase();
adc_pos=55; // 20-90 ist der Drehbereich der Servos
adc_servo=0; // Startwerte setzen
adc_count=0;
servo_ON(); // Servo-ISR starten

while(1){
if (adc_servo) // wenn die Messspannung größer 0 ist
{
if (adc_count < 255) adc_count++; // counter hochzählen
if (adc_count>4) setLEDs(63); // Schwelle für Belastung
}
else
{
adc_count=0; // keine Belastung
setLEDs(0); //
}
mSleep(200); // kurz warten
}
return 0;
}

ISR(ADC_vect)
{
static uint16_t count=0; // Zykluszähler
if (count>adc_pos) // Servoimpuls senden?
{
DDRA &= ~16; // nein: E_INT auf Eingang ohne PullUp
PORTA &= ~16;
if (count == adc_pos+100) // seit 100 Takten auf Eingang gesetzt,
{
adc_servo=ADC; // jetzt messen wir die Spannung!
}
}
else
{
DDRA |= 16; // Impuls senden, Pin auf Ausgang
PORTA |= 16; // und high
}
if(count<1000) count++; else count=0; // Zyklus fertig?
}
(Ansteuerung des Servos wie in RN-Wissen beschrieben.)

Gruß

mic

rp6flash
09.02.2008, 10:12
servus,
ganz schön clever die sache.

ich hab bei youtube andere videos entdeckt, auch die mit der jukebox und wollt mal fragen ob du die codes noch hast?

wenn ja poste sie doch

danke

radbruch
09.02.2008, 13:15
Hallo

Zur RP6-Jukebox:

Meist verlinke ich den endsprechenden Thread bei meinen Filmchen:
https://www.roboternetz.de/phpBB2/viewtopic.php?p=339495#339495

Der Zugriff auf's Flash ist nicht so einfach, denn nur aus dem Loaderbereich heraus kann man darauf schreibend zugreifen. Die einzige Chance dafür wär wohl eine Funktion im Loader mit der man indirekt was ins Flash schreibt.

Mein aktueller Ansatz: Der RP6 sampled die Daten und sendet sie zum Terminal. Per Copy&Paste erzeugt man daraus ein Daten[]-Array und included es im Programm:


// RP6 als Tonband mit Aufnehmen und Abspielen (Daten im Flash) 1.1.2008 mic

#include "rblib.h" // bindet u.a io.h und stdlib.h ein
#include "rblib.c" // und dient vorrangig dem Debuggen
#define speichergroesse 2048 // Anzahl der einzulesenden Bytes

int main(void)
{
uint8_t daten[]="";
uint8_t temp, bit_nr; // Speicherplatz bereitstellen
uint16_t byte_nr, i, dummy; // und ein paar Hilfsvariablen

rblib_init(); // ein paar Initialisierungen
setMotorPWM(0,0); // PWM0= sterrt den PWM-Interrupt
PORTA &= ~(1 << PINA4); // PINA4 liest die Daten ein
DDRA &= ~(1 << PINA4); // PullUp PINA4 aus
DDRC |= (1 << PINC0); // an PINC4 hängt der Speaker
byte_nr=speichergroesse; // Zähler für die Bytes
daten[0]=daten[0];

while(0) // Zum Einstellen des Pegels
{ // wird nicht verwendet
if (PINA & (1 << PINA4))
{
setLEDs(1);
PORTC |= (1 << PINC0);
writeInteger(255,16);
}
else
{
setLEDs(0);
PORTC &= ~(1 << PINC0);
writeInteger(0,16);
}
if (!temp--) writeString("\n\r");
} // Ende Testschleife

writeString("\n\rStart\n\r");
cli(); // Keine Störung zulassen, wir lesen ein
do // Schleife der Datenbytes
{
temp=0;
bit_nr=8; // acht Bit einlesen
do // Schleife der Bits
{
if (PINA & (1 << PINA4)) // Pegel als High erkannt?
{
setLEDs(1); // Ja, LED an
PORTC |= (1 << PINC0); // Speaker an
temp += 1; // und Bit0 im Datenbyte setzen
}
else
{
setLEDs(0); // Nein, LED aus
PORTC &= ~(1 << PINC0); // Speaker aus
temp += 0; // für's Timing Bit0 nicht setzen
}
if (--bit_nr) // alle Bits komplett?
{
temp *= 2; // Speicherbyte nach links shiften
//for(i=0;i<100;i++) dummy+=i; // kurze Verzögerung (8MHz!)
if (byte_nr % 32)
{
if (bit_nr == 6) writeString(",");
if (bit_nr == 4) writeString("&");
if (bit_nr == 2) writeString("H");
}
else
{
if (bit_nr == 6) writeString(",\\");
if (bit_nr == 4) writeString("\n");
if (bit_nr == 2) writeString("&H");
}
}
else
{
writeInteger(temp,16); // Fertig, Byte als Hex senden
}
}
while(bit_nr); // Wenn nötig, nächstes Bit einlesen
}
while(--byte_nr); // nächstes Byte bis Speicher voll
sei(); // eigentlich nicht nötig
writeString("\n\rFertig\n\r");

return(0); // das war's. Einfach und blechern
}

Gruß

mic

Michael
09.02.2008, 14:14
Hallo radbruch,


Die Idee: Was macht die Signalleitung des Servos, wenn kein Impuls ansteht?

Das Ergebniss: Mein RP6 erkennt, wenn ich mit dem Daumen gegen das Servohorn drücke:
was mißt du denn am Servopin?
Steigt die Spannung? Wenn ja, um welchen Betrag?

Gruß, Michael

robo.fr
09.02.2008, 14:26
Hallo radbruch,

Ähm, der Zusammenhang, dass die Spannung am Stuerpin von der Last beeinflusst wird, ist mir nicht klar.
Da wäre es doch interessant zu wissen: was ist die Ursache? Sinkt durch die Belastung des Servos die gesammte Versorgungsspannung des Roboters ab und kann diese dann gemessen werden? Tritt der Effekt nur bei einem bestimmten Typ von Servo auf? Hängt es von der Innenschaltung des Servos ab? Welcher Hersteller, Typ ist das Servo genau?

Wie bist Du denn auf die Idee gekommen, so etwas auszuprobieren?

Gruß,
robo

radbruch
09.02.2008, 19:47
Hallo


Wie bist Du denn auf die Idee gekommen, so etwas auszuprobieren?
Über eine gedankliche Strommessung an der 5V-Leitung. Dabei fiel mir dann auf, dass der Steuerpin intern ja weder zu + noch zu - verbunden sein kann, bei Belastung also möglicherweise etwas zu messen wäre. Nach ein paar Timeingversuchen beim Einlesen der Spannung klappt es nun ganz gut. Die Verzögerung im Demo kommt vom relativ langem Verzögern zwischen den Auswertungen in der Hauptschleife (5*200ms). Da kann man aber noch einiges rausholen, das sind noch die allerersten Versuche.

Zum Messzeitpunkt: Innerhalb der 20ms-Zyklen wird erst der Impuls ausgegeben, dann kurz gewartet und dann erst der Wert eingelesen. Mit 5V-Referenz, schnellem Prescaler /16 (bei 8MHz-Kontrollertakt. Der ADC-Interrupt ist gleichzeitig der Timer für die Servointerrupts.) und 10Bit-Sampling lese ich Spitzenwerte von ca. 4.

Wichtig ist die kurze Wartezeit nach dem Impuls, denn es dauert bei dem verwendeten Takt bis zu 10 Aufrufe der ISR bis der Wert am Pin auf 0V sinkt. (Ich messe im Beispiel oben genau 100 Aufrufe nach dem Impuls) Der Wert bleibt auf 0 bis das Servo belastet wird. Beim Drehen ohne Last bleibt der Wert auch bei 0, aber möglicherweise kann man mit Last auch schon die Drehung selbst erkennen. Ich habe es auch noch nicht an einem freien ADC-Pin ausprobiert, in meinem Versuch ist ein 10k-PullDown verschaltet.

Bei mir funktioniert das mit den 5€-Miniservos und den 3€-Servos gut, mit den großen 5€-Servos funktioniert es noch nicht. Andere Typen stehen mir zum Testen nicht zur Verfügung. Anwenden möchte ich das bei einem Greifer, aber auch für Spinnenbeine dürfte das interesant sein.

Gruß

mic

Manf
09.02.2008, 20:31
Das ist sicher interessant und wichtig.
Ich bin mir nicht sicher wie weit die Sache untersucht ist und was ich davon richtig verstanden habe.

An die Steuerleitung eines Sevos wird wie üblich ein Signal mit einer Impulsdauer ausgegeben.
Abhängig von der Last ändert sich die Stromaufnahme des Servos und die Belastung ist am einfachsten(ohne weitere Schaltungen am deutlichsten ) an der Spannungsänderung auf der Signalleitung messbar.

Manfred

radbruch
09.02.2008, 22:08
Hallo Manfred

Ja, das trifft es im wesentlichen.

Was letztlich dazu führt, dass sich die Spannung an der Steuerleitung nach dem Impuls erhöht, kann ich im Moment noch nicht sagen. Auch ob das ein genereller Servo-Effekt ist oder ob das nur zufällig ein paar Servos machen weiß ich noch nicht. Man könnte es vermutlich auch mit dem Oszi sehen, wenn man darauf achtet. Die Spannung ist zwar recht klein, aber mit dem ADC eindeutig messbar. Ich werde mir mal die Ansteuerelektronik eines Servos genauer anschauen und natürlich werde ich auch mal versuchen, die Funktion sinnvoll anzuwenden.

Gruß

mic

robo.fr
09.02.2008, 22:19
Man könnte vielleicht einen relativ niederohmigen Widerstand ( 1 Ohm oä. ) in die Versorgungsleitung des Servos schalten und schauen, ob sich der Effekt verstärkt.

Manf
09.02.2008, 22:25
Vielen Dank erst einmal, ich denke dass es für das Herumtasten mit einem Bein, das den Boden erreichen soll, sehr hilfreich sein kann.

Mal sehen ob es noch jemand nachmisst, mit einem Shunt in der Versorgungsleitung sollte es natürlich grundsätztlich auch gehen.
Für die interaktive Führung eines Beins sind solche Signale sicher nötig.

Dass es jetzt auf der Steuerleitung am deutlichsten messbar ist, ist originell. Mal sehen wie weit es auf diese Weise geht.
Manfred

radbruch
10.02.2008, 23:18
Hallo

Ich habe den Code etwas umgestrickt. Der Impuls wird nun über einen 8bit-Timer per Interrupt erzeugt. In der Servo-ISR wird zum richtigen Zeitpunkt (der ist extrem wichtig!) das einmalige Wandeln des ADC angestoßen. Wenn die Wandlung beendet ist, wird in einer ADC-ISR das Ergebniss in adc_servo gespeichert. In der Hauptschleife wird dieser Wert mit LEDs ausgegeben (für den RP6):

// Servo-Lastmessung am Steuerpin 9.2.2008 mic

// In der 20ms-Signalpause wird die Spannung am Steuerpin des Servos gemessen
// und ausgewertet.

#include "rblib.h"
#include "rblib.c"

uint8_t adc_pos; // Position des Servos
uint16_t adc_servo; // Messwert der Signalleitung

void servo_ON(void) // Servo-ISR starten
{
cli();
TCCR0 = (0 << WGM00) | (1 << WGM01); // CTC-Mode
TCCR0 |= (0 << COM00) | (0 << COM01); // ohne OCR-Pin
TCCR0 |= (0 << CS02) | (0 << CS01) | (1 << CS00); // prescaler /1
TIMSK = (1 << OCIE0); // Interrupt ein
OCR0 = 105;

// 5V-Referenz, Kanal 0
ADMUX = (0<<REFS1) | (1<<REFS0) | 0;
// Interrupt ein, ADC enable, prescal /16, altes Flag löschen
ADCSRA = (1<<ADIE) | (1<<ADEN) | (1<<ADPS2) | (1<<ADIF);

sei();
}

int main(void)
{
rblib_init();
adc_pos=100; // Position der Servos
adc_servo=0; // Startwerte setzen
servo_ON(); // Servo-ISR starten

while(1)
{
setLEDs(adc_servo);
}
return 0;
}

ISR(ADC_vect)
{
adc_servo=ADC; // jetzt messen wir die Spannung!
}

ISR(TIMER0_COMP_vect)
{
static uint16_t count=0; // Zykluszähler
if (count>adc_pos) // Servoimpuls senden?
{
DDRA &= ~1; // nein: auf Eingang ohne PullUp
PORTA &= ~1;
if (count == adc_pos+100) // seit 100 Takten auf Eingang gesetzt,
{
ADCSRA |= (1<<ADSC); // ADC starten
}
}
else
{
DDRA |= 1; // Impuls senden, Pin auf Ausgang
PORTA |= 1; // und high
}
if(count<2000) count++; else count=0; // Zyklus fertig?
}


Hier noch eine Anwendung für einen 8MHz-Mega32 ohne RP6-Funktionen:


// Servo-Lastmessung am Steuerpin mit einem 8MHz-ATMega32 10.2.2008 mic

// In der 20ms-Signalpause wird die Spannung am Steuerpin des Servos gemessen
// und ausgewertet. Servoimpuls wird mit einem 8bit-Timer im CTC-Mode per ISR
// erzeugt. Kurz nach Ende des Impulses wird der ADC gestartet und der Messwert
// in einer ADC-ISR eingelesen.

#include <avr/io.h> // I/O Port definitions
#include <avr/interrupt.h> // Interrupt macros

// Position des Servos, Belastungszähler
uint8_t servo_pos;
// Messwert der Signalleitung, Verzögerung
volatile uint16_t servo_adc, servo_count, pause;

void init_servo(void) // Servo-ISR starten
{
cli();
TCCR0 = (0 << WGM00) | (1 << WGM01); // CTC-Mode
TCCR0 |= (0 << COM00) | (0 << COM01); // ohne OCR-Pin
TCCR0 |= (0 << CS02) | (0 << CS01) | (1 << CS00); // prescaler /1
TIMSK = (1 << OCIE0); // Interrupt ein
OCR0 = 105; // Servomitte=100?

// 5V-Referenz, Kanal 0
ADMUX = (0<<REFS1) | (1<<REFS0) | 0;
// Interrupt ein, ADC enable, prescaler /16, altes Flag löschen
ADCSRA = (1<<ADIE) | (1<<ADEN) | (1<<ADPS2) | (1<<ADIF);
sei();
}
void wait(uint8_t p)
{
pause=p;
while(pause);
}
int main(void)
{
servo_pos=100; // Position des Servos
servo_adc=-1; // Startwerte setzen
init_servo(); // Servo-ISR starten
wait(20);

while(1)
{
weiter2:
servo_pos+=2;
servo_count=0;
while((servo_pos++ < 200))
{
wait(1);
while(servo_count > 8)
{
if (servo_count > 15) goto weiter1;
}
}
weiter1:
servo_pos-=2;
servo_count=0;
while((servo_pos-- > 30))
{
wait(1);
while(servo_count > 8)
{
if (servo_count > 15) goto weiter2;
}
}
}
return 0;
}

ISR(ADC_vect)
{
servo_adc=ADC; // ADC-Messung beendet, Wert speichern
if (servo_adc) servo_count++; else servo_count /=2;

}

ISR(TIMER0_COMP_vect)
{
static uint16_t count=0; // Zykluszähler
if (count>servo_pos) // Servoimpuls senden?
{
DDRA &= ~1; // nein: auf Eingang ohne PullUp
PORTA &= ~1;
if (count == servo_pos+100) // seit 100 Takten auf Eingang gesetzt,
{
ADCSRA |= (1<<ADSC); // ADC starten
}
}
else
{
DDRA |= 1; // Impuls senden, Pin auf Ausgang
PORTA |= 1; // und high
}
if(count<2000) count++; else { // Zyklus fertig?
count=0;
if (pause) pause--;
}
}


und das Video dazu:
http://i.ytimg.com/vi/39tOx0IxQ40/1.jpg (http://www.youtube.com/watch?v=39tOx0IxQ40)
http://www.youtube.com/watch?v=39tOx0IxQ40

Der Steuerpin hängt dabei ohne weitere Beschaltung direkt am ADC-Pin. Gemessen habe ich Werte bis über 30. Direkt nach dem Impuls messe ich noch für einige Zyklen das High des Impulses, gegen Ende des Zyklus bleibt der Wert immer bei 0. Gut funktioniert's um 100, sogar mit diesem Müll-Code...

Gruß

mic

Thund3r
03.03.2010, 17:53
Hallo

Sehr interessantes Projekt!
Ich steuer meinen Servo über die M32 Erweiterung
mit folgender Methode an:

void ServoG(uint8_t pos)
{
DDRC |= IO_PC7;
PORTC |= IO_PC7;
sleep(pos);
PORTC &= ~IO_PC7;
sleep(185);
}

Ich habe mir deine Programme angeguckt aber leider nicht verstanden wann genau die ADC-Messung wie erfolgen muss.
Ich wollte über die M32 ADC-Kanäle messen.
Kannst du mir dies nochmal für mein Beispiel erklären?

Gruß Thund3r

radbruch
03.03.2010, 18:27
Hallo

Bei deiner Ansteuerung musst du während sleep(185); messen. Mein Messpunkt war 100 Einheiten nach dem Impulsende. Weil deine Sleep()-Ansteuerung um den Faktor 10 langsamer ist, würde ich etwa folgenden Messpunkt vorschlagen:

sleep(10);
readADC(kanal); // Nicht zusammen mit task_ADC() verwenden!
sleep(175);

Zusätzlich (noch vor demSleep(10);) musst du die Datenrichtung des Pins auf Eingang setzen!

In der RP6-Library wird der ADC mit externer Spannungsreferenz und Prescaler /64 verwendet, beim M32 weiß ich das nicht auswendig. Ich verwende die internen 5V und Prescaler /16. Vor allem das vielmal schnellere Wandeln der Spannung könnte wichtig für diese Servo-Sensor-Funktion sein. Vielleicht solltest du für die ersten Versuche dieses Setup übernehmen, bzw. Prescaler /32 bei 16MHz des M32.

Gruß

mic

Thund3r
03.03.2010, 18:45
Hallo

Ich hab die ADC-Messung zwischen die sleep gebaut.
Leider funktioniert es nicht. Er misst permanent 0.

Den Teil:



In der RP6-Library wird der ADC mit externer Spannungsreferenz und Prescaler /64 verwendet, beim M32 weiß ich das nicht auswendig. Ich verwende die internen 5V und Prescaler /16. Vor allem das vielmal schnellere Wandeln der Spannung könnte wichtig für diese Servo-Sensor-Funktion sein. Vielleicht solltest du für die ersten Versuche dieses Setup übernehmen, bzw. Prescaler /32 bei 16MHz des M32.

Hab ich nicht verstanden.

Könntest du mir das etwas genauer erläutern und mir erklärn wie ich weiter vorgehn kann?

Gruß Thund3r

radbruch
03.03.2010, 19:13
Hallo


Hab ich nicht verstanden.Ist eigentlich auch nicht wichtig. Da wir hier ja nur eine einzelne Messung machen, spielt das keine Rolle. Beim Start der Messung wird die Spannung in das Sample&Hold-Register kopiert und dann ist es unwichtig, wie schnell wir den Wert wandeln. Und da die Dauer der Wandlung (sie ist bei readADC() blockierend) auch mit Prescaler /64 das Timeing der Impulspause des Servos wohl nicht stört, kann man sicher auch das orginale ADC-Setup der M32-Lib verwenden. Sorry, war mein Fehler.


Ich hab die ADC-Messung zwischen die sleep gebaut.
Leider funktioniert es nicht. Er misst permanent 0.Vielleicht solltest du mal dein aufs nötigste reduzierte Programm zeigen. Aber nicht nur ein paar Fetzen sondern schon eine kompilierbare und lauffähige Version. Wie oben geschrieben funktioniert es auch nicht mit allen Servos.

Gruß

mic

Thund3r
03.03.2010, 19:19
Hallo

Also ich benutze den TOP-LINE MINI SERVO ES-05 JR von Conrad.

Meine Methoden sehen so aus:


void ServoG(uint8_t pos)
{
DDRC |= IO_PC7;
PORTC |= IO_PC7;
sleep(pos);
PORTC &= ~IO_PC7;
sleep(10);
messG();
sleep(175);
}

...

void messG()
{
uint16_t adc5 = readADC(ADC_5);
clearLCD();
setCursorPosLCD(0, 0);
writeStringLCD("Belastung: ");
writeIntegerLCD(adc5, DEC);
if(adc5>0)
{ setLEDs(0b1111);}
}
...

void gtest(void) // im Hauptprogramm aufgerufene Methode
{
int c;
setLEDs(0b0000);
for(c=0;c<=50;c++)
{
ServoG(12);
mSleep(20);
}

mSleep(1000);
for(c=0;c<=50;c++)
{
ServoG(21);
mSleep(20);
}

mSleep(1000);
setLEDs(0b0000);
}

Gruß Thund3r

radbruch
03.03.2010, 19:46
Hallo


Ich wollte über die M32 ADC-Kanäle messen. Und der ATMega32 im M32 hat seine ADC-Eingänge an Port C7? Was ist damit: "Zusätzlich (noch vor demSleep(10);) musst du die Datenrichtung des Pins auf Eingang setzen!"

Vergleiche doch mal was ich zwischen Sleep(10); und Sleep(175); vorgeschlagen habe und was du eingebaut hast. Die vom LCD vertrödelte Zeit kannst du am folgenden Sleep(175); möglicherweise wieder reinholen. Bewegt sich das Servo eigentlich?

Gruß

mic

Thund3r
03.03.2010, 20:25
Hallo

Der Port C7 ist ein IO Port (IO_PC7; )

ADC_5 ist mein ADC-kanal den ich benutze.

Ah "...musst du die Datenrichtung des Pins auf Eingang setzen!"

Nun funktioniert es.
Vielen Dank für deine Unterstützung!

Nun möchte ich meinen Greifer mit dem Programm aufpeppn so dass der Greifer wenn er Widerstand spürt nich weiter drückt sondenr nur einen stabilen Griff hält.

Gruß Thund3r

RobbyMartin
03.03.2010, 21:28
Mir ist gerade so ne Idee gekommen koennte man nicht ueber ein adc Eingang den Strom über ein spannungsteiler messen, da soweit ich weiß wenn der servo blockiert der Strom steigt.

Das waere im Prinzip doch viel einfacher oder irre ich mich??

LG
Martin

radbruch
03.03.2010, 21:38
Nochmals hallo


Nun funktioniert es.Das ist verblüffend. Wenn das Servo mit seiner Signalleitung an PC7 "hängt", wie kannst du dann die Spannung an dieser Signalleitung an ADC_5 (PA5) messen? Aber wenn es funktioniert ist es ja gut...


...koennte man nicht ... den Strom über einen Spannungsteiler messen...?Das könnte man schon, aber die Idee ist nicht wirklich neu und wurde weiter oben schon angesprochen. Und das wäre dann doch keine Minimalösung (=keine weiteren Bauteile) mehr, oder?

Gruß

mic

Thund3r
03.03.2010, 21:50
Hallo

Ich habe ein Kabel vom ADC zum I/O montiert und die beiden sind mit dem Steuerpin des Servos verbunden.

Hier ein kleines Video meiner Umsetzung an meinem Greifarm:

http://www.youtube.com/watch?v=GDv6Ys0Wsgk

Nochmals Dank radbruch ;)

Gruß Thund3r

radbruch
03.03.2010, 22:24
Ich habe ein Kabel vom ADC zum I/O montiertAha!

Aber trotzdem bleibt es verblüffend, weil du nach über zwei Jahren der erste bist, der diese Idee aufgreift und es quasi auf Anhieb funktioniert, obwohl du eine vollkommen andere Art der Servoansteuerung verwendest. Das ist echt der Hammer! Vielleicht sollte sich doch mal jemand erbarmen und das Signal auf der Servoleitung mit einem Oszi genau auf diesen Effekt hin untersuchen.

Dein Projekt mit deinem Roboterarm gefällt mir natürlich auch gut ;)

Um das Roboternetz-Forum zu pushen, und unsere Videos zusammen zu halten, haben wir mal vorgeschlagen, in den Tags der youtube-Videos auch ein "roboternetz" einzufügen. (Das wurde hier (https://www.roboternetz.de/phpBB2/zeigebeitrag.php?p=418702#418702) mal vorgeschlagen ;)

btw: Kannst mir hierfür mal den Quellcode schicken:
http://www.youtube.com/watch?v=U5HgMhHF9DU

*gg*

Gruß

mic

Thund3r
03.03.2010, 22:29
Hallo

Vielen Dank.

Der Quellcode kommt über PN
Aber verrat erstmal nichts wird ja für den Wettbewerb (https://www.roboternetz.de/phpBB2/viewtopic.php?t=52477) benutzt ;)

Gruß Thund3r

Thund3r
04.03.2010, 17:05
Hallo

Hier nochmal der Quellcode für mein Video (http://www.youtube.com/watch?v=GDv6Ys0Wsgk) inkl. Erklärung:



// Servo-Sensor an einem Greifer 4.3.2010 Thund3r


static int reset,durch,durch2,stop,count; //Variablen die von verschiedenen Methoden verändert werden können

void gtest(void)
{

int c;
if(reset==0) // Wird nur einma zu Beginn des Programmes aufgerufen

{
for(c=0;c<=50;c++)

{
ServoG(12);
}

for(c=0;c<=50;c++)

{

ServoG(21);
if(durch>durch2) // Ermittelt den höchsten Schwellwert

{
durch2=durch; // Speichert diesen
}
mSleep(40);
}
reset=1; // Damit es nur einmal ausgeführt wird
}

for(c=0;c<=50;c++)

{
ServoG(12); //Greifarm öffnet sich
}

setLEDs(0b0000);
mSleep(200);

for(c=0;c<=50;c++)

{

if(stop==0) // Wenn alles ok Greif zu
{
ServoG(21);
mSleep(40);
}

else {mSleep(50);} // Wenn Widerstand erkannt (s.u.) halte Position

if(durch>durch2) //Wenn Belastung höher als ermittelter Grenzwert
{
count++; // Anzahl der Grenzwertüberschreitungen
}
else{count=0;} // Wenn Grenzwert nur einmalig erreicht wurde verwerfe den Entrag
if(count==2) //Wenn Grenzwert 2 mal Überschritten wird tritt Aktion in Kraft (Anzahl variabel)
{
setLEDs(0b1111);
count=0;
stop=1; // Greifvorgang wird abgebrochen und Position gehalten s.o.
}
}
stop=0;
mSleep(200);

}




void messG() // Messmethode
{

uint16_t adc5 = readADC(ADC_5); // Messwert einlesen
clearLCD();
durch=adc5; // Übergeben damit andere Methoden damit arbeiten können
setCursorPosLCD(0, 0);
writeStringLCD("Belastung: "); // Ausgabe auf LCD Display
writeIntegerLCD(adc5, DEC);

}





void ServoG(uint8_t pos) // Zur Ansteuerung des Servos
{

DDRC |= IO_PC7; // Pin auf Ausgang
PORTC |= IO_PC7; // High
sleep(pos); // Stellzeit
PORTC &= ~IO_PC7; // Low
DDRC &= ~IO_PC7; // Pin auf Eingang
sleep(5);
messG(); // messen
sleep(180);

}

Prakitsch zum schonen der Greifmechanik, wenn der Arm etwas nicht zu fest drücken darf, um zu überprüfen ob die gewünnschte Servo Position erreicht wurde oder ob der Servo noch in Bewegung ist etc.

Gruß Thund3r

radbruch
16.08.2010, 21:44
Hallo

Eher zufällig bin ich hier mal wieder reingestolpert. Eigentlich schade, dass bisher außer Thund3r diesen Effekt niemand nutzte. Sein Video zeigt schön, wie man das umsetzen kann:
http://www.youtube.com/watch?v=GDv6Ys0Wsgk

Mich würde immer noch interessieren, ob man die Spannungsänderung auf der Signalleitung mit einem Osziloskop sehen kann. Das Testprogramm und die Messung selbst wäre wohl einfach: In der Impulspause das Signal nicht nach GND verbinden, sondern den Steuerpin auf Z-State schalten. Dann sollte in der Pulspause ein lastabhäniger Peek erkennbar sein. Die genaue Lage und Größe dieses Peeks würde mich interessieren. :)

Auch heute noch eines meiner besten Filmchen:
http://i.ytimg.com/vi/39tOx0IxQ40/1.jpg (http://www.youtube.com/watch?v=39tOx0IxQ40)
http://www.youtube.com/watch?v=39tOx0IxQ40

Gruß

mic

HeXPloreR
04.08.2013, 20:23
Hallo mic,

könnte das denn auch mit einem Controller und min. 6 Servos funktionieren - in Deinem Video wird ja nur einer ausgewertet?
Hast Du vielleicht schon einen neueren Test mit digitalen Servos gemacht?

oberallgeier
16.08.2013, 12:03
... Mich ... interessieren ... Spannungsänderung auf der Signalleitung mit einem Osziloskop sehen kann ...
Das Testprogramm .. Impulspause ... den Steuerpin auf Z-State schalten ...Hallo Mic,

derzeit arbeite ich an (m)einem Teststand für Servos, eher einem Prüfstand für eine Latte verschiedener Messungen (Leerlauf- und Lastströme, Positioniergenauigkeit, Speed, Beschleunigungen etc) an meinen Servos. Dabei wollte ich auch diesen Effekt mal verfolgen. Die Mechanik des Teststandes ist im Aufbau, als Platine nehme ich meinen KopfController für den Archie, die tasten-/LCD-gesteuerte Software läuft in wenigen Grundfunktionen.

Nun habe ich genau diese Messung am Oskar mit dem High-Torque (siehe hier) (https://www.roboternetz.de/community/threads/61379-Kopfsache-und-ein-m1284-etliche-Servos-viel-Alu?p=583165&viewfull=1#post583165) gemacht mit folgenden Abgriffen:
Steuerpin gegen GND. Das ergibt die an sich bekannte, saubere Rechteckspannung, die sich auch bei Lastmoment am Servoarm nicht ändert. Ein schulbuchmässiges Oszilloskopbild.
Steuerpin gegen Vcc, Abgriff unmittelbar am Servostecker. Hier ist die Rechteckspannung invers, Nullwert deutlich verschoben - und - der Spannungshub scheint sich bei Lastmoment am Servoarm geringfügig zu ändern. Deutlicher ist bei einer Momentenlast die Änderung des gesamten Niveaus - also am Oskar angezeigte Null- und Pulsspannung. Dabei wabert das Signalbild am Schirm leicht, umso mehr, je mehr Last da ist. Das Signalbild verlagert sich insgesamt, der Hub Puls-keinPuls scheint sich auch tatsächlich gleichzeitig zu verändern.

Dass ich bei einigen Messungen mit UART- und Prog rammer-Anschluss zum PC mit dem Netzteil in die Strombegrenzung von 1,5 A fuhr, wobei die Versorgungsspannung der Servoplatine von 8,00 V auf 7,0x V absank ist eine seltsame Nebenerscheinung, die ohne UART- und ohne Programmerverbindung verschwand. Der Servo ist dabei übrigens eine ganze Zeitlang ausgestiegen (brrrrr). Das Netzteil zur Platinen- und Servoversorgung (zwei getrennte 7805/78S05) hat keine GND-Verbindung zum Netz.

Messungen des Controllers selbst in der von Dir vorgeschlagenen Art werde ich auch durchführen. Noch ist mir zu viel unklar.

Dirk
16.08.2013, 19:54
Leute,

ich bin immer noch ratlos, wodurch dieser Effekt zustande kommt.
Etwas hilflose Fragen:
1. In den Servo-Elektroniken sitzt ja wohl meist ein NE544 oder M51660L. Da ist der Impulseingang dieser ICs außen nicht beschaltet, so dass es nur um Effekte "aus dem IC heraus" handeln kann. Was kann das sein?
2. Ist der Effekt wirklich völlig unabhängig von Schwankungen der Versorgungsspannung?
3. Welche induktiven Effekte könnten eine Rolle spielen?

Genauso hilflose Antwortversuche:
1. Keine Ahnung.
2. Ich denke: Nein. Wenn es z.B. im Servo-IC einen Eingangsspannungteiler gäbe, der an VCC liegt, könnte das ein Effekt sein. Was kann man überhaupt am Eingangspin 5 eines M51660L unter VCC messen?
3. Da man in einer Impulspause die Spannung am Impulseingang des Servos mißt, könnten am Anfang der Pause Nachschwingungen eine Rolle spielen, dann spielt vielleicht auch eine Selbstinduktion eine Rolle, wenn im IC-Eingangskreis eine Induktivität wirkt.

... und:
Was diese Effekt, wenn es sie gibt, dann mit dem Ausmaß der mechanischen Servobelastung zu tun haben könnten: Keine Ahnung.

Klärt mich auf! Was tut sich da?
Klappt das mit jeder Servo-Elektronik?

Klebwax
17.08.2013, 03:11
Ich versuche mal eine Erklärung:

Es wird oft gesagt: "Wer misst misst Mist". Ich denke, das trift hier zu, aber etwas anders, als man vermutet.

Ein offener Eingang eines Chips wird sich durch interne Widerstände auf einen Spannungswert zwischen Vcc und GND einstellen. Gemeint ist hier die Spannung am Vcc Pin und am GND Pin. Etwas anderes kann der Chip ja nicht sehen. Während und nach dem Servo-Pulse wird ja der Motor eingeschaltet, es ist der Zeitpunkt des größten Stromes. Wenn der Eingang des Servo-ICs sich an seinem GND-Pin orientiert, misst man aus Sicht der Ansteuerelektronik am Steuersignal den Strom im Servo. Als Mess-Shunt fungiert dabei eine schlechte (zu hochohmige) Masseanbindung des Servos.

Man misst also den suboptimalen (so nennt man heute wohl "Mist") Aufbau einer Baugruppe. Den gleichen Effekt hat man natürlich auch in der Vcc Leitung, je nach Messpunkt kommen da noch die Innenwiderstände einer suboptimalen (unterdimensionierten) Stromversorgung hinzu.

Dies wäre meine, rein theoretische Erklärung des Phänomens.

Ein solcher, eigentlich schlechter, Aufbau einer Elektronik (zu dünne, zu lange Drähte, zu viele zu schlechte Steckverbinder, zu hohe Leitungsinduktivitäte, zu dünne Leiterbahnen, unterdimensionierte Stromversorgungen etc) retten aber manche Elektronik oder auch Mechanik.

Elektromoteren sind Biester, beim Anlaufen und beim Blockieren wollen sie hohe Ströme und liefern dabei hohe Momente. Und da sie durch diese Ströme nicht direkt zerstört werden, sondern erst durch die langsamer erfolgende Überhitzung, rettet ein "suboptimaler" Schaltungsaufbau, der als Strombegrenzung funktioniert, so manches Ritzel vor dem Zahnverlust und manche Wicklung vor dem Abbrennen.

MfG Klebwax

BTW: Hier wird in verschiedenen Threads über die Versorgung von Servos philosophiert. Ich habe aber noch nichts von wirklichen Messungen mit Shunt und Scope oder mit Stromzange und Scope gelesen. Alle berichteten Spitzenstromwerte stammen aus Vermutungen, schlecht übersetzten Produktbeschreibungen oder (eigentlich unbrauchbaren) Multimetermessungen. Da ich nur zwei jahrzehnte alte Servos aus der "Miniservo" Klasse besitze, kann ich selbst keine Messwerte beisteuern. Wenn ich einen Teststand für Servos bauen würde, hätte eine Strommessung mit guter zeitlicher Auflösung hohe Priorität.

nochmal MfG

radbruch
17.08.2013, 09:02
Hallo


Wenn der Eingang des Servo-ICs sich an seinem GND-Pin orientiert, misst man aus Sicht der Ansteuerelektronik am Steuersignal den Strom im Servo. Als Mess-Shunt fungiert dabei eine schlechte (zu hochohmige) Masseanbindung des Servos.Das könnte die gesuchte Erklärung des Effekts sein. Dann sollte man am Servo-GND auch eine Spannungsanhebung gegenüber dem ADC-GND messen können.

Gruß

mic

Dirk
17.08.2013, 09:05
@Klebwax,

deine Deutung kann ich gut nachvollziehen.
Wenn es so sein sollte, würde doch vielleicht eine Strommessung an Servo-VCC ein ähnliches Ergebnis bringen, oder?
Das wird ja auch teilweise zur Servo-Anschlags-Erkennung schon eingesetzt.
Vielleicht könnte man ja mal die Messungen am Impulseingang korrelieren mit einer Strommessung an Servo-VCC oder sogar einer Spannungsmessung der Servo-VCC (abnehmen müßte man die dann wohl IM Servo am VCC-Eingang und GND des Steuer-ICs).