Python anfänger

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
jojo45
User
Beiträge: 9
Registriert: Freitag 4. Februar 2022, 13:27

Hallo am alle.

Bin absolute Anfänger was Python an geht und brauche Hilfe.

Ich habe ein Scrip. Es ist Konverter von gcode zu hex.

Ich werde es entweder in Processing java übersetzen wollen (Wäre mir am liebsten) oder eine Änderung in Python haben. Geht um ausführen von diesem Scrip.
  • # Simple GCode to Arduino hex format converter.
    # It only understands G00 and G01 codes, nothing fancy!
    #
    # It will automatically scale the object to the full 12 bit
    # range for my Arduino laser project, to change that
    # you have to modify the scale in createObject().
    #
    # Typical files I worked with have been generated with
    # http://ncplot.com/stickfont/stickfont.htm (StickFont 1.1)
    #
    # Usage: python convertGCode.py inputfile.nc outputfile.cpp

    import math
    import sys

    def createObject(name, cmds):
    minx = miny = 10000000
    maxx = maxy = 0
    string = ""
    for cmd in cmds:
    if cmd[0] == 2:
    minx = min(minx,cmd[1])
    miny = min(miny,cmd[2])
    maxx = max(maxx,cmd[1])
    maxy = max(maxy,cmd[2])

    string += "const unsigned short draw_" + name + "[] PROGMEM = {\n";
    laserState = False

    biggestSide = max(maxx-minx, maxy-miny)
    # scale to the laser range
    scale = 1500. / biggestSide; # velkost objektu max 4095, smal 500 // laser.setScale(7);
    print "bounding box x: ", minx, maxx
    print "bounding box y: ", miny, maxy
    print "scale: ", scale
    for cmd in cmds:
    if cmd[0] == 0:laserState = False
    if cmd[0] == 1:laserState = True
    if cmd[0] == 2:
    x = int(math.floor((cmd[1]-minx) * scale))
    y = int(math.floor((cmd[2]-miny) * scale))
    if laserState:
    x += 0x8000
    string += hex(x) + "," + hex(y) + ",\n"
    string += "};\n"
    return string

    def run(input, output):
    result = ""
    f = open(input);
    lines = f.readlines()
    drawing = False
    posx = posy = 0.

    cmds = []
    for l in lines:
    if l.startswith("G00"):
    if drawing:
    cmds.append((0,))
    drawing = False
    elif l.startswith("G01"):
    drawing = True
    cmds.append((1,))
    elif l.startswith("X"):
    parts = l.split("Y")
    newposx = float(parts[0][1:])
    newposy = float(parts[1])
    cmds.append((2,newposx,newposy))
    posx = newposx
    posy = newposy

    result = createObject("object", cmds)

    o = open(output,"w")
    o.write(result)

    if __name__ == "__main__":
    if len(sys.argv) < 3:
    print "Usage: convertGCode.py inputfile.nc outputfile.cpp"
    else:
    run(sys.argv[1], sys.argv[2])


Der Zeit ist es :

Python convertGCode.py “Eingang File” “Ausgang File”.

Werde gerne ein Dialog kriegen wo ich mir das Dokument zum Öffnen aussuche und ebenso ein Dialog wo ich es speichern will und wäre nicht schlecht Möglichkeit wo ich wert zum Skalieren eingeben kann.

Mir ist klar, dass ich zu viel verlange aber konnte mir jemand helfen?
Benutzeravatar
sparrow
User
Beiträge: 4540
Registriert: Freitag 17. April 2009, 10:28

Python kommt in der Regel mit einem Modul namens tkinter - damit lassen sich GUIs erstellen.
Ein guter allgemeiner Einstiegspunkt in Python ist das offizielle Tutorial.
jojo45
User
Beiträge: 9
Registriert: Freitag 4. Februar 2022, 13:27

Ja, ich habe die Seite gefunden.
Aber ich weiß nicht, wie ich diese Bibliothek in die Processing python einfügen soll.
Processing zeigt Kompilierungsfehler und ist daher für mich als Anfänger besser geeignet.
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Das geht nicht. Processing ist eine andere Programmiersprache. Du kannst nicht einfach Code einer Sprache in einer anderen benutzen. Wenn du das in processing haben willst, musst du es richtig konvertieren. Es ist ja kein besonders komplizierter code.
jojo45
User
Beiträge: 9
Registriert: Freitag 4. Februar 2022, 13:27

Dieser Code funktioniert in Processing Python. Ich weiß, es ist eine andere Python.
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Na dann musst du eben schauen, was in processing Python so geht mit Eingaben und so. Aber wenn ich mir https://py.processing.org/reference/ anschaue, bin ich da skeptisch. Das ist einfach nicht dafür gemacht, GUIs zu bauen. Sondern eher kreative Grafik. Da gibt’s zb keine Input-Boxen oder Dialoge oder so.
jojo45
User
Beiträge: 9
Registriert: Freitag 4. Februar 2022, 13:27

Kennen Sie ein Programm für Python, welche Kompilierungsfehler anzeigt? Zumindest dort, wo sie sind. Ein Programm für Anfängern, welche beim Programmieren helfen wird. Für Linux oder Win10
jojo45
User
Beiträge: 9
Registriert: Freitag 4. Februar 2022, 13:27

Ich bin ein Fan von (), {}. Das ist mein größtes Problem.
Benutzeravatar
__blackjack__
User
Beiträge: 14078
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@jojo45: Ich verstehe die Frage nicht so ganz. Python ist ein Programm das Kompilierungsfehler anzeigt. Also das Programm das man auch zum ausführen von Python-Programmen verwendet. Denn das kompiliert den Quelltext ja automagisch bevor es den ausführt, und wenn da etwas drin ist, mit dem der Compiler nicht zurecht kommt, dann wird da ein Fehler ausgegeben.

Fan von leeren Tupeln und Wörterbüchern zu sein ist kein wirklich grosses Problem. 🤡
“Vir, intelligence has nothing to do with politics!” — Londo Mollari
jojo45
User
Beiträge: 9
Registriert: Freitag 4. Februar 2022, 13:27

Habe schon einiges gemacht. Problem habe ich mit speichern des result. Immer wieder fehlen.

#################### open file ###################

def openFile():
tf = filedialog.askopenfilename(
initialdir="C:/Users/MainFrame/Desktop/",
title="Open Text file",
filetypes=(("Text Files", "*.txt"),)
)
pathh.insert(END, tf)
tf = open(tf)

# file_cont = tf.read()
# txtarea.insert(END, file_cont) # write input to text field

lines = tf.readlines() # f to tf.readlines()
drawing = False #
posx = posy = 0. #

cmds = [] #
for l in lines: #
if l.startswith("G00"): #
if drawing: #
cmds.append((0,)) #
drawing = False #
elif l.startswith("G01"): #
drawing = True #
cmds.append((1,)) #
elif l.startswith("X"): #
parts = l.split("Y") #
newposx = float(parts[0][1:]) #
newposy = float(parts[1]) #
cmds.append((2,newposx,newposy)) #
posx = newposx #
posy = newposy #

result = createObject("object", cmds) #

file_cont = tf.read() # read converted result
txtarea.insert(END, result) # write converted result to text space

# o = open(output,"w") #
# o.write(result) #

tf.close()

################################################


################ savee file ####################

def saveFile():
tf = filedialog.asksaveasfile(
mode='w',

title ="Save file",
defaultextension=".txt"
)
tf.config(mode='w') #

pathh.insert(END, tf)
data = str(txtarea.get(1.0, END)) #
tf.write(data) #

tf.close()

###############################################
Benutzeravatar
__blackjack__
User
Beiträge: 14078
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@jojo45: Anmerkungen zum Quelltext aus dem ersten Beitrag: Das ist Python 2 Quelltext. Python 2 sollte man nicht mehr verwenden, das hat sein Lebensende erreicht/überschritten.

Eingerückt wird vier Leerzeichen pro Ebene, nicht zwei.

Da sind mindestens zwei unnötige Semikolons an Zeilenenden drin.

Namen werden in Python klein_mit_unterstrichen geschrieben. Ausnahmen sind Konstanten (KOMPLETT_GROSS) und Klassen (PascalCase).

`input` ist der Name einer eingebauten Funktion, den sollte man nicht für etwas anderes verwenden.

Einbuchstabige Namen sind selten gute Namen. Es gibt wenige Ausnahmen wie `x`, `y`, und `z` für Koordinaten und `i`, `j`, und `k` für ganze Zahlen als Laufvariablen und für Indexzugriffe wenn es da nichts sprechenderes für gibt. Aber `f`, `o`, oder `l` für Dateiobjekte oder Zeichenketten sind keine gute Idee.

Abkürzungen sollte man sich auch sparen wenn die nicht allgemein verständlich sind. Man sollte nicht `cmds` schreiben wenn man `commands` meint.

`run()` ist als Name ein bisschen sehr generisch. Selbst `convert()` wäre das noch, würde aber immerhin besser beschreiben was die Funktion macht.

`result` wird ganz am Anfang mit einer leeren Zeichenkette belegt die aber nirgends verwendet wird. Das kann und sollte man sich sparen.

Dateien die man öffnet, sollte man auch wieder schliessen. Das wird bei beiden Dateien nicht getan. Am besten öffnet man Dateien zusammen mit der ``with``-Anweisung, damit die Datei auch in jedem Fall wieder geschlossen wird, egal wo und warum der ``with``-Block verlassen wird.

`readlines()` ist nicht nötig. Dateiobjekte selbst sind iterierbar und liefern die Zeilen, und es gibt keinen Grund die Eingabedatei erst komplett in den Arbeitsspeicher zu lesen bevor die Verarbeitunge beginnt.

Bei Textdateien sollte man beim öffnen immer die Kodierung angeben.

`posx`, und `posy` werden nicht wirklich verwendet. Das heisst die Namen werden zwar an Werte gebunden, aber diese Werte werden dann nirgends verwendet.

`split()` wenn man genau zwei Ergebnisse erwartet ist eher ein `partition()`.

In der `createObject()`-Funktion dann das gleiche mit `string` was in der `run()`-Funktion schon mal war: eine leere Zeichenkette die nie verwendet wird.

Zeichenketten in einer Schleife immer wieder mit ``+`` oder ``+=`` zu erweitern ist ineffizient, weil Zeichenketten nicht veränderbar sind, und da immer länger werdende Zeichenketten immer wieder in neue Speicherbereiche kopiert werden müssen. Idiomatisches Python sammelt die Teilzeichenketten in einer Liste und erstellt daraus dann am Ende eine Zeichenkette mit der `join()`-Methode auf Zeichenketten.

"G00" und "G01" kann man auch als ein Kommando abbilden, das den Status als Argument mitführt. Und statt magischer Zahlen würde man sich mindestens Konstanten für die Kommandos definieren.

Zeichenketten und Werte mit ``+`` zusammenstückeln ist eher BASIC denn Python. Python hat dafür Zeichenkettenformatierung mit der `format()`-Methode und f-Zeichenkettenliterale.

Bei den Kommandocodes kann es ja immer nur einen pro Kommando geben, also machen ``elif``-Anweisungen Sinn, und es ist in der Regel eine gute Idee dann auch einen ``else``-Zweig zu haben, damit bei Programmierfehlern keine unbekannten Werte einfach so geräuschlos unter den Tisch fallen.

Ungetestet:

Code: Alles auswählen

#!/usr/bin/env python3
"""
Simple GCode to Arduino hex format converter.
It only understands G00 and G01 codes, nothing fancy!

It will automatically scale the object to the full 12 bit
range for my Arduino laser project, to change that
you have to modify the scale in `create_object()`.

Typical files I worked with have been generated with
http://ncplot.com/stickfont/stickfont.htm (StickFont 1.1)

Usage: python convert_gcode.py inputfile.nc outputfile.cpp
"""
import math
import sys
from enum import Enum, auto
from pathlib import Path


class CommandType(Enum):
    LASER_STATE = auto()
    COORDINATE = auto()


def create_object(name, commands):
    min_x = min_y = math.inf
    max_x = max_y = -math.inf
    for command_type, arguments in commands:
        if command_type is CommandType.COORDINATE:
            x, y = arguments
            min_x = min(min_x, x)
            min_y = min(min_y, y)
            max_x = max(max_x, x)
            max_y = max(max_y, y)

    scale = 1500 / max(max_x - min_x, max_y - min_y)
    # scale to the laser range
    # velkost objektu max 4095, smal 500 // laser.setScale(7)
    print("bounding box x: ", min_x, max_x)
    print("bounding box y: ", min_y, max_y)
    print("scale: ", scale)

    parts = [f"const unsigned short draw_{name}[] PROGMEM = {{\n"]
    laser_state_mask = 0
    for command_type, arguments in commands:
        if command_type is CommandType.LASER_STATE:
            laser_state_mask = 0x8000 if arguments[0] else 0

        elif command_type is CommandType.COORDINATE:
            x, y = arguments
            x = int(math.floor((x - min_x) * scale)) | laser_state_mask
            y = int(math.floor((y - min_y) * scale))
            parts.append(f"0x{x:x},0x{y:x},\n")

        else:
            raise ValueError(
                f"unknown command type {command_type!r}"
                f" with arguments {arguments!r}"
            )

    parts.append("};\n")
    return "".join(parts)


def convert(gcode_file_path, cpp_file_path):
    drawing = False
    commands = []
    for line in gcode_file_path.open("r", encoding="ascii"):
        if line.startswith("G00"):
            if drawing:
                commands.append((CommandType.LASER_STATE, (False,)))
            drawing = False

        elif line.startswith("G01"):
            drawing = True
            commands.append((CommandType.LASER_STATE, (True,)))

        elif line.startswith("X"):
            x_part, _, y_part = line[1:].partition("Y")
            commands.append(
                (CommandType.COORDINATE, (float(x_part), float(y_part)))
            )

    cpp_file_path.write_text(create_object("object", commands), "ascii")


def main():
    if len(sys.argv) < 3:
        print("Usage: convert_gcode.py inputfile.nc outputfile.cpp")
    else:
        convert(Path(sys.argv[1]), Path(sys.argv[2]))


if __name__ == "__main__":
    main()
In einer objektorientierten Programmiersprache wie Python, wäre IMHO ein objektorientierte Lösung statt der Tupel mit den Kommandotypen etwas netter.
“Vir, intelligence has nothing to do with politics!” — Londo Mollari
jojo45
User
Beiträge: 9
Registriert: Freitag 4. Februar 2022, 13:27

Ich habe die Zeile gelöscht. Jetzt ist es OK.

Code: Alles auswählen

  tf.config(mode='w')  
jojo45
User
Beiträge: 9
Registriert: Freitag 4. Februar 2022, 13:27

Hier ist komplet code.

Code: Alles auswählen

from tkinter import *
from tkinter import filedialog

import math
import sys


################### converter ####################

def createObject(name, cmds):
  minx = miny = 10000000
  maxx = maxy = 0
  string = ""
  for cmd in cmds:
    if cmd[0] == 2:
      minx = min(minx,cmd[1])
      miny = min(miny,cmd[2])
      maxx = max(maxx,cmd[1])
      maxy = max(maxy,cmd[2])

  string += "const unsigned short draw_" + name + "[] PROGMEM = {\n";
  laserState = False
  
  biggestSide = max(maxx-minx, maxy-miny)
  # scale to the laser range
  scale = 1500. / biggestSide;
  print ("bounding box x: ", minx, maxx)
  print ("bounding box y: ", miny, maxy)
  print ("scale: ", scale)
  for cmd in cmds:
    if cmd[0] == 0:laserState = False
    if cmd[0] == 1:laserState = True
    if cmd[0] == 2:
      x = int(math.floor((cmd[1]-minx) * scale))
      y = int(math.floor((cmd[2]-miny) * scale))
      if laserState:
        x += 0x8000
      string += hex(x) + "," + hex(y) + ",\n"
  string += "};\n"
  return string
  
##################################################


#################### open file ###################
 
def openFile():
    tf = filedialog.askopenfilename(
        initialdir="C:/Users/MainFrame/Desktop/", 
        title="Open Text file", 
        filetypes=(("Text Files", "*.txt"),)
        )
    pathh.insert(END, tf)
    tf = open(tf)

#    file_cont = tf.read()
#    txtarea.insert(END, file_cont) # write input to text field

    lines = tf.readlines()                          #  f   to    tf.readlines()
    drawing = False                                 #
    posx = posy = 0.                                #

    cmds = []                                       #
    for l in lines:                                 #
      if l.startswith("G00"):                       #
        if drawing:                                 #
          cmds.append((0,))                         #
        drawing = False                             #
      elif l.startswith("G01"):                     #
        drawing = True                              #
        cmds.append((1,))                           #
      elif l.startswith("X"):                       #
        parts = l.split("Y")                        #
        newposx = float(parts[0][1:])               #
        newposy = float(parts[1])                   #
        cmds.append((2,newposx,newposy))            #
        posx = newposx                              #
        posy = newposy                              #

    result = createObject("object", cmds)           #

    file_cont = tf.read()                   # read converted result 
    txtarea.insert(END, result)             # write converted result to text space


    tf.close()

################################################


################ save file ####################

def saveFile():
    tf = filedialog.asksaveasfile(
        mode='w',

        title ="Save file",
        defaultextension=".txt"
        )
   # tf.config(mode='w')

    pathh.insert(END, tf)
    result = str(txtarea.get(1.0, END))
    tf.write(result) 
   
    tf.close()



ws = Tk()
ws.title("PythonGuides")
ws.geometry("400x500")
ws['bg']='#2a636e'

# adding frame
frame = Frame(ws)
frame.pack(pady=20)

# adding scrollbars 
ver_sb = Scrollbar(frame, orient=VERTICAL )
ver_sb.pack(side=RIGHT, fill=BOTH)

hor_sb = Scrollbar(frame, orient=HORIZONTAL)
hor_sb.pack(side=BOTTOM, fill=BOTH)

# adding writing space
txtarea = Text(frame, width=40, height=20)
txtarea.pack(side=LEFT)

# binding scrollbar with text area
txtarea.config(yscrollcommand=ver_sb.set)
ver_sb.config(command=txtarea.yview)

txtarea.config(xscrollcommand=hor_sb.set)
hor_sb.config(command=txtarea.xview)

# adding path showing box
pathh = Entry(ws)
pathh.pack(expand=True, fill=X, padx=10)

# adding buttons 
Button(
    ws, 
    text="Open File", 
    command=openFile
    ).pack(side=LEFT, expand=True, fill=X, padx=20)

Button(
    ws, 
    text="Save File", 
    command=saveFile
    ).pack(side=LEFT, expand=True, fill=X, padx=20)

Button(
    ws, 
    text="Exit", 
    command=lambda:ws.destroy()
    ).pack(side=LEFT, expand=True, fill=X, padx=20, pady=20)

ws.mainloop()
jojo45
User
Beiträge: 9
Registriert: Freitag 4. Februar 2022, 13:27

Ich habe das erste Programm nicht geschrieben. Über Python habe ich eigentlich fast keine Ahnung. Wollte es nur so verändern das ich nicht ständig befehle in terminal schreiben muss. Ob wohl ich eigentlich fast 0 Ahnung über Python habe, Änderung habe ich gemacht.

Ich will mich bedanken, dass du das Programm korrigieret hast. Werde ich verwenden.

Grüße.
Antworten