Arduino Motor-Focus für APM 2,5“ OAZ

Status
Es sind keine weiteren Antworten möglich.

Edgar99

Aktives Mitglied
hier der Prototyp meines Selbstbau Motor-Fokus.
Bei den ersten Tests am Stern konnte er sich bereits bestens bewähren.


Link zur Grafik: http://abload.de/img/stepper-focf4uxo.jpg

Der Motor ist ein kleiner Nema 11 Schrittmotor (28mm x 28mm x 51mm lang)-> Motor .
Ein Zahnriemenantrieb (22/48 Zähne) untersetzt das ganze um Faktor 2. Bei einem Motorstrom von 0,6A kann der 2,5“APM OAZ dann ca. 2 Kg Last heben (für meine EOS450 reicht das leicht, eine etwas stärkere Untersetzung hätte aber wohl auch nix geschadet…).

Gesteuert wird der Motor über ein Arduino Nano Board mit USB Schnittstelle (das blaue Board im Foto)-> Prozessor. Ein Schrittmotortreiber (das violette Board) ist Huckepack aufgelötet -> Treiber. An diesem wird dann die 12V Versorgungsspannung und der Schrittmotor angeschlossen. Ein 47µF/63V Kondensator dient zur Glättung der Spikes vom Treiber. Der Prozessor wird über USB versorgt.

Die Software ist RoboFokus und damit ASCOM kompatibel. Ursprünglich wurde diese von Thomas Westerhoff, in BASCOM-AVR, für ein ATmega8 entwickelt -> Software . Diese läuft aber auch auf den Arduino Nano (ein ATmega328P Prozessor).
In der Software habe ich die Pins so umdefiniert, dass man, mit der Huckepack Verdrahtung, bereits alle Verbindungen zum Motortreiber herstellt.

Die größten Änderungen an der Software sind aber dadurch entstanden, dass ich die kostenlose Trial Version von BASCOM verwenden wollte und deshalb den Code auf 4096 Bytes zusammengestaucht habe. Dabei sind die Möglichkeit zur Handsteuerung und die Endlagenschalter entfallen. Außerdem waren gröbere Veränderungen in der Struktur der Software nötig (4096 Byte sind schon extrem wenig!).

Der kleine Motor läuft auch in der schnellsten Geschwindigkeitseinstellung und bei 32-fach Mikroschritt sehr gut (klingt wie beim Zahnarzt). Das Fahren des Motors ist dadurch beim Scharfstellen nicht sichtbar. Beim Mausklick scheint der Fokus in die nächste Position zu springen.

Link zur Grafik: http://abload.de/img/bahtinovxju9x.jpg
Hier mal ein Bild von meinen Tests.
Aufgenommen mit Bathinow-Maske, an meinem 8“, f/8, GSO-RC, mit einer EOS450, mit 20sek und 1600ASA (voller Bildauschnitt).
Im LiveView und 200% Lupe kann man perfekt scharfstellen. Bei 32-fach Mikroschritt und 2-fache Getriebeuntersetzung sieht man bei Schrittweiten von 50 Steps (das sind so 0,06 mm am OAZ!) gerade noch eine Variation in der Schärfe.
 
Hi Edgar,

sehr schönes Projekt - besonders die Hardware finde ich genial einfach.
 
Hi Edgar,

eine sehr schöne und kompakte Umsetzung.
Wenn das erst der Prototyp ist, wie wird das dann später aussehen...?!

CS Thorsten
 
Hi Edgar,

Du bist ja flott. Kaum haben wir drüber gesprochen, schon hast Dus umgesetzt. Großer Respekt!

Das sieht sehr gut aus! Dass die Handsteuerung und die Endlagenschalter entfallen sind, ist aber schon ziemlich ärgerlich. Willst Du Dir nicht mal die Vollversion von BASCOM AVR gönnen, oder vielleicht die Firmware doch mal auf "C" umstricken?

Dein Code würde mich übrigens interessieren. :-)

Ich komme leider einfach zeittechnisch momentan nicht zur Weiterentwicklung meiner neuen Version, obwohl das mit der versprochenen Bluetoothanbindung der Steuerung schon einwandfrei funktioniert.

Ich freue mich darauf was Du noch aus Deinem Prototypen machst und verfolge das mit Spannung.

Viele Grüße,
Jan-David

 
danke für das Feedback

@Jan-David
Ging eh sehr schnell, weil sich das Projekt als viel einfacher herausgestellt hat, als ich angenommen habe. Außerdem ist nur das drin, was ich wirklich brauche. Da ist noch viel Entwicklungspotenzial für Freaks drin...

Hier noch einige Hinweise, falls jemand noch weiterarbeiten mag:

Die Software stammt ursprünglich von Thomas Westerhoff. Auf seiner Homepage gibt es dazu noch grundlegende Hinweise und weitere Tipps und Tricks.

Ich habe den Code auf 4k zusammengestaucht um mit dem kostenlosen BASCOM Tool zu arbeiten. Dabei ist die Temperaturanzeige, die Endlagenschalter und die Handsteuerung geopfert worden. Da ich ausschließlich Fotografisch und mit Netbook unterwegs bin, brauche ich das nicht unbedingt...
Der „Stop“ Button in RoboFocus fuktioniert nicht (ich denke, in der originalen Version funktionierte dieser ebenfalls nicht?).
Mir ist es nicht gelungen, in BASCOM, Variablen im EEPROM vorzubesetzen. Wenn man den Code frisch aufgespielt hat, stehen deshalb unsinnige Werte im EEPROM. RoboFokus meckert daher beim ersten Starten. Wenn man dann aber gültige Werte eingibt (und mit ENTER bestätigt) funktioniert es ab dann.
Die StepSize Einstellung in RoboFokus ist ebenfalls ohne Funktion: Der Mikroschritt Betrieb ist fest auf 32-fach eingestellt.
Wie in der orginalen Version funktioniert die Duty Cycle Einstellung wie folgt: Ist der Wert kleiner als 50, wird der Motor nach dem Positionieren stromlos geschalten, sonst bleibt er an.

Der Prozessor ist eigentlich für das Arduino Entwicklungstool gedacht. Der Code wird dort per USB und einem Bootloader aufgespielt. In BASCOM muss man allerdings - in altväterlicher Sitte - über ein ISP-Kabel programmieren. Die spezielle RESET Funktionalität des Arduino, über den USB Bus, muss man daher deaktivieren. Ich habe dazu den Kondensator, auf der Rückseite der Platine, nahe am Pin1 vom FTDI-Chip entfernt.

Für die Huckepack Lösung habe ich die Pfostenleiste aus dem Prozessor Board ausgelötet und umgekehrt wieder eingelötet. Das ist seeehr haarig, da sich die feinen Pads sehr schnell ablösen. Vielleicht finden ja jemand eine bessere Lösung dazu...

Auf der Schrittmotorplatine ist ein Poti zu Einstellung des Motorstromes. Der Einstellbereich ist allerdings viel größer als der Chip verkraftet (mehr als 1,6A sollte man nicht einstellen, sonst verbrennt man sich die Finger, entweder am Chip, oder am Motor). Man sollte also unbedingt vorher das Poti auf den passenden Wert einstellen, bevor man den Motor ansteckt...

Neben den 8 Signalleitungen, die ja bereits durch das Hucke-packen angeschlossen werden, muss man noch die GND Leitung von Schrittmotortreiber zum Prozessor verdrahten. Ich habe dazu eine Stück Draht, vom GND PIN des Treibers, zu der benachbarten USB Buchse verlötet.

Wenn ich rausgefunden habe, wie man Textdatein, hier im Forum, anhängt, stelle ich mal meinen Source-Code ein
 
Hi Edgar,
feines Projekt, das gefällt.
Zumal ich ähnliche Komponenten hier noch rumfliegen habe...
Das mit dem SourceCode ist ganz einfach: schließe ihn mit einem "code" und "/code" jeweils in eckigen Klammern ein.
 
Hi Ralf,

guter Tipp :super:

Code:
'Version Beta0
' ursprünglich von Thomas Westerhoff
'gändert auf 4K Code, ohne Enlagenschalter, ohne Handsteuerung, ohne Temperaturanzeige 
'von Edgar99
'--------------------------------------------------------------


$loadersize = 512
$regfile = "m328pdef.dat"
$crystal = 16000000
$baud = 19200
$hwstack = 128
$swstack = 128
$framesize = 32

Config Serialin = Buffered , Size = 20


' Bits für die Motoransteuerung

Config Pinb.0 = Output
Config Pinb.1 = Output
Config Pinb.2 = Output
Config Pind.3 = Output
Config Pind.4 = Output
Config Pind.5 = Output
Config Pind.6 = Output
Config Pind.7 = Output

Mot_dir Alias Portb.2                                       ' Richtung  CW/CCW
Mot_stp Alias Portb.1                                       ' Takt      MOT_STP
Mot_sleep Alias Portb.0                                     ' Sleep     L = Sleep
Mot_reset Alias Portd.7                                     ' Reset     L = RESET
Mot_m2 Alias Portd.6                                        ' µ-Step    Bit2
Mot_m1 Alias Portd.5                                        ' µ-Step    Bit1
Mot_m0 Alias Portd.4                                        ' µ-Step    Bit0
Mot_en Alias Portd.3                                        ' Enable    L = Enable




Dim Inpuffer As String * 10
Dim Zeichen As String * 1
Dim Tempstr As String * 10
Dim Temp As String * 10
Dim Temp1 As String * 10
'Dim Gotochar As String * 1
Dim Schecksum As String * 1
Dim I As Integer
Dim Count As Integer
Dim Value As Word                                           'Speicher für die zu tätigende Schrittanzahl
Dim Actualposition As Word                                  'Speicher für aktuelle Position
Dim Dutycycle As Byte
Dim Stepdelay As Byte
Dim Stepsize As Byte
'Dim Moveout As Bit
Dim Astop As Bit
Dim Tmpb As Byte
Dim Bs As Byte
Dim I1 As Integer
Dim Steps As Word
Dim Timerdelay As Byte
Dim Ar(2) As Byte                                           'Array für die Register
'Dim Comm_en As Byte
Dim Backlash As Word
Dim Bldir As Byte



'Variablen für Funktionen
Dim Ts As String * 10
Dim Laenge As Integer
Dim T As String * 5
Dim Valuestr As String * 8
Dim Cs As String * 1
Dim Bytesum As Integer
Dim Charval As Byte
Dim Zeichtmp As String * 1



' Konfigurationsvariablen im EEprom
Dim Emaxsteps As Eram Integer
Dim Edutycycle As Eram Byte
Dim Estepdelay As Eram Byte
Dim Estepsize As Eram Byte
Dim Ebacklash As Eram Integer
Dim Ebldir As Eram Byte



'Deklarationen für den Datentransfer per RS232
'Datenstruktur für den Commandstring
Dim Subcommandbyte As Byte                                  '1 byte
Dim V1 As Word                                              '2 byte
Dim V2 As Word                                              '2 byte
Dim V3 As Word                                              '2 byte
Dim Chksum As Byte                                          '1 byte
Dim Command(8) As Byte At Subcommandbyte Overlay            ' overlay für den Commandstring
Dim C As Byte                                               'Zeichen puffer
Dim D As Byte                                               'Zähler
Dim Commandstr As String * 8
Dim Subcommandchar As String * 1



'Subfunktionen
'Declare Sub Empfang
Declare Function Encodevalue(byval Value As Word) As String
Declare Function Valuetoint(cmd As String) As Word
Declare Function Getcommandvalue As Integer
Declare Function Computechecksum(cmd As String) As String
Declare Sub Responsecommand(byval Subchar As String , Cmd As String)
'Declare Sub Moveincommand(w As Byte)
'Declare Sub Moveoutcommand(w As Byte)


'*******************************************************************************
'Hauptprogrammstart  initialisierung
'*******************************************************************************

'Disable Interrupts                                          'zuerst alle Interrupts Disablen
'Disable Timer1
'Disable Int0
'Disable Int1

Reset Mot_stp
Set Mot_en                                                  ' Steppertreiber disable
Set Mot_sleep

Set Mot_m2                                                  ' Mikroschritte festlegen
Set Mot_m1
Set Mot_m0

Reset Mot_reset                                             ' Motortreiber resetten
Waitms 2
Set Mot_reset

Actualposition = 1
                                                            'Variablen vom EEProm holen
Dutycycle = Edutycycle
Stepdelay = Estepdelay
Stepsize = Estepsize
Backlash = Ebacklash
Bldir = Ebldir                                              ' 51 oder 50 für Backlash IN bzw. Out

Config Timer0 = Timer , Prescale = 1024
On Timer0 Tim0_isr
Stop Timer0
Enable Interrupts
Enable Timer0

'Comm_en = 1                                                 'Comm Einschalten


'###############################################################################


'Hauptschleife
'Warter auf ein Zeichen von der RS232 Schnittstelle
'===============================================================================
'###############################################################################

D = 0                                                       ' auf steuerzeichen warten

Do

 If Ischarwaiting() = 1 Then
  Gosub Empfang                                             'Wenn einzeichen kommt dann Empfangsroutine aufrufen
 End If

 If D = 9 Then
 Gosub Decodecommand
   End If
                                                         'Wenn es ein kommando war
Loop
End



' Falls ein "F" gesendet wird, werden die Nachfolgenden 8 Byte gelesen
'===============================================================================
Empfang:

'Stop Timer0                                                 'Empfang hat vorrang vor
C = Inkey()                                                 'Motor
   If D > 0 Then
      If D < 8 Then Command(d) = C
      Incr D
   Else
      If C = "F" Then Incr D
   End If
Return


'===============================================================================

'Liest den Commandstring aus und zerlegt ihn in seine Bestandteile
'===============================================================================
Decodecommand:

     Temp = ""
     D = 0

     Subcommandchar = Chr(subcommandbyte)

     'value auslesen
     For I = 2 To 7
       Temp = Temp + Chr(command(i))
     Next I

     If Temp = "VVVVVV" Then
      Gosub Dostop
      Return
     End If


     Value = Valuetoint(temp)

     Tmpb = 0
     Select Case Subcommandchar                             'in entsprechende Unterroutinen verzweigen
       Case "V" : Temp = "003.14"
                   Call Responsecommand( "V" , Temp)        'Firmware zurück geben
       Case "G" : Gosub Gotocommand
       Case "I" : Gosub Moveincommand
       Case "O" : Gosub Moveoutcommand
       Case "S" : Gosub Positioncommand
       Case "B" : Gosub Backlashcommand
       Case "C" : Gosub Configcommand
'       Case Else : Print "Fehler"
     End Select
Return


'===============================================================================
'Wenn Backlash Commando empfangen wurde
'===============================================================================
Backlashcommand:

   If Command(2) <> 48 Then                                 ' wenn neuer Wert empfangen wird
      Bldir = Command(2)
      Backlash = Value
      Ebacklash = Backlash                                  ' neuen Wert ins EEprom
      Ebldir = Bldir
   End If

   Temp = Encodevalue(backlash)
   Temp = Chr(bldir) + Temp
   Call Responsecommand( "B" , Temp)                        ' aktuelen Wert zurücksenden

Return

Return


'===============================================================================
'Wenn Position Commando empfangen wurde
'===============================================================================
Positioncommand:


  If Value <> 0 Then
      Actualposition = Value                                ' neue Position setzen
  End If

   Temp1 = Encodevalue(actualposition)                      ' aktuelle Position melden
   Call Responsecommand( "D" , Temp1)


Return


'===============================================================================
'Wenn Config Commando empfangen wurde
'===============================================================================
Configcommand:

     Bs = 0
     For I = 2 To 4
       Bs = Bs + Command(i)
     Next I

     If Bs = 144 Then                                       '3x ASCII zeichen "0" aufsummiert
      Temp = Chr(dutycycle)                                 'Aktuelle Werte zurückgeben
      Temp = Temp + Chr(stepdelay)
      Temp = Temp + Chr(stepsize)
      Temp = Temp + "000"                                   'neue werte zurück geben

     Else
      Dutycycle = Command(2)                                'Neue Werte schreiben
      Stepdelay = Command(3)
      Stepsize = Command(4)
      Edutycycle = Dutycycle
      Estepsize = Stepsize
      Estepdelay = Stepdelay                                'ins EEprom
      Gosub Dostop
      Temp = Chr(dutycycle) + Chr(stepdelay) + Chr(stepsize) + "000"       'Aktuelle Werte zurückgeben
     End If

    Call Responsecommand( "C" , Temp)

Return



'===============================================================================
' Berechnet den String mit vorangestellten Nullen eines numerischen Wert
'===============================================================================
Function Encodevalue(byval Value As Word) As String

  Ts = Str(value)
  Laenge = Len(ts)

  For I = Laenge To 4
    Ts = "0" + Ts                                           'nullen voranstellen
  Next I

  Encodevalue = Ts


End Function


'===============================================================================
' Berechnet den numerischen Wert im Kommando und gibt ihn zurück
'===============================================================================
Function Valuetoint(cmd As String) As Word

  T = Right(cmd , 5)
  Valuetoint = Val(t)

End Function


'===============================================================================
' Berechnet das Checksummenzeichen für den Commandstring
'===============================================================================
Function Computechecksum(byval Cmd As String) As String * 1

  Bytesum = 0
  For I = 1 To Len(cmd)
    Zeichtmp = Mid(cmd , I , 1)
    Charval = Asc(zeichtmp)
    Bytesum = Bytesum + Charval
  Next I

  Bytesum = Bytesum Mod 256
  Computechecksum = Chr(bytesum)

End Function


'===============================================================================
' hängt die Prüfsumme an den Commandstring und gibt ihn auf die RS232 Schnittst.
'===============================================================================
Sub Responsecommand(byval Subchar As String , Cmd As String)

  Dim Resp As String * 10

  If Len(cmd) = 5 Then Cmd = "0" + Cmd

   Resp = "F"                                               '+ Subchar + Cmd + Computechecksum(resp)
   Resp = Resp + Subchar
   Resp = Resp + Cmd
   Schecksum = Computechecksum(resp)
   Resp = Resp + Schecksum
  Print Resp

End Sub


'###############################################################################
'Motorbewegungen
'###############################################################################

'==============================================================================
'Motor Stop
'==============================================================================
Dostop:

   Temp1 = Encodevalue(actualposition)
   Call Responsecommand( "D" , Temp1)                       ' aktuelle Position zurückgeben

    If Dutycycle < 50 Then
      Set Mot_en                                            ' Motor Disable
    Else
      Reset Mot_en
    End If

Return

'==============================================================================
'Backlash ausführen
'==============================================================================
 Dobacklash:

   If Backlash = 0 Then
     Return
   End If

   Waitms 20
                                                             'Backlash Korrektiur nach innen
   If Bldir = 51 Then
      If Mot_dir = 1 Then                                   'abbrechen wenn bewegung nach außen
        Return
      End If

      Set Mot_dir                                           'Richtung nach Außen
      Steps = Backlash

   Else                                                     'Backlash Korrektur nach innen
      If Mot_dir = 0 Then                                   'Wenn nach innen gefahren wurde dann exit
        Return
      End If

      Reset Mot_dir                                         'Richtung nach innen
      Steps = Backlash

   End If

Gosub Motor_loop

Return


'==============================================================================
'Interrupt Timer für Motor bewegen
'===============================================================================
Motor_loop:
:
      Reset Mot_en                                          'Motor Einschalten
      Reset Astop

      Timerdelay = 10 * Stepdelay                           ' Timer initialisieren
      Timerdelay = 255 - Timerdelay

      Start Timer0                                          ' Interrupt Timer starten


      Do
      Loop Until Astop = 1                                  ' warten bis Zielposition erreicht

      Stop Timer0

Return

'==============================================================================
'Motor auf die in Value angegebenen Position fahren
'===============================================================================
Gotocommand:

   If Value = 0 Then
      Temp1 = Encodevalue(actualposition)
      Call Responsecommand( "D" , Temp1)                    ' aktuelle Position melden
    Else
         If Value < Actualposition Then
          Value = Actualposition - Value
          Gosub Moveincommand
         Else
          Value = Value - Actualposition
          Gosub Moveoutcommand
         End If
    End If
Return


'===============================================================================
'Bewegt den Motor um die in Value angegebenen Steps nach innen
'===============================================================================
Moveincommand:

   Reset Mot_dir


   If Bldir = 51 Then                                       ' Backlash bestimmen
     Steps = Value + Backlash
   Else
     Steps = Value
   End If

Gosub Motor_loop
Gosub Dobacklash
Gosub Dostop

Return


'===============================================================================
'Bewegt den Motor um die in Value angegebenen Steps nach außen
'===============================================================================
Moveoutcommand:

   Set Mot_dir

   If Bldir = 50 Then                                       ' Backlash bestimmen
     Steps = Value + Backlash
   Else
     Steps = Value
   End If

Gosub Motor_loop
Gosub Dobacklash
Gosub Dostop

Return

'===============================================================================
'Timer INTERRUPT für Schrittimpulse
'===============================================================================
Tim0_isr:


   Timer0 = Timerdelay                                      'Timerwert zurücksetzen

Set Mot_stp

  Decr Steps

  If Mot_dir = 0 Then
    Decr Actualposition
'    Print "I"
  Else
    Incr Actualposition
'    Print "O"
  End If

Reset Mot_stp

  If Steps = 0 Then
   Set Astop
  End If


Return
 
Ah wunderbar, vielen Dank. Ich sehe Du hast auch wie angedacht den möglichen Schrittbereich vergrößert. Es gibt auch in der "Vollversion" der Firmware noch ein paar weitere Bugs in Zusammenhang mit der Robofocus Software.

Was mich noch interessieren würde, wie gut harmonieren denn die 16 MHz mit denen der AtMega 32 getaktet ist mit dem UART Takt? Konntest Du da schon Schwankungen feststellen? Nutzt der Arduino den internen Oszillator, oder ist da ein externer Quarz drauf?

Grüße,
Jan-David
 
Hallo Jan-David,

richtig Erkannt, der Verfahrweg geht jetzt bis 65535 Schritten...

Auf den Arduino-Platinchen ist ein 16MHz Quarz. In der 3-ten Code Zeile wird dies BASCOM mittgeteilt. In der 4-ten Zeile wird dann die Baudrate festgelegt. Alles andere macht BASCOM.
Das funktioniert ganz gut. Mit der Datenübertragung hatte ich keine Probleme.

Die kleinen Bug's, die ich bemerkt habe, sind weiter oben aufgelistet.
Sind Dir noch weitere aufgefallen?
 
Hi Edgar, mir ist schon klar wo das in der Firmware steht. ;-) Meine Frage ist eher wie das mit den Timings klappt und wie groß Deine zeitliche Abweichung ist. Also bspw. wenn eine Umdrehung des Motors laut Deines Timers x Sekunden dauern soll, diese x Sekunden aber unter- oder überschritten werden.

Deine Firmware hab ich jetzt noch nicht getestet, aber folgender Bug ist noch aufgefallen:

Direkt nach Start der Robofocus Software lässt sich keine der gespeicherten Fokuspositionen direkt anfahren. Der Motor hüpft dann nur einen Schritt. Fährt man jedoch manuell erstmal 100 Schritte raus und wieder rein funktioniert die Positionierung danach reibungslos.

Viele Grüße,
Jan-David
 
Hallo Jan-David,

aha, "gespeicherte Fokuspositionen", diese Funktion habe ich noch gar nicht getestet.

Mit dem Timing gibt es keine Probleme. Der Prozessor ist ja Quarzgesteuert und mit 16MHz, Impulse im ms Bereich zu generieren, ist kein Problem. Das hab ich mit meinem Oscar überprüft.

Der Prescaler ist auf 1024 gesetzt. In Unterprogramm "Motor-Loop" wird der Takt nocheinmal um 10 geteilt. Ein Step in RoboFokus entspricht dann real 0,64ms.
Da der Timer0 nur ein 8-Bit Zähler ist, kann man den Teiler auf max. 12 setzen, damit es bei der Einstellung "20Steps" keinen Überlauf gibt.
Wenn man die Einstellung Eichen will, so dass 1Step exakt 1ms entspicht, kann man den 16 bittigen Timer1 verwenden.

Ich hab ganz vergessen zu erwähnen, das die Software (wie auch schon die originale Version von Thomas Westerhoff) natürlich von jedemann verbessert werden darf ;-)



 
Hallo Edgar,
das issa ma was dolles.

Die Preise in deinem ersten Betrag haben mich aber etwas abgeschreckt.

Hab selbst mal geschaut und jetzt sieht es schon vieeel besser aus.

9,-€ SainSmart Nano V3 (von irgendwo)
13,-€ DRV8825 Stepper Motor Driver Carrier
14,-€ Stepper Motor: Bipolar, 200 Steps/Rev, 20x30mm, 3.9V, 600mA
von hier.
20 Teuronen für Zahnriemenscheiben.

Da man nicht viel löten muss, ist das eine feine Sache.
Ne, tolle Idee, keine Frage.

Endlagenschalter brauch ich nicht und Handbetrieb werd ich wohl über einen kleinen Analog-Stick realisieren.
So was hier.

CS
Pit


PS

Zahnriemenscheiben
 
Zuletzt von einem Moderator bearbeitet:
Hallo Pit,

das SainSmart Board sieht genau so aus wie mein 4x teureres Arduino. Sogar die Farbe ist gleich! Nur der Hersteller Aufdruck ist anders !!!

Der Motor scheint mir aber ein wenig schwach zu sein. Für ein paar € mehr gibt es dort auch einen 5x stärkeren Motor (28x45, 4,5V, 670mA). Das ist die Größe, die ich auch verwendet habe, kostet dort aber weniger als die Hälfte...
Wenn man nur eine 1:2, oder 1:3 Untersetzung hat, ist diese Größe wohl das Minimum.

Inzwischen habe ich die Untersetzung auf 16/48 Zähnen, also 1:3, geändert.
Das 16-er Ritzel bekommt man gelegentlich auch schon fertig gebohrt bei ebäh. Das wird dort für Selbstbau 3-D Drucker angeboten.
Ein 48-er Ritzel ist meistens eh schon auf 6mm gebohrt und passt dann auf die meisten OAZ's.
 
Hiho,

sag mal mit welcher Robofocus Software arbeitest du?

Ich hab schon beim öffnen der Com Pufferüberläufe.

CS
Pit
 
Hi Pit,

...aber nur beim ersten mal...?

Ich hab das Problem weiter oben beschrieben: "Mir ist es nicht gelungen, in BASCOM, Variablen im EEPROM vorzubesetzen. Wenn man den Code frisch aufgespielt hat, stehen deshalb unsinnige Werte im EEPROM. RoboFokus meckert daher beim ersten Starten. Wenn man dann aber gültige Werte eingibt (und mit ENTER bestätigt) funktioniert es ab dann"

Also im Config Menü Werte für Backlash Compensation, Duty Cycle, MicrostepPause und StepSize eingeben und jeweils mit Enter bestätigen.

Hast du das mal ausprobiert?

Meine Robofokus Version ist übrigens 3.2.3.
 
So an alle Nachbauwilligen,

es lüppt. Unter Windows7/8 niemals den FTDI Treiber 2.8.18 nehmen. Seiner einer funktioniert nicht mit dem Nano Board.

Nehmt den 2.8.14, ist im Arduinoverzeichniss. Die Pufferüberläufe sind nach parametrieren weg.

Echt simple und einfach aufzubauen.

Grüße
Pit
 
Moin moin,

ich hab mal ein bissele im Code rumgefuscht.

Stopfunktion funktioniert jetzt. Außerdem kann man jetzt die Endsdtufe damit abschalten. Sofortiger Stop, Endstufe deaktiviert, Aktuellen Werte werden gespeichert.
Durch Betätigen des In oder Out Buttons wird die Endstufe aktiviert, erst dann kann man irgendwas anfahren

Parameter Dutycycle etwas mißbraucht.
Dort kann man jetzt den Microstep-Modus wählen.
1,2,4,8,16,32 entsprcht eben der Anzahl der Mikroschritte bei Abschalten der Endstufe nach jedem Befehl oder
51,52,54,58,66,82 ditto. Jetzt wird die Endstufe jedoch nicht abgeschaltet. Was im Mikroschrittmodus auch sinn macht. Wenn jedesmal die Endstufe abgeschaltet wird, spring der Stepper immer in den Vollschritt und zwar rückwärts oder vorwärts.
100 mal fokusiert und nichts ist da noch genau.

Oh ja, im Code hab ich den Prescaler auf 64 stehen, war mir etwas zu langsam.


Sonnige Grüße

Code:
'Version Beta0
' ursprünglich von Thomas Westerhoff
'gändert auf 4K Code, ohne Enlagenschalter, ohne Handsteuerung, ohne Temperaturanzeige
'von Edgar99,
'5.07.13 Pit  V3.28 ;) Bug Notaus, Microsteps implementiert
'
'
'
'
'
'--------------------------------------------------------------


$loadersize = 256
$regfile = "m328pdef.dat"
$crystal = 16000000
$baud = 19200
$hwstack = 128
$swstack = 128
$framesize = 32

' Bits für die Motoransteuerung

Config Pinb.0 = Output
Config Pinb.1 = Output
Config Pinb.2 = Output
Config Pind.3 = Output
Config Pind.4 = Output
Config Pind.5 = Output
Config Pind.6 = Output
Config Pind.7 = Output

Mot_dir Alias Portb.2                                       ' Richtung  CW/CCW
Mot_stp Alias Portb.1                                       ' Takt      MOT_STP
Mot_sleep Alias Portb.0                                     ' Sleep     L = Sleep
Mot_reset Alias Portd.7                                     ' Reset     L = RESET
Mot_m2 Alias Portd.6                                        ' µ-Step    Bit2
Mot_m1 Alias Portd.5                                        ' µ-Step    Bit1
Mot_m0 Alias Portd.4                                        ' µ-Step    Bit0
Mot_en Alias Portd.3                                        ' Enable    L = Enable




Dim Inpuffer As String * 10
Dim Zeichen As String * 1
Dim Tempstr As String * 10
Dim Temp As String * 10
Dim Temp1 As String * 10
'Dim Gotochar As String * 1
Dim Schecksum As String * 1
Dim I As Integer
Dim Count As Integer
Dim Value As Word                                           'Speicher für die zu tätigende Schrittanzahl
Dim Actualposition As Word                                  'Speicher für aktuelle Position
Dim Dutycycle As Byte
Dim Stepdelay As Byte
Dim Stepsize As Byte
'Dim Moveout As Bit
Dim Astop As Bit
Dim Tmpb As Byte
Dim Bs As Byte
Dim I1 As Integer
Dim Steps As Word
Dim Timerdelay As Byte
Dim Ar(2) As Byte                                           'Array für die Register
'Dim Comm_en As Byte
Dim Backlash As Word
Dim Bldir As Byte
dim notausflag as bit


'Variablen für Funktionen
Dim Ts As String * 10
Dim Laenge As Integer
Dim T As String * 5
Dim Valuestr As String * 8
Dim Cs As String * 1
Dim Bytesum As Integer
Dim Charval As Byte
Dim Zeichtmp As String * 1



' Konfigurationsvariablen im EEprom
Dim Emaxsteps As Eram Integer
Dim Edutycycle As Eram Byte
Dim Estepdelay As Eram Byte
Dim Estepsize As Eram Byte
Dim Ebacklash As Eram Integer
Dim Ebldir As Eram Byte



'Deklarationen für den Datentransfer per RS232
'Datenstruktur für den Commandstring
Dim Subcommandbyte As Byte                                  '1 byte
Dim V1 As Word                                              '2 byte
Dim V2 As Word                                              '2 byte
Dim V3 As Word                                              '2 byte
Dim Chksum As Byte                                          '1 byte
Dim Command(8) As Byte At Subcommandbyte Overlay            ' overlay für den Commandstring
Dim C As Byte                                               'Zeichen puffer
Dim D As Byte                                               'Zähler
Dim Commandstr As String * 8
Dim Subcommandchar As String * 1



'Subfunktionen
'Declare Sub Empfang
Declare Function Encodevalue(byval Value As Word) As String
Declare Function Valuetoint(cmd As String) As Word
Declare Function Getcommandvalue As Integer
Declare Function Computechecksum(cmd As String) As String
Declare Sub Responsecommand(byval Subchar As String , Cmd As String)
'Declare Sub Moveincommand(w As Byte)
'Declare Sub Moveoutcommand(w As Byte)


'*******************************************************************************
'Hauptprogrammstart  initialisierung
'*******************************************************************************

'Disable Interrupts                                          'zuerst alle Interrupts Disablen
'Disable Timer1
'Disable Int0
'Disable Int1

Reset Mot_stp
Set Mot_en                                                  ' Steppertreiber disable
Set Mot_sleep

Reset Mot_m2                                                  ' Mikroschritte festlegen
Set Mot_m1
Set Mot_m0

Reset Mot_reset                                             ' Motortreiber resetten
Waitms 2
Set Mot_reset

Actualposition = 1

                                                            'Variablen vom EEProm holen
Dutycycle = Edutycycle
Stepdelay = Estepdelay
Stepsize = Estepsize
Backlash = Ebacklash
Bldir = Ebldir                                              ' 51 oder 50 für Backlash IN bzw. Out

Config Timer0 = Timer , Prescale = 64
On Timer0 Tim0_isr
Stop Timer0
Enable Interrupts
Enable Timer0

Config Serialin = Buffered , Size = 20, Bytematch = 86
'Comm_en = 1                                                 'Comm Einschalten




'###############################################################################


'Hauptschleife
'Warter auf ein Zeichen von der RS232 Schnittstelle
'===============================================================================
'###############################################################################

D = 0                                                       ' auf steuerzeichen warten

Do

 If Ischarwaiting() = 1 Then
  Gosub Empfang                                             'Wenn einzeichen kommt dann Empfangsroutine aufrufen
 End If

 If D = 9 Then
 Gosub Decodecommand
   End If
                                                         'Wenn es ein kommando war
Loop
End



' Falls ein "F" gesendet wird, werden die Nachfolgenden 8 Byte gelesen
'===============================================================================
Empfang:

'Stop Timer0                                                 'Empfang hat vorrang vor
C = Inkey()                                                 'Motor
   If D > 0 Then
      If D < 8 Then Command(d) = C
      Incr D
   Else
      If C = "F" Then Incr D
   End If
Return


'===============================================================================

'Liest den Commandstring aus und zerlegt ihn in seine Bestandteile
'===============================================================================
Decodecommand:

     Temp = ""
     D = 0

     Subcommandchar = Chr(subcommandbyte)

     'value auslesen
     For I = 2 To 7
       Temp = Temp + Chr(command(i))
     Next I

     'If Temp = "VVVVVV" Then
      'Gosub Dostopnot:
      'Return
     'End If


     Value = Valuetoint(temp)

     Tmpb = 0
     Select Case Subcommandchar                             'in entsprechende Unterroutinen verzweigen
       Case "V" : Temp = "003.28"
       Call Responsecommand( "V" , Temp)        'Firmware zurück geben
       Case "G" : Gosub Gotocommand
       Case "I" : Gosub Moveincommand
       Case "O" : Gosub Moveoutcommand
       Case "S" : Gosub Positioncommand
       Case "B" : Gosub Backlashcommand
       Case "C" : Gosub Configcommand
       Case Else : Print "Fehler"
     End Select
Return


'===============================================================================
'Wenn Backlash Commando empfangen wurde
'===============================================================================
Backlashcommand:

   If Command(2) <> 48 Then                                 ' wenn neuer Wert empfangen wird
      Bldir = Command(2)
      Backlash = Value
      Ebacklash = Backlash                                  ' neuen Wert ins EEprom
      Ebldir = Bldir
   End If

   Temp = Encodevalue(backlash)
   Temp = Chr(bldir) + Temp
   Call Responsecommand( "B" , Temp)                        ' aktuelen Wert zurücksenden

Return

Return


'===============================================================================
'Wenn Position Commando empfangen wurde
'===============================================================================
Positioncommand:


  If Value <> 0 Then
      Actualposition = Value                                ' neue Position setzen
  End If

   Temp1 = Encodevalue(actualposition)                      ' aktuelle Position melden
   Call Responsecommand( "D" , Temp1)


Return


'===============================================================================
'Wenn Config Commando empfangen wurde
'===============================================================================
Configcommand:

     Bs = 0
     For I = 2 To 4
       Bs = Bs + Command(i)
     Next I

     If Bs = 144 Then                                       '3x ASCII zeichen "0" aufsummiert
      Temp = Chr(dutycycle)                                 'Aktuelle Werte zurückgeben
      Temp = Temp + Chr(stepdelay)
      Temp = Temp + Chr(stepsize)
      Temp = Temp + "000"                                   'neue werte zurück geben

     Else
      Dutycycle = Command(2)                                'Neue Werte schreiben
      Stepdelay = Command(3)
      Stepsize = Command(4)
      Edutycycle = Dutycycle
      Estepsize = Stepsize
      Estepdelay = Stepdelay                                'ins EEprom
      Gosub Dostop
      Temp = Chr(dutycycle) + Chr(stepdelay) + Chr(stepsize) + "000"       'Aktuelle Werte zurückgeben
     End If

    Call Responsecommand( "C" , Temp)

    if dutycycle > 50 then                                      'Microsteps festlegen
        dutycycle = dutycycle - 50
    endif

        Select Case dutycycle
       Case 1 :
        mot_m0 = 0
        mot_m1 = 0
        mot_m2 = 0
       Case 2 :
        mot_m0 = 1
        mot_m1 = 0
        mot_m2 = 0
       Case 4 :
        mot_m0 = 0
        mot_m1 = 1
        mot_m2 = 0
       Case 8 :
        mot_m0 = 1
        mot_m1 = 1
        mot_m2 = 0
       Case 16 :
        mot_m0 = 0
        mot_m1 = 0
        mot_m2 = 1
       Case 32 :
        mot_m0 = 1
        mot_m1 = 1
        mot_m2 = 1
        End Select

  Dutycycle = Edutycycle


Return



'===============================================================================
' Berechnet den String mit vorangestellten Nullen eines numerischen Wert
'===============================================================================
Function Encodevalue(byval Value As Word) As String

  Ts = Str(value)
  Laenge = Len(ts)

  For I = Laenge To 4
    Ts = "0" + Ts                                           'nullen voranstellen
  Next I

  Encodevalue = Ts


End Function


'===============================================================================
' Berechnet den numerischen Wert im Kommando und gibt ihn zurück
'===============================================================================
Function Valuetoint(cmd As String) As Word

  T = Right(cmd , 5)
  Valuetoint = Val(t)

End Function


'===============================================================================
' Berechnet das Checksummenzeichen für den Commandstring
'===============================================================================
Function Computechecksum(byval Cmd As String) As String * 1

  Bytesum = 0
  For I = 1 To Len(cmd)
    Zeichtmp = Mid(cmd , I , 1)
    Charval = Asc(zeichtmp)
    Bytesum = Bytesum + Charval
  Next I

  Bytesum = Bytesum Mod 256
  Computechecksum = Chr(bytesum)

End Function


'===============================================================================
' hängt die Prüfsumme an den Commandstring und gibt ihn auf die RS232 Schnittst.
'===============================================================================
Sub Responsecommand(byval Subchar As String , Cmd As String)

  Dim Resp As String * 10

  If Len(cmd) = 5 Then Cmd = "0" + Cmd

   Resp = "F"                                               '+ Subchar + Cmd + Computechecksum(resp)
   Resp = Resp + Subchar
   Resp = Resp + Cmd
   Schecksum = Computechecksum(resp)
   Resp = Resp + Schecksum
  Print Resp

End Sub


'###############################################################################
'Motorbewegungen
'###############################################################################

'==============================================================================
'Motor Stop
'==============================================================================

Dostop:

   Temp1 = Encodevalue(actualposition)
   Call Responsecommand( "D" , Temp1)                       ' aktuelle Position zurückgeben

    If Dutycycle < 50 Then
      Set Mot_en                                            ' Motor Disable
    Else
      Reset Mot_en
    End If

    reset notausflag
Return

Serial0charmatch:

  Set notausflag
  Set Mot_en

Return




'==============================================================================
'Backlash ausführen
'==============================================================================
 Dobacklash:

   If Backlash = 0 Then
     reset notausflag
     Return
   End If

   Waitms 20
                                                             'Backlash Korrektiur nach innen
   If Bldir = 51 Then
      If Mot_dir = 1 Then
        reset notausflag                                 'abbrechen wenn bewegung nach außen
        Return
      End If

      Set Mot_dir                                           'Richtung nach Außen
      Steps = Backlash

   Else                                                     'Backlash Korrektur nach innen
      If Mot_dir = 0 Then
        reset notausflag                                 'Wenn nach innen gefahren wurde dann exit
        Return
      End If

      Reset Mot_dir                                         'Richtung nach innen
      Steps = Backlash

   End If

Gosub Motor_loop
reset notausflag
Return


'==============================================================================
'Interrupt Timer für Motor bewegen
'===============================================================================
Motor_loop:
:
      Reset Mot_en                                          'Motor Einschalten
      Reset Astop

      Timerdelay = 10 * Stepdelay                           ' Timer initialisieren
      Timerdelay = 255 - Timerdelay

      Start Timer0                                          ' Interrupt Timer starten


      Do
      Loop Until Astop = 1  or notausflag = 1                                ' warten bis Zielposition erreicht

      Stop Timer0

Return

'==============================================================================
'Motor auf die in Value angegebenen Position fahren
'===============================================================================
Gotocommand:

   If Value = 0 Then
      Temp1 = Encodevalue(actualposition)
      Call Responsecommand( "D" , Temp1)                    ' aktuelle Position melden
    Else
         If Value < Actualposition Then
          Value = Actualposition - Value
          Gosub Moveincommand
         Else
          Value = Value - Actualposition
          Gosub Moveoutcommand
         End If
    End If
Return


'===============================================================================
'Bewegt den Motor um die in Value angegebenen Steps nach innen
'===============================================================================
Moveincommand:

   Reset Mot_dir


   If Bldir = 51 Then                                       ' Backlash bestimmen
     Steps = Value + Backlash
   Else
     Steps = Value
   End If

Gosub Motor_loop
Gosub Dobacklash
Gosub Dostop

Return


'===============================================================================
'Bewegt den Motor um die in Value angegebenen Steps nach außen
'===============================================================================
Moveoutcommand:

   Set Mot_dir

   If Bldir = 50 Then                                       ' Backlash bestimmen
     Steps = Value + Backlash
   Else
     Steps = Value
   End If

Gosub Motor_loop
Gosub Dobacklash
Gosub Dostop

Return

'===============================================================================
'Timer INTERRUPT für Schrittimpulse
'===============================================================================
Tim0_isr:


   Timer0 = Timerdelay                                      'Timerwert zurücksetzen

Set Mot_stp

  Decr Steps

  If Mot_dir = 0 Then
    Decr Actualposition
  Else
    Incr Actualposition
  End If

Reset Mot_stp

  If Steps = 0 Then
   Set Astop
  End If


Return

 
Zuletzt von einem Moderator bearbeitet:
huhu,
noch mal kurz nachgehakt.

Was hat es sich mit 1ms pro Step und 16bit Timer auf sich?

Wenn ich denn Prescaler auf 64 stelle und mit 250 lade gibts genau eine 1ms auch bei Prescaler 128 und Ladewert 125. Alles mit Timer0.

Gruß
Pit

 
Hi Pit,

in RoboFocus kann man ja, im Config-Menü, unter "MicrostepPause", die Geschwindigkeit des Motors einstellen. Da sind Werte von 1ms...20ms erlaubt. Wenn man da 20 einstellt und der Prescaler ist schon auf 64, gibt's ein Überlauf (20*64 = 1280, das ist größer als 255!!).
Der Prescaler darf deshalb höchstens 12 sein.

Übrigens gibt es ja in RoboFocus die Einstellung "StepSize", wo man die µ-Schritt Auflösung einstellen kann. Wäre es nicht besser gewesen, die Auswahl der Schrittauflösung dort unterzubringen, als unter "Duty Cycle"?

Ich vermute, dass du mit den aktuellen Erweiterungen eh schon über das 4K Code-Limit für die Demo Version bist?

Wenn ich deinen Code richtig verstehe, kann man den Motor, wenn er erst mal läuft, auch nicht sofort stoppen?
Ich hatte mal bei IN/OUT eine Null zu viel eingetippt. Der Motor ist dann dahergenudelt und es gab keine Möglichkeit ihn zu stoppen...
 
moin edgar,

ich schreib mal alles klein, bin in eile.

Code:

Timerdelay = 10 * Stepdelay ' Timer initialisieren
Timerdelay = 255 - Timerdelay

Beim Prescaler kannst du einstellen was du willst, ohne das der der Timmer überläuft. Stepdelay ist der Wert von 1-20. Selbst bei 20 liegst du unter 255. 255-10*20=55 Oder?

Der Motor bleibt sofort stehen wenn über den UART ein "V" empfangen wird. Beim configurieren des Empfangspuffer mach ich eine Bytematchabfrage auf "V" und springt sofort nach beenden des Timerinterrupts in den Bytematchinterrupt. 1 Timerinterrupt ist 1 Step.

Stepsize kann man parametrieren wie man will es wird nicht zum Controller übertragen oder hab ich was übersehen ?

Deshalb der Weg über Dutycycle.

Jop bin über 4k aber das hex-file kannst du auch so laden.
Ich häng es an wenn ich rausgefunden habe wie geht.

Nachtrag:
Du hast Recht Stepsize müßte übertragen werden. Morgen mal schauen.



So jetzt in die Sonne.
Pit
 
Zuletzt von einem Moderator bearbeitet:
Hi Pit,

du hast recht mit dem Prescaler. Der kann auf PRESCALE= 1|8|64|256|1024 eingestellt werden.

Ich hab da was verwechselt mit der Code Zeile
"Timerdelay = 10 * Stepdelay "
Die "10" darf maximal 12 sein, sonst gibt es den Überlauf.

Wenn 1 Step genau 1ms entsprechen soll, braucht man wohl den 16Bit Timer? Aber eigentlich ist das unwichtig. Die kleinen Motoren laufen bei 12V eh problemlos schneller als 1ms/Step. So kann man dieses Feature auch nutzen.
 
Hallo zusammen,

ich bin übern euren thread gestolpert und finde es ein sehr gute Sache :-)

Nun meine Frage: Unter welcher Lizenz läuft den das Ganze [GPL, FreeBSD, MIT]?

Grüße,
Emmanouil
 
Hallo Emmanouil,

die Software stammt ursprünglich von Thomas Westerhoff. Auf seiner Homepage heißt es "Da ich inzwischen am Nachfolger des Stepperfocuser bastele habe ich mich entschlossen, die Firmware frei zur Verfügung zu stellen. So kann sich jetzt jeder eigene Anpassungen vornehmen oder nach eigenen Wünschen umprogrammieren (z.B. zur Filterradsteuerung oder zum Field-Rotator)" .

Das gleiche gilt natürlich auch für meine Modefikationen.

Bei RoboFokus heißt es in der FAQ:
"Can I write my own control program for RoboFocus?
Yes. You can base it upon the control program we supply (it is open source), or write your own program to take advantage of the various RoboFocus commands that are a part of our documentation. The control program is also ASCOM compatible for those writing their own control routines."

@Pit:
Wie siehst du das? Du hast ja auch schon erhebliche Verbesserungen vorgenommen?

 
Hi Edgar,

schönes Projekt. Ich hab mir in gleicherweise einen Robofocus-Clone in C entwickelt. Allerdings mit Temperaturssensor.
Grüsse,
Gerrit
 
Hiho,

was den Code angeht, ist mir das schnuppe. Hätte ich ihn hier sonst gepostet? ;)

Wenn jemand im ersten Beitrag nach Urheberrecht, Lizensen und was weiß ich fragt, hört sich das nach Vermarktung an.
Schön, ein Focuser für 50 Teuronen.

Ansonsten füge ich gerade einen analogen Stick ein, dann kann man auch mit unterschiedlichen Geschwindigkeiten den Fokus verfahren.

@Edgar
Ich hab keine Möglichkeit gefunden den Microstep-Modus zu übertragen. Bleib also nur der Umweg über Dutycycle-

Sonnige Grüße Pit
 
Hi Pit,

der Microstep Modus wird zusammen mit dem DutyCycle und dem StepDelay übertragen. Das steht so im Appendix1, unter FCABCDEFZ, vom "RoboFokus User Manual" (siehe Downloads).
Eigentlich sollte im Source Code schon alles da sein!?
 
Hi Edgar,

du hast Recht. Hab keine Datenübertragung gesehen, da beim Return im Feld Stepsize nichts passiert. Ändere ich dort den Wert und geh ins Feld Dutycycle oder Stepsdelay wird der Wert gesendet. Habs geändert. Dutycycle wieder wie er war und µSteps wird in Stepsize eingetragen.

Hab ein Joystic-Poti eingebunden auf Anschlusspunkt A5 entspricht dann ADC Channel 5. Läuft gut und man kann jetzt mit beliebiger Geschwindikkeit hin und her fahren. Die Kombination Arduino+Steppertreiber läuft ausgesprochen gut. Mit deinem 28x28mm Stepper komm ich im Handbetrieb auf schlappe 2200U/m, das ist schon echt gut. Im 1/32 Stepp-Betrieb läuft es ohne "Mikroruckler", echt toll.

Mit dem Dingen könnte man viele tolle Sachen machen.

Endstufen für Teleskopsteuerung, schnucklige kleine Ansteuerung für Barndoors usw. Na man müsste viel mehr Zeit haben.

Code:
'Version Beta0
$PROG &HFF,&HFF,&HDF,&HFF' generated. Take care that the chip supports all fuse bytes.
' ursprünglich von Thomas Westerhoff
'gändert auf 4K Code, ohne Enlagenschalter, ohne Handsteuerung, ohne Temperaturanzeige
'von Edgar99,
'5.07.13 Pit  V3.28 ;) Bug Notaus, Microsteps implementiert
'17.07.13 Pit V3.28 Joystic-Poti implementiert, 1/4 Steppmodus bis 2200U/m aua
'
'
'
'
'--------------------------------------------------------------


$loadersize = 256
$regfile = "m328pdef.dat"
$crystal = 16000000
$baud = 19200
$hwstack = 128
$swstack = 128
$framesize = 32

' Bits für die Motoransteuerung

Config Pinb.0 = Output
Config Pinb.1 = Output
Config Pinb.2 = Output
Config Pind.3 = Output
Config Pind.4 = Output
Config Pind.5 = Output
Config Pind.6 = Output
Config Pind.7 = Output

Mot_dir Alias Portb.2                                       ' Richtung  CW/CCW
Mot_stp Alias Portb.1                                       ' Takt      MOT_STP
Mot_sleep Alias Portb.0                                     ' Sleep     L = Sleep
Mot_reset Alias Portd.7                                     ' Reset     L = RESET
Mot_m2 Alias Portd.6                                        ' µ-Step    Bit2
Mot_m1 Alias Portd.5                                        ' µ-Step    Bit1
Mot_m0 Alias Portd.4                                        ' µ-Step    Bit0
Mot_en Alias Portd.3                                        ' Enable    L = Enable




Dim Inpuffer As String * 10
Dim Zeichen As String * 1
Dim Tempstr As String * 10
Dim Temp As String * 10
Dim Temp1 As String * 10
'Dim Gotochar As String * 1
Dim Schecksum As String * 1
Dim I As Integer
Dim Count As Integer
Dim Value As Word                                           'Speicher für die zu tätigende Schrittanzahl
Dim Actualposition As Word                                  'Speicher für aktuelle Position
Dim Dutycycle As Byte
Dim Stepdelay As Byte
Dim Stepsize As Byte
'Dim Moveout As Bit
Dim Astop As Bit
Dim Tmpb As Byte
Dim Bs As Byte
Dim I1 As Integer
Dim Steps As Word
Dim Timerdelay As Byte
Dim Ar(2) As Byte                                           'Array für die Register
'Dim Comm_en As Byte
Dim Backlash As Word
Dim Bldir As Byte
dim notausflag as bit
Dim anain as word
dim anainin as byte
dim anainaus as byte

'Variablen für Funktionen
Dim Ts As String * 10
Dim Laenge As Integer
Dim T As String * 5
Dim Valuestr As String * 8
Dim Cs As String * 1
Dim Bytesum As Integer
Dim Charval As Byte
Dim Zeichtmp As String * 1



' Konfigurationsvariablen im EEprom
Dim Emaxsteps As Eram Integer
Dim Edutycycle As Eram Byte
Dim Estepdelay As Eram Byte
Dim Estepsize As Eram Byte
Dim Ebacklash As Eram Integer
Dim Ebldir As Eram Byte



'Deklarationen für den Datentransfer per RS232
'Datenstruktur für den Commandstring
Dim Subcommandbyte As Byte                                  '1 byte
Dim V1 As Word                                              '2 byte
Dim V2 As Word                                              '2 byte
Dim V3 As Word                                              '2 byte
Dim Chksum As Byte                                          '1 byte
Dim Command(8) As Byte At Subcommandbyte Overlay            ' overlay für den Commandstring
Dim C As Byte                                               'Zeichen puffer
Dim D As Byte                                               'Zähler
Dim Commandstr As String * 8
Dim Subcommandchar As String * 1



'Subfunktionen
'Declare Sub Empfang
Declare Function Encodevalue(byval Value As Word) As String
Declare Function Valuetoint(cmd As String) As Word
Declare Function Getcommandvalue As Integer
Declare Function Computechecksum(cmd As String) As String
Declare Sub Responsecommand(byval Subchar As String , Cmd As String)
'Declare Sub Moveincommand(w As Byte)
'Declare Sub Moveoutcommand(w As Byte)


'*******************************************************************************
'Hauptprogrammstart  initialisierung
'*******************************************************************************

'Disable Interrupts                                          'zuerst alle Interrupts Disablen
'Disable Timer1
'Disable Int0
'Disable Int1

Reset Mot_stp
Set Mot_en                                                  ' Steppertreiber disable
Set Mot_sleep

Reset Mot_m2                                                  ' Mikroschritte festlegen
Set Mot_m1
Set Mot_m0

Reset Mot_reset                                             ' Motortreiber resetten
Waitms 2
Set Mot_reset

Actualposition = 1

                                                            'Variablen vom EEProm holen
Dutycycle = Edutycycle
Stepdelay = Estepdelay
Stepsize = Estepsize
Backlash = Ebacklash
Bldir = Ebldir                                              ' 51 oder 50 für Backlash IN bzw. Out

Config Timer0 = Timer , Prescale = 64
On Timer0 Tim0_isr
Stop Timer0
Enable Interrupts
Enable Timer0

Config Serialin = Buffered , Size = 20, Bytematch = 86
'Comm_en = 1                                                 'Comm Einschalten

Config Adc = free , Prescaler = Auto ,  REFERENCE = avcc

'###############################################################################


'Hauptschleife
'Warter auf ein Zeichen von der RS232 Schnittstelle
'===============================================================================
'###############################################################################

D = 0                                                       ' auf steuerzeichen warten

Do

anain = getadc(5)
anain = anain /5

If anain > 140 then
  nop
else

  while  anain > 105
   gosub motormanuellaussen
  wend

  while  anain < 95
   gosub motormanuellinnen
  wend

stop  TIMER0

If Dutycycle < 50 Then
      Set Mot_en                                            ' Motor Disable
    Else
      Reset Mot_en
    End If'set Mot_en

end if






'print anain

 If Ischarwaiting() = 1 Then
  Gosub Empfang                                             'Wenn einzeichen kommt dann Empfangsroutine aufrufen
 End If

 If D = 9 Then
  Gosub Decodecommand
 End If
                                                         'Wenn es ein kommando war
Loop
End



' Falls ein "F" gesendet wird, werden die Nachfolgenden 8 Byte gelesen
'===============================================================================
Empfang:

'Stop Timer0                                                 'Empfang hat vorrang vor
C = Inkey()                                                 'Motor
   If D > 0 Then
      If D < 8 Then Command(d) = C
      Incr D
   Else
      If C = "F" Then Incr D
   End If
Return


'===============================================================================

'Liest den Commandstring aus und zerlegt ihn in seine Bestandteile
'===============================================================================
Decodecommand:

     Temp = ""
     D = 0

     Subcommandchar = Chr(subcommandbyte)

     'value auslesen
     For I = 2 To 7
       Temp = Temp + Chr(command(i))
     Next I

     'If Temp = "VVVVVV" Then
      'Gosub Dostopnot:
      'Return
     'End If


     Value = Valuetoint(temp)

     Tmpb = 0
     Select Case Subcommandchar                             'in entsprechende Unterroutinen verzweigen
       Case "V" : Temp = "003.28"
       Call Responsecommand( "V" , Temp)        'Firmware zurück geben
       Case "G" : Gosub Gotocommand
       Case "I" : Gosub Moveincommand
       Case "O" : Gosub Moveoutcommand
       Case "S" : Gosub Positioncommand
       Case "B" : Gosub Backlashcommand
       Case "C" : Gosub Configcommand
       Case Else : Print "Fehler"
     End Select
Return


'===============================================================================
'Wenn Backlash Commando empfangen wurde
'===============================================================================
Backlashcommand:

   If Command(2) <> 48 Then                                 ' wenn neuer Wert empfangen wird
      Bldir = Command(2)
      Backlash = Value
      Ebacklash = Backlash                                  ' neuen Wert ins EEprom
      Ebldir = Bldir
   End If

   Temp = Encodevalue(backlash)
   Temp = Chr(bldir) + Temp
   Call Responsecommand( "B" , Temp)                        ' aktuelen Wert zurücksenden

Return

Return


'===============================================================================
'Wenn Position Commando empfangen wurde
'===============================================================================
Positioncommand:


  If Value <> 0 Then
      Actualposition = Value                                ' neue Position setzen
  End If

   Temp1 = Encodevalue(actualposition)                      ' aktuelle Position melden
   Call Responsecommand( "D" , Temp1)


Return


'===============================================================================
'Wenn Config Commando empfangen wurde
'===============================================================================
Configcommand:

     Bs = 0
     For I = 2 To 4
       Bs = Bs + Command(i)
     Next I

     If Bs = 144 Then                                       '3x ASCII zeichen "0" aufsummiert
      Temp = Chr(dutycycle)                                 'Aktuelle Werte zurückgeben
      Temp = Temp + Chr(stepdelay)
      Temp = Temp + Chr(stepsize)
      Temp = Temp + "000"                                   'neue werte zurück geben

     Else
      Dutycycle = Command(2)                                'Neue Werte schreiben
      Stepdelay = Command(3)
      Stepsize = Command(4)
      Edutycycle = Dutycycle
      Estepsize = Stepsize
      Estepdelay = Stepdelay                                'ins EEprom
      Gosub Dostop
      Temp = Chr(dutycycle) + Chr(stepdelay) + Chr(stepsize) + "000"       'Aktuelle Werte zurückgeben
     End If

    Call Responsecommand( "C" , Temp)

    'if dutycycle > 50 then                                      'Microsteps festlegen
        'dutycycle = dutycycle - 50
    'endif

        Select Case stepsize
       Case 1 :
        mot_m0 = 0
        mot_m1 = 0
        mot_m2 = 0
       Case 2 :
        mot_m0 = 1
        mot_m1 = 0
        mot_m2 = 0
       Case 4 :
        mot_m0 = 0
        mot_m1 = 1
        mot_m2 = 0
       Case 8 :
        mot_m0 = 1
        mot_m1 = 1
        mot_m2 = 0
       Case 16 :
        mot_m0 = 0
        mot_m1 = 0
        mot_m2 = 1
       Case 32 :
        mot_m0 = 1
        mot_m1 = 1
        mot_m2 = 1
        End Select

  Dutycycle = Edutycycle


Return



'===============================================================================
' Berechnet den String mit vorangestellten Nullen eines numerischen Wert
'===============================================================================
Function Encodevalue(byval Value As Word) As String

  Ts = Str(value)
  Laenge = Len(ts)

  For I = Laenge To 4
    Ts = "0" + Ts                                           'nullen voranstellen
  Next I

  Encodevalue = Ts


End Function


'===============================================================================
' Berechnet den numerischen Wert im Kommando und gibt ihn zurück
'===============================================================================
Function Valuetoint(cmd As String) As Word

  T = Right(cmd , 5)
  Valuetoint = Val(t)

End Function


'===============================================================================
' Berechnet das Checksummenzeichen für den Commandstring
'===============================================================================
Function Computechecksum(byval Cmd As String) As String * 1

  Bytesum = 0
  For I = 1 To Len(cmd)
    Zeichtmp = Mid(cmd , I , 1)
    Charval = Asc(zeichtmp)
    Bytesum = Bytesum + Charval
  Next I

  Bytesum = Bytesum Mod 256
  Computechecksum = Chr(bytesum)

End Function


'===============================================================================
' hängt die Prüfsumme an den Commandstring und gibt ihn auf die RS232 Schnittst.
'===============================================================================
Sub Responsecommand(byval Subchar As String , Cmd As String)

  Dim Resp As String * 10

  If Len(cmd) = 5 Then Cmd = "0" + Cmd

   Resp = "F"                                               '+ Subchar + Cmd + Computechecksum(resp)
   Resp = Resp + Subchar
   Resp = Resp + Cmd
   Schecksum = Computechecksum(resp)
   Resp = Resp + Schecksum
  Print Resp

End Sub


'###############################################################################
'Motorbewegungen
'###############################################################################

'==============================================================================
'Motor Stop
'==============================================================================

Dostop:

   Temp1 = Encodevalue(actualposition)
   Call Responsecommand( "D" , Temp1)                       ' aktuelle Position zurückgeben

    If Dutycycle < 50 Then
      Set Mot_en                                            ' Motor Disable
    Else
      Reset Mot_en
    End If

    reset notausflag
Return

Serial0charmatch:

  Set notausflag
  Set Mot_en

Return




'==============================================================================
'Backlash ausführen
'==============================================================================
 Dobacklash:

   If Backlash = 0 Then
     reset notausflag
     Return
   End If

   Waitms 20
                                                             'Backlash Korrektiur nach innen
   If Bldir = 51 Then
      If Mot_dir = 1 Then
        reset notausflag                                 'abbrechen wenn bewegung nach außen
        Return
      End If

      Set Mot_dir                                           'Richtung nach Außen
      Steps = Backlash

   Else                                                     'Backlash Korrektur nach innen
      If Mot_dir = 0 Then
        reset notausflag                                 'Wenn nach innen gefahren wurde dann exit
        Return
      End If

      Reset Mot_dir                                         'Richtung nach innen
      Steps = Backlash

   End If

Gosub Motor_loop
reset notausflag
Return


'==============================================================================
'Interrupt Timer für Motor bewegen
'===============================================================================
Motor_loop:

      Reset Mot_en                                          'Motor Einschalten
      Reset Astop

      Timerdelay = 10 * Stepdelay                           ' Timer initialisieren
      Timerdelay = 255 - Timerdelay

      Start Timer0                                          ' Interrupt Timer starten


      Do
      Loop Until Astop = 1  or notausflag = 1                                ' warten bis Zielposition erreicht

      Stop Timer0

Return

'==============================================================================
'Motor auf die in Value angegebenen Position fahren
'===============================================================================
Gotocommand:

   If Value = 0 Then
      Temp1 = Encodevalue(actualposition)
      Call Responsecommand( "D" , Temp1)                    ' aktuelle Position melden
    Else
         If Value < Actualposition Then
          Value = Actualposition - Value
          Gosub Moveincommand
         Else
          Value = Value - Actualposition
          Gosub Moveoutcommand
         End If
    End If
Return


'===============================================================================
'Bewegt den Motor um die in Value angegebenen Steps nach innen
'===============================================================================
Moveincommand:

   Reset Mot_dir


   If Bldir = 51 Then                                       ' Backlash bestimmen
     Steps = Value + Backlash
   Else
     Steps = Value
   End If

Gosub Motor_loop
Gosub Dobacklash
Gosub Dostop

Return


'===============================================================================
'Bewegt den Motor um die in Value angegebenen Steps nach außen
'===============================================================================
Moveoutcommand:

   Set Mot_dir

   If Bldir = 50 Then                                       ' Backlash bestimmen
     Steps = Value + Backlash
   Else
     Steps = Value
   End If

Gosub Motor_loop
Gosub Dobacklash
Gosub Dostop

Return



'==============================================================================
'Motor manuell bewegen
'===============================================================================
Motormanuellinnen:

reset Mot_dir
Reset Mot_en
Reset Astop

anain = getadc(5)
anain = anain / 5
anainin = anain + 10
Timerdelay = 255 - anainin

Start Timer0

Return


Motormanuellaussen:

Set Mot_dir
Reset Mot_en
Reset Astop

anain = getadc(5)
anain = anain / 5
anainaus = anain + 41
Timerdelay = anainaus

Start Timer0

Return



'===============================================================================
'Timer INTERRUPT für Schrittimpulse
'===============================================================================
Tim0_isr:


   Timer0 = Timerdelay                                      'Timerwert zurücksetzen

Set Mot_stp

  Decr Steps

  If Mot_dir = 0 Then
    Decr Actualposition
  Else
    Incr Actualposition
  End If

Reset Mot_stp

  If Steps = 0 Then
   Set Astop
  End If


Return


Wer die .bin möchte, PN an mich, oder wie häng ich hier eine Datei an.


CS Pit
 
Zuletzt von einem Moderator bearbeitet:
Status
Es sind keine weiteren Antworten möglich.
Zurück
Oben