Hallo! Für ein kleines Projekt würde ich gerne einen Servomotor über ein Potentiometer steuern. Der Servomotor läuft bereits, und lässt sich über das Poti steuern. Jedoch verliert der Servo anscheinend immer wieder das Signal. Dreh ich das Poti langsam von 0 auf ca. 1/2 Anschlag folgt mir der Servo ca. 1:1, dreh ich dann etwas weiter verliert der Motor auf einmal die Verbindung (Windows Plugin Sound kommt) und marschiert nur noch in größeren einzelnen Schritten weiter. Bleib ich dann wieder auf dem Wert, und drehe wieder langsam in die andere Richtung so fängt er sich wieder und marschiert 1:1 weiter bis er das nächste mal die Verbindung verliert. Habt ihr eventuell eine Ahnung was das sein könnte? Vielen Dank schonmal für eure Hilfe & Ideen. LG Kurze Daten: Servo VILROS MicroServe SG90 (Pulsbreite von 500us-2500us) Arduino UNO Board - ATmega328p (Den Code sende ich sobald sich einer damit auseinander setzen möchte)
servomoto schrieb: > (Den Code sende ich sobald sich einer damit auseinander setzen möchte) Das könnte ein Henne-Ei-Problem sein ...
1 | #define F_CPU 16000000
|
2 | #include <avr/io.h> |
3 | #include <avr/interrupt.h> |
4 | #include <util/delay.h> |
5 | |
6 | uint16_t ReadChannel(uint8_t mux_adc_channel); //ADC-auslese Funktion deklarieren |
7 | uint16_t adc_value; // Rückgabewert der Auslese-Funktion |
8 | uint16_t valuetosend; |
9 | uint16_t move = 0; |
10 | uint16_t adc_enabled = 1; |
11 | uint16_t grad; |
12 | |
13 | void adc_init (){ |
14 | TCCR1A = (1<<WGM11)|(1<<COM1A1) ; // 9-Bit PWM Modus Auflösung 1024, NICHT invertiert |
15 | TCCR1B = (1<<WGM13) | (1<<WGM12)|(1<<CS12)|(1<<CS10); // Prescale 1024, Mode 14 (CTC) |
16 | DDRB |= (1<< PB1); // PB1(OC1A) als Ausgang definieren |
17 | ICR1 = 312; |
18 | }
|
19 | |
20 | ISR(USART_RX_vect) // definiert Interrupt Service Routine für USART receive complete |
21 | {
|
22 | cli(); // clear interrupt enable |
23 | grad = UDR0; |
24 | char sendString [3]; |
25 | |
26 | if(grad >= 0 && grad <= 180) // wenn Eingabe zwischen 0-180, dann accepted |
27 | {
|
28 | adc_enabled = 0; |
29 | uart_sendstring(" Adc Disabled "); |
30 | |
31 | int_to_string(grad, sendString); |
32 | uart_sendstring(sendString); |
33 | move = grad * 5.688; |
34 | OCR1A = (move / 35 ) + 8; |
35 | }
|
36 | else // wenn nicht, nochmalige Eingabe |
37 | {
|
38 | adc_enabled = 1; |
39 | uart_sendstring("adc enabled"); |
40 | }
|
41 | |
42 | sei(); // enable global Interrupt |
43 | }
|
44 | |
45 | // MAIN
|
46 | |
47 | int main(void) |
48 | {
|
49 | uart_init(115200); |
50 | adc_init(); |
51 | sei(); |
52 | |
53 | while(1) |
54 | { if(adc_enabled == 1) |
55 | {
|
56 | adc_value = ReadChannel(0); // Channel 0 auslesen (Wert 0...1023) |
57 | OCR1A = (adc_value / 35 ) + 8; // PWM-Vergleichswert setzen, werte müssen zwischen 8 und 32 liegen |
58 | }
|
59 | }
|
60 | return 0; |
61 | }
|
62 | |
63 | // Auslesen des ADC
|
64 | |
65 | uint16_t ReadChannel(uint8_t mux_adc_channel) |
66 | {
|
67 | ADCSRA = (1<<ADEN) | (1<<ADPS2) | (1<<ADPS1)| (1<<ADPS0); // Frequenzvorteiler auf 32 setzen und ADC aktivieren |
68 | ADMUX = mux_adc_channel; // übergebenen Kanal waehlen |
69 | ADMUX |= (0<<REFS1) | (1<<REFS0); // interne Referenzspannung nutzen |
70 | |
71 | //dummy readout
|
72 | ADCSRA |=(1<<ADSC); // start ADC Conversio |
73 | while( ADCSRA & (1<<ADSC) ) {}; // auf abschluss von Wandlung warten |
74 | ADCSRA &= ~(1<<ADEN); // ADC deaktivieren ("Enable-Bit" auf LOW setzen) |
75 | |
76 | return ADCW; |
77 | }
|
Vergiss deinen Plan den Servo über den Arduino besaften zu wollen und gönne dem Servo seine eigene Stromversorgung mit ausreichend Strom!
Gut, danke. Werde es demnächst ausprobieren, hab nun aber noch 2 weitere Probleme :D Und zwar: Soll über UART die aktuelle Grad Position gesendet werden, so dass der PC User immer weiß welche Stellung der Servo gerade hat. Dies funktioniert ebenfalls bereits, jedoch unterbricht die Datenübertragung immer wieder nach unterschiedlicher Zeit. Mittels _delay_ms(1000) sollte mir die Schnittstelle am PC jede Sekunde die aktuelle Position senden. Hier der UART-Code und die Umrechnung auf Grad in dem ich die Werte vom Poti (0-1023) auf 0-180° umrechne (/5,68).
1 | //UART
|
2 | void uart_init (uint32_t baudrate) |
3 | {
|
4 | uint16_t ubrr = (F_CPU / 8 / baudrate) - 1; |
5 | |
6 | UBRR0H = (uint8_t) (ubrr >> 8); |
7 | UBRR0L = (uint8_t) (ubrr & 0xff); |
8 | |
9 | UCSR0A |= (1<<U2X0); |
10 | |
11 | UCSR0B |= ( 1<<TXEN0); |
12 | UCSR0B |= ( 1<<RXEN0); |
13 | }
|
14 | |
15 | void uart_transmit (uint8_t data) |
16 | {
|
17 | while ( (UCSR0A & (1 << UDRE0)) == 0) ; |
18 | UDR0 = data; |
19 | }
|
20 | |
21 | uint8_t uart_receive () |
22 | {
|
23 | while ( (UCSR0A & (1 << RXC0)) == 0) ; |
24 | return(UDR0); |
25 | }
|
26 | |
27 | void int_to_string ( uint16_t number, char *targetString ) |
28 | {
|
29 | int8_t digit; |
30 | |
31 | for (digit = 3; digit >= 0; digit--) |
32 | {
|
33 | targetString[digit]= number%10 + '0'; |
34 | number = number/10; |
35 | }
|
36 | targetString[4] = 0; |
37 | }
|
38 | |
39 | void uart_sendstring ( char * str ) |
40 | {
|
41 | while ( * str != 0 ) |
42 | {
|
43 | uart_transmit ( * str); |
44 | str++; |
45 | }
|
46 | }
|
47 | |
48 | // MAIN
|
49 | int main(void) |
50 | {
|
51 | char sendString [3]; |
52 | uart_init(115200); |
53 | |
54 | TCCR1A = (1<<WGM11)|(1<<COM1A1) ; // 9-Bit PWM Modus Auflösung 1024, NICHT invertiert |
55 | TCCR1B = (1<<WGM13) | (1<<WGM12)|(1<<CS12)|(1<<CS10); // Prescale 1024, Mode 14 (CTC) |
56 | DDRB |= (1<< PB1); // PB1(OC1A) als Ausgang definieren |
57 | |
58 | ICR1 = 312; |
59 | |
60 | while(1) |
61 | {
|
62 | adc_value = ReadChannel(0); // Channel 0 auslesen (Wert 0...1023) |
63 | OCR1A = (adc_value / 35 ) + 8; // PWM-Vergleichswert setzen, werte müssen zwischen 8 und 32 liegen |
64 | |
65 | ADCSRA |= (1<<ADSC); |
66 | |
67 | while (ADCSRA & (1<<ADSC)); |
68 | |
69 | uint16_t result = ADCL; |
70 | result = result + (ADCH<<8); |
71 | |
72 | valuetosend = result / 5.68; |
73 | |
74 | int_to_string (valuetosend, sendString); |
75 | uart_sendstring (sendString); |
76 | uart_sendstring ("Grad "); |
77 | |
78 | PORTB ^= (1<<5); |
79 | |
80 | _delay_ms(1000); |
81 | }
|
82 | return 0; |
83 | }
|
>hab nun aber noch 2 weitere Probleme :D
Löse erst mal dein erstes Problem. Weitere Probleme
sind solange das nicht geschehen ist nicht wichtig.
Hab jetzt aber leider keine 5V Versorgung bei der Hand und würde gerne die anderen Probleme noch beseitigen. Ich bin leider alles schon zu oft durchgegangen und anscheinend verlese ich mich immer wieder an einer Stelle, da beides ja schon ziemlich gut funktioniert würde ich sagen, kann es nur an einer Kleinigkeit liegen. Kennt sich von euch zufällig jemand gut mit UART aus und verwendet ev. auch HTerm als Schnittstellensoftware?
>kann es nur an einer Kleinigkeit liegen. Nein, nur an deiner Unfähigkeit. > char sendString [3]; > int_to_string (valuetosend, sendString);
1 | void int_to_string ( uint16_t number, char *targetString ) |
2 | {
|
3 | int8_t digit; |
4 | |
5 | for (digit = 3; digit >= 0; digit--) // digit wird hier negativ, sendstring hat nur drei Byte, der erste Zugriff ist auf Byte vier |
6 | {
|
7 | targetString[digit]= number%10 + '0'; |
8 | number = number/10; |
9 | }
|
10 | targetString[4] = 0; // sendstring hat nur drei Byte. Hier wird auf das fünfte zugegriffen. |
11 | }
|
Danke für den Hinweis. Hab leider schon unzählige verschiedene Code-Versionen an denen ich rumbastle. Bin jetzt der Meinung dass die Versorung einfach zu wenig ist, somit die Verbindung verloren geht und daher dann auch das Schnittstellenprogramm nicht mehr arbeitet. Das einzige was noch fehlt: Der Servo soll durch Eingabe in HTerm (Dez.) (0-180°) an die gewünschte Position fahren. Bekommt der uC nun also eine Eingabe, so soll er den ADC deaktivieren (sodass Änderung mittels Poti kurzzeitig nicht mehr möglich ist), und an die gewünschte Position fahren. Ist dies abgearbeitet, so soll er den ADC wieder aktivieren. Ich habe oben schon ein Interrupt geschrieben. Teste ich das ganze mit einer Hilfsvariable, so bekomm ich immer einen Wert gesendet, obwohl der ADC deaktiviert ist, und erst ein Wert kommen dürfte wenn ich eine Eingabe getätigt habe. Hat hierzu jemand vielleicht einen Lösungsvorschlag, oder gar einen Weg? LG
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.