Minimallösung: Servo-Sensor
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:
Bild hier Bild hier Bild hier
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:
Code:
// 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
Liste der Anhänge anzeigen (Anzahl: 2)
Hallo
Zur RP6-Jukebox:
Meist verlinke ich den endsprechenden Thread bei meinen Filmchen:
https://www.roboternetz.de/phpBB2/vi...=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:
Code:
// 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