MikroBasic en Servomotor

Arco

Special Member

Je moet zoals gezegd in rust blijven aansturen (middenstand of wat anders)

Arco - "Simplicity is a prerequisite for reliability" - hard-, firm-, en software ontwikkeling: www.arcovox.com
Bavelt

Golden Member

Dus dacht ik in mijn onschuld, dan doe ik het zo:

De interrupt komt iedere 20 ms (is dus 50Hz)
In de main laat ik dan de delay oplopen van 1 naar 2 ms in stappen van 10us. Zo lang blijft Portb.3 dan hoog.
Een puls dus van 1 ms tot 2 ms.

Het effect is dat de servo nu (schokkerig) 360 graden ronddraait... :/

pic basic code:

Program PWM_Test

Dim Direction as byte
    i1 as word
    z1 as word
    
Sub Procedure Wait(Dim pDelay as Word)
For z1 = 0 to pDelay
  Delay_us(1)
Next z1
End sub

'-------------------------------------------------------------------------------
Sub procedure Interrupt() iv 0x0004 ics ICS_AUTO
'-------------------------------------------------------------------------------
  If TMR2IF_bit Then                                    'See if timer2 irq
     PORTB.3 = 1
     PORTB.7 = 1
     TMR2IF_bit = 0
  End If
End sub

Main:

  OSCCON     = %01000000                                '1 Mhz internal
  T2CON      = %00100101                                'Post:5 - Pre:16
  PR2        = 249                                      'Timer load value
  GIE_bit    = 1                                        'Enable timer2 irq
  PEIE_bit   = 1
  TMR2IE_bit = 1

  ANSEL  = 0
  ANSELH = 0
  TRISA = %11111111
  TRISB = %00000000
  PORTA = %00000000
  PORTB = %00000000
  
  PORTB.7 = 1                        'Measure Frequency
  PORTB.6 = 1                        'Test LED On
  Delay_ms(2000)                     'Wait befors start
  
  PORTB.6 = 0                        'Test LED Off
  Direction = 1                      'Default Mid Position
 
  While True
  For i1 = 1000 to 2000 step 10
   Wait(i1)
   PORTB.3 = 0
  Next i1

  For i1 = 2000 to 1000 step -10
   Wait(i1)
   PORTB.3 = 0
  Next i1

 Wend
 
end.
Fouten zijn het bewijs dat je het probeert..

Op 25 juli 2020 22:04:34 schreef Bavelt:
Het effect is dat de servo nu (schokkerig) 360 graden ronddraait... :/

Lijkt me sterk. De meeste servo's komen niet verder dan iets meer dan 180 graden.

Bavelt

Golden Member

Lijkt me sterk. De meeste servo's komen niet verder dan iets meer dan 180 graden

Vond ik ook. maar deze draait echt vrolijk helemaal rond...

Ik had verwacht dat hij heen en weer zou gaan, maar het programma doet niet wat ik wil...

Fouten zijn het bewijs dat je het probeert..
Arco

Special Member

Wat voor pic gebruik je? (aan de anselh en lage klok te zien een oud beestje?)
Dat 'ie 360 graden ronddraait is inderdaad onmogelijk (het kan mechanisch niet als het een SG-90 is)

De laatst geplaatste code doet volgens mij niets zinvols. Kan goed dat er 'random' dingen gebeuren...

[Bericht gewijzigd door Arco op zaterdag 25 juli 2020 23:35:01 (23%)

Arco - "Simplicity is a prerequisite for reliability" - hard-, firm-, en software ontwikkeling: www.arcovox.com
Bavelt

Golden Member

Een PIC16F887.

Ik weet niet of ik een filmpje als attachment kan meesturen bij een beriht?

Fouten zijn het bewijs dat je het probeert..
Arco

Special Member

Een MP4 o.i.d. (mits bescheiden van formaat) moet je kunnen plaatsen.
Ik zal eens kijken of ik wat kan maken (ik doe nooit wat met servo's, maar het is vrij eenvoudig)

Arco - "Simplicity is a prerequisite for reliability" - hard-, firm-, en software ontwikkeling: www.arcovox.com
Bavelt

Golden Member

Fouten zijn het bewijs dat je het probeert..
Bavelt

Golden Member

Fouten zijn het bewijs dat je het probeert..
Bavelt

Golden Member

Kort filmpje, ik moet onder de 4MB blijven...
Je kunt er wel aan zien dat hij schokkerig draait met mijn programma.

[Bericht gewijzigd door Bavelt op zaterdag 25 juli 2020 23:56:37 (44%)

Fouten zijn het bewijs dat je het probeert..
Lambiek

Special Member

Op 25 juli 2020 23:05:30 schreef Bavelt:
Vond ik ook. maar deze draait echt vrolijk helemaal rond...

Deze servo kan max maar 180 graden draaien, die is dus stuk als hij helemaal rond gaat.

Ding komt bij Alie vandaan zeker of zat hij bij zo'n doos voor de arduino?

Heb je mijn artikel nog doorgelezen, daar staat alles zo'n beetje in wat je moet weten.

Als je haar maar goed zit, GROETEN LAMBIEK.
Bavelt

Golden Member

Nee, dit keer geen 'tante Alie', maar de reguliere electronicahandel.
Tegen een normale prijs.

Het ding zat nieuw in de verpakking.

Ik had al wel gelezen (in o.a. het artikel van Lambiek) dat je zelf de (mechanische) blokkade er uit kan halen waardoor hij 360 Gr kan draaien.
Maar dat heb ik niet gedaan. Ik wilde gewoon eens 'spelen' met zo'n ding.
Links-midden-rechts en terug. Met de Arduino sketch werkt dat ook prima en traploos.

Het artikel van Lambik heb ik doorgenomen. Erg uitgebreid en verhelderend hoe het werkt.
Alleen zit er nog even een muurtje tussen theorie en praktijk.
(zoals vertaling van Picbasic maar MikroBasic voorbeelden).

Ik dacht zelf alles goed te hebben gedaan, frequentie 50 Hz, pulsduur 1 tot 2 ms.

Ik zie overigens wel dat de voeding een 'dipje' krijgt als de motor wordt ingeschakeld. (de voedingsled knippert dan even).
En omdat de microcontroller daar ook aan hangt, zou het wellicht aanbevelenswaardig zijn deze voedingen te scheiden (?).

Fouten zijn het bewijs dat je het probeert..
Arco

Special Member

Zoals gezegd, de laatst geposte code kan niet werken (althans doet niks voorspelbaars... ;) )
Er is geen synchronisatie tussen de timerinterrupt en de routine in main() : die hobbelen onafhankelijk van elkaar op verschillende snelheden...
Daardoor komen de pulsen op willekeurige momenten in de interruptcyclus.

Arco - "Simplicity is a prerequisite for reliability" - hard-, firm-, en software ontwikkeling: www.arcovox.com
Lambiek

Special Member

Op 26 juli 2020 12:04:56 schreef Bavelt:
Het ding zat nieuw in de verpakking.

Kan een foutje zijn. Je kunt eens kijken of de mechanische stop soms afgebroken is.

Ik zie overigens wel dat de voeding een 'dipje' krijgt als de motor wordt ingeschakeld. (de voedingsled knippert dan even).
En omdat de microcontroller daar ook aan hangt, zou het wellicht aanbevelenswaardig zijn deze voedingen te scheiden (?).

Voor zo'n kleine servo zou het moeten kunnen, ik doe het vaak op de zelfde voeding.

Als het echter een grotere servo is of de servo wordt zwaar belast, dan is een externe voeding aan te raden.

Maar voor nu denk ik dat het voornamelijk aan de software ligt.

Als je haar maar goed zit, GROETEN LAMBIEK.
marcob

Golden Member

Op 26 juli 2020 11:40:25 schreef Lambiek:
[...]
Deze servo kan max maar 180 graden draaien, die is dus stuk als hij helemaal rond gaat.

Dit is een Continuous Rotation Servo, volgens de site. Dus hij kan inderdaad ronddraaien.
https://www.hobbyelectronica.nl/product/sg90-digital-servo-360-graden/

Heeft MikroBasic geen eigen servo commando? PicBasic heeft deze wel.

People tend to overestimate what can be done in one year and to underestimate what can be done in five or ten years
Lambiek

Special Member

Op 26 juli 2020 15:04:40 schreef marcob:
Dit is een Continuous Rotation Servo, volgens de site. Dus hij kan inderdaad ronddraaien.

Dat is vreemd, ik kom deze tegen.

sg90_datasheet.pdf

Zal er waarschijnlijk aan liggen of het een digitale is of niet. :)

Heeft MikroBasic geen eigen servo commando? PicBasic heeft deze wel.

Zover ik weet heeft micro basic dat commando niet. Anders had Arco dat wel gezegd.

Als je haar maar goed zit, GROETEN LAMBIEK.
Arco

Special Member

Misschien zijn er wel libraries voor, even op Libstock kijken...

Arco - "Simplicity is a prerequisite for reliability" - hard-, firm-, en software ontwikkeling: www.arcovox.com
Bavelt

Golden Member

Ik ben al weer een stuk verder.
Arco had gelijk dat er geen synchronisatie zat tussen de timer interrupt en de main:

Dat heb ik aangepast: in de main wordt gekeken of er een interrupt was (via een vlaggetje) zodat de statements onderling relaties hebben.

pic basic code:

Program PWM_Test

Dim Direction as byte
    i1 as word
    z1 as word
    Ind as byte
    
Sub Procedure Wait(Dim pDelay as Word)
For z1 = 0 to pDelay
  Delay_us(1)
Next z1
End sub

'-------------------------------------------------------------------------------
Sub procedure Interrupt() iv 0x0004 ics ICS_AUTO
'-------------------------------------------------------------------------------
  If TMR2IF_bit Then                                    'See if timer2 irq
     PORTB.3 = 1
     Ind = 1
     TMR2IF_bit = 0
  End If
End sub

Main:

  OSCCON     = %01000000                                '1 Mhz internal
  T2CON      = %00100101                                'Post:5 - Pre:16
  PR2        = 249                                      'Timer load value
  GIE_bit    = 1                                        'Enable timer2 irq
  PEIE_bit   = 1
  TMR2IE_bit = 1

  ANSEL  = 0
  ANSELH = 0
  TRISA = %11111111
  TRISB = %00000000
  PORTA = %00000000
  PORTB = %00000000

  Direction = 1                      'Default Mid Position
  Ind = 0
 
  While True
  
  If Ind = 1 then
   if z1 < 20 then
     Delay_us(1500)
     'Wait(1500)
   else
     if (z1 > 19) and (z1 < 30) then
       Delay_ms(1)
     else
       if z1 > 39 then
          Delay_ms(2)
       end if
     end if
  end if
      PORTB.3 = 0
      Ind = 0
      z1 = z1 + 1
      if z1 > 40 then
         z1 = 0
      End if
  End if
 Wend
 
end.

Ik kan de servo nu heen en weer laten bewegen, zij het dat 1ms-1,5ms-2ms pulsduur niet gelijk is aan 0-90-180gr beweging.
De sprong van 1 naar 1,5 doet beduidend minder dan van 1,5-2 ms.

Dit kon ook wel eens te maken met het volgende: omdat ik de delay met een parameter wilde aansturen (de MikroBasic procedure Delay wil een literal en geen variabele) had ik de volgende procedure geschreven:

pic basic code:

Sub Procedure Wait(Dim pDelay as Word)
For z1 = 0 to pDelay
  Delay_us(1)
Next z1
End sub

Maar: Delay_us(1500) en Wait(1500) geven een ander resultaat. Ik vermoed omdat de klokfrequentie op 1Mhz staat, de tijd die nodig is voor het uitvoeren van een instructie te groot wordt, waardoor mijn procedure niet werkt..

[Bericht gewijzigd door Bavelt op zondag 26 juli 2020 21:20:48 (43%)

Fouten zijn het bewijs dat je het probeert..
Arco

Special Member

Delays zijn bij gebruik van interrupts al vrij onnauwkeurig (bij een heel veel aangeroepen interrupt kan de afwijking zelfs +50% zijn...)
De hele lage kloksnelheid is inderdaad ook niet echt bevorderlijk.
Een aparte subroutine voor de delay maakt 't nog onnauwkeuriger: iedere aanroep kost minstens 8 extra instructiecycles...

Delay_ms en Delay_us verwachten een constante inderdaad, omdat de compiler inline code genereert voor nauwkeurigheid.
(er is ook VDelay_ms waar je wel een variabele op kunt geven, maar dat is onnauwkeuriger)

[Bericht gewijzigd door Arco op zondag 26 juli 2020 22:10:19 (24%)

Arco - "Simplicity is a prerequisite for reliability" - hard-, firm-, en software ontwikkeling: www.arcovox.com
Bavelt

Golden Member

Dus de interrupt is voor deze toepassing eigenlijk niet zo geschikt (mede vanwege de lage frequentie van 50Hz. Daarom koos ik ook voor een lage klokfrequentie).
Wat zou dan een betere oplossing zijn voor deze toepassing?

Fouten zijn het bewijs dat je het probeert..
Lambiek

Special Member

Je kunt toch gewoon een plus maken met een paar delays. Even met de scoop controleren of met een logic analyser.

Als je haar maar goed zit, GROETEN LAMBIEK.
Lambiek

Special Member

Hier heb je een voorbeeld, hoe simpel kan het zijn. :)

pic basic code:


Device 16F887                     ; Processor type

Xtal 10                           ; Cristal 10Mhz

Asm                               ; Config settings  HS_OSC
CONFIG_REQ            
__CONFIG _CONFIG1, HS_OSC & WDT_OFF & DEBUG_OFF & FCMEN_OFF & LVP_OFF & IESO_OFF & BOR_OFF & CPD_OFF & CP_OFF & MCLRE_OFF & PWRTE_ON 
__CONFIG _CONFIG2, WRT_OFF & BOR40V 
EndAsm
   
All_Digital true                  ; Alle poorten digitaal

Declare Adin_Res = 8              ; resolutie 8 bits
Declare Adin_Tad = frc            ; set RC osc
Declare Adin_Stime = 50           ; sample tijd 5

Declare LCD_RSPin PORTD.2         ; Reset display poort D.2
Declare LCD_ENPin PORTD.3         ; Enable display poort D.3
Declare LCD_DTPin PORTD.4         ; Data display poort D.4 t/m D.7

Symbol SERVO_PULS = PORTE.0

Symbol S1 = PORTA.0 
Symbol S2 = PORTA.1 





Cls                               ; Wis display

DelayMS 500                       ; Pauze 0.5 sec 


Clear                             ; Wis geheugen

;------------------------------------------------------
; ALS TRISA - TRISB - TRISC - TRISD OF TRISE IS 0, DAN
; STAAT DE POORT ALS EEN UITGANG.
; ALS TRISA - TRISB - TRISC - TRISD OF TRISE IS 1, DAN
; STAAT DE POORT ALS EEN INGANG.
;------------------------------------------------------ 

         ;543210                  ; Hulpregel poort A
PORTA  = %000000                  ; Maak poort A laag
TRISA  = %111111                  ; Poort_A I/O

         ;543210                  ; Hulpregel poort B
PORTB  = %000000                  ; Maak poort B laag
TRISB  = %000001                  ; Poort_B I/O

         ;76543210                ; Hulpregel poort C
PORTC  = %00000000                ; Maak poort C laag
TRISC  = %00000011                ; Poort_C I/O

         ;76543210                ; Hulpregel poort D
PORTD  = %00000000                ; Maak poort D laag
TRISD  = %00000000                ; Poort_D I/O

         ;210                     ; Hulpregel poort E 
PORTE  = %000                     ; Maak poort E laag
TRISE  = %000                     ; Poort_E I/O

         ;76543210                ; Hulpregel analoog
ADCON0 = %00000001                ; ADCON0 register 8 bit analoog

         ;76543210                ; Hulpregel analoog
;ADCON1 = %10000000                ; ADCON1 register 10 bit analoog

         ;543210                  ; Hulpregel analoog poort_B
;ANSELH = %000000                  ; ANSEL register analoog poort_B

;-------------------------
; HIER KOMT HET PROGRAMMA
;-------------------------

RUN:


    SERVO_PULS = 1
      DelayUS 1650
    SERVO_PULS = 0
      DelayMS 20

    If S1 = 1 Then
       GoTo POS_1
    EndIf
    
    If S2 = 1 Then
       GoTo POS_2
    EndIf
    
GoTo RUN

POS_1:


    SERVO_PULS = 1
      DelayUS 2500
    SERVO_PULS = 0
      DelayMS 20
    
    If S1 = 0 Then
       GoTo RUN
    EndIf
    
GoTo POS_1

POS_2:


    SERVO_PULS = 1
      DelayUS 850
    SERVO_PULS = 0
      DelayMS 20
    
    If S2 = 0 Then
       GoTo RUN
    EndIf
    
GoTo POS_2

End



Als je haar maar goed zit, GROETEN LAMBIEK.
Bavelt

Golden Member

Op 26 juli 2020 22:51:42 schreef Lambiek:
Je kunt toch gewoon een plus maken met een paar delays. Even met de scoop controleren of met analyser.

OK, terug naar de basis:

Met een heel simpel programma, met een fatsoelijke klokfrequentie (8Mhz) en een paar delays, werkt het ook:

pic basic code:

Program PWM_Test
Dim z1 as word

Main:

  OSCCON     = %01110000                                '8 Mhz internal
  ANSELH = 0
  TRISB = %00000000
  PORTB = %00000000

  portb.6 = 1
  Delay_ms(2000)

 While True
 Portb.6 = 0          'Test Led

 if z1 < 101 then
  PORTB.3 = 1
  Delay_ms(1)
  PORTB.3 = 0
  Delay_ms(1)
else
 PORTB.3 = 1
 Delay_ms(3)
 PORTB.3 = 0
 Delay_ms(2)
end if

 z1 = z1 + 1
 if z1 > 200 then
  z1 = 0
 end if
 
 Delay_ms(19)

 Wend
 
end.
Fouten zijn het bewijs dat je het probeert..
Bavelt

Golden Member

Ah, berichten hebben elkaar gekruist.. ;)

Fouten zijn het bewijs dat je het probeert..
Bavelt

Golden Member

Hier heb je een voorbeeld, hoe simpel kan het zijn.

Beide programmaatjes doen ongeveer hetzelfde. Ik laat de servo 180 gaden draaien, het voorbeeld van Lambiek werkt met schakelaartjes.
Principe is idd hetzelfe: als je zorgt dat je pulsen aanbiedt met een frequentie van 50 Hz (20ms delay) en de pulsduur ook aanpast via een delay, dan ben je er al.

[Bericht gewijzigd door Bavelt op maandag 27 juli 2020 11:40:53 (24%)

Fouten zijn het bewijs dat je het probeert..