nicoaspra commited on
Commit
c77aacd
·
1 Parent(s): 25d0313

update checker: add check_required_gcodes_position

Browse files
Files changed (2) hide show
  1. gcode_analyzer_ui.py +17 -13
  2. python_gcode_checker.py +65 -6
gcode_analyzer_ui.py CHANGED
@@ -1,13 +1,14 @@
1
  # app.py
2
 
3
  import streamlit as st
 
 
4
  from python_gcode_checker import run_checks
5
  from settings_report_details import generate_detailed_report
6
 
7
  def analyze_gcode(gcode, depth_max=0.1):
8
  errors, warnings = run_checks(gcode, depth_max)
9
  config_report = generate_detailed_report(gcode)
10
-
11
  return errors, warnings, config_report
12
 
13
  def format_issues(issues):
@@ -19,7 +20,16 @@ def format_issues(issues):
19
  formatted.append(message) # No "Line 0" for general warnings/errors
20
  return formatted
21
 
22
- # Streamlit UI
 
 
 
 
 
 
 
 
 
23
  st.title("G-code Programming Assistant (v0.1)")
24
 
25
  st.markdown("""
@@ -30,18 +40,14 @@ Welcome to the G-code Assistant! This tool helps you verify and analyze your G-c
30
  This is a beta version, and you're free to use it for checking your G-codes. If you encounter any issues or unexpected behavior, please contact the developer at **nico.aspra@bicol-u.edu.ph**.
31
  """)
32
 
33
- # Input for maximum depth of cut
34
  depth_max = st.number_input("Maximum Depth of Cut", min_value=0.0, value=0.1, step=0.1, format="%.1f")
35
 
36
- # Text area for G-code input
37
- gcode_input = st.text_area("Input G-code", height=300, placeholder="Enter G-code here...")
38
 
39
- # Button to analyze G-code
40
  if st.button("Analyze G-code"):
41
- # Run analysis
42
  errors, warnings, config_report = analyze_gcode(gcode_input, depth_max)
43
 
44
- # Display Errors with count in the subheader
45
  st.subheader(f"Errors ({len(errors)})")
46
  if errors:
47
  for message in format_issues(errors):
@@ -49,7 +55,6 @@ if st.button("Analyze G-code"):
49
  else:
50
  st.success("No errors found.")
51
 
52
- # Display Warnings with count in the subheader
53
  st.subheader(f"Warnings ({len(warnings)})")
54
  if warnings:
55
  for message in format_issues(warnings):
@@ -57,10 +62,9 @@ if st.button("Analyze G-code"):
57
  else:
58
  st.info("No warnings found.")
59
 
60
- # Display Configuration Settings
61
  st.subheader("Configuration Settings")
62
- st.text(config_report)
63
-
64
- # Footer
65
  st.markdown("---")
66
  st.markdown("Developed by **Aspra, N.**")
 
1
  # app.py
2
 
3
  import streamlit as st
4
+ import pandas as pd
5
+ from streamlit_ace import st_ace
6
  from python_gcode_checker import run_checks
7
  from settings_report_details import generate_detailed_report
8
 
9
  def analyze_gcode(gcode, depth_max=0.1):
10
  errors, warnings = run_checks(gcode, depth_max)
11
  config_report = generate_detailed_report(gcode)
 
12
  return errors, warnings, config_report
13
 
14
  def format_issues(issues):
 
20
  formatted.append(message) # No "Line 0" for general warnings/errors
21
  return formatted
22
 
23
+ def parse_config_report(config_report):
24
+ config_lines = config_report.strip().split('\n')
25
+ config_data = {"Setting": [], "Value": []}
26
+ for line in config_lines:
27
+ if ':' in line:
28
+ key, value = line.split(':', 1)
29
+ config_data["Setting"].append(key.strip())
30
+ config_data["Value"].append(value.strip())
31
+ return pd.DataFrame(config_data)
32
+
33
  st.title("G-code Programming Assistant (v0.1)")
34
 
35
  st.markdown("""
 
40
  This is a beta version, and you're free to use it for checking your G-codes. If you encounter any issues or unexpected behavior, please contact the developer at **nico.aspra@bicol-u.edu.ph**.
41
  """)
42
 
 
43
  depth_max = st.number_input("Maximum Depth of Cut", min_value=0.0, value=0.1, step=0.1, format="%.1f")
44
 
45
+ # Use Ace editor for G-code input with line numbering
46
+ gcode_input = st_ace(language='text', theme='cobalt', placeholder="Enter G-code here...", font_size=14, height=300)
47
 
 
48
  if st.button("Analyze G-code"):
 
49
  errors, warnings, config_report = analyze_gcode(gcode_input, depth_max)
50
 
 
51
  st.subheader(f"Errors ({len(errors)})")
52
  if errors:
53
  for message in format_issues(errors):
 
55
  else:
56
  st.success("No errors found.")
57
 
 
58
  st.subheader(f"Warnings ({len(warnings)})")
59
  if warnings:
60
  for message in format_issues(warnings):
 
62
  else:
63
  st.info("No warnings found.")
64
 
 
65
  st.subheader("Configuration Settings")
66
+ config_df = parse_config_report(config_report)
67
+ st.table(config_df)
68
+
69
  st.markdown("---")
70
  st.markdown("Developed by **Aspra, N.**")
python_gcode_checker.py CHANGED
@@ -54,10 +54,10 @@ def check_required_gcodes(lines_with_numbers):
54
  Returns a list of errors with individual entries for each missing group.
55
  """
56
  required_groups = {
57
- "units": {"G20", "G21"},
58
- "mode": {"G90", "G91"},
59
- "work_coordinates": {"G54", "G55", "G56", "G57", "G58", "G59"},
60
- "plane": {"G17", "G18", "G19"},
61
  }
62
 
63
  # Create a set to track found codes and their line numbers
@@ -72,6 +72,7 @@ def check_required_gcodes(lines_with_numbers):
72
 
73
  # Check for presence of required codes
74
  for category, codes in required_groups.items():
 
75
  found = any(code in found_codes for code in codes)
76
  if not found:
77
  missing_codes = "/".join(sorted(codes))
@@ -86,6 +87,60 @@ def check_required_gcodes(lines_with_numbers):
86
 
87
  return missing_group_errors
88
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
89
  def check_end_gcode(lines_with_numbers):
90
  """
91
  Checks that M30 is the last G-code command.
@@ -378,8 +433,9 @@ def run_checks(gcode, depth_max=0.1):
378
  # Preprocess G-code to remove comments and get cleaned lines with original line numbers
379
  lines_with_numbers = preprocess_gcode(gcode)
380
 
381
- # Run all checks
382
  required_gcode_issues = check_required_gcodes(lines_with_numbers)
 
383
  spindle_issues = check_spindle(lines_with_numbers)
384
  feed_rate_issues = check_feed_rate(lines_with_numbers)
385
  depth_issues = check_depth_of_cut(lines_with_numbers, depth_max)
@@ -390,6 +446,7 @@ def run_checks(gcode, depth_max=0.1):
390
  # Combine all issues
391
  all_issues = (
392
  required_gcode_issues
 
393
  + spindle_issues
394
  + feed_rate_issues
395
  + depth_issues
@@ -415,10 +472,12 @@ if __name__ == "__main__":
415
  # Example usage
416
  gcode_sample = """
417
  %
418
- G21 G90 G54 G17
419
  G00 X0 Y0 Z5.0
420
  M03 S1000
421
  G01 Z-0.1 F100 ; Plunge using rapid movement (should be G01)
 
 
422
  G01 X10 Y10
423
  G01 X20 Y20
424
  G00 Z5.0 ; Retract using rapid movement (allowed since Z > 0)
 
54
  Returns a list of errors with individual entries for each missing group.
55
  """
56
  required_groups = {
57
+ "units": {"G20", "G21"}, # Metric or Imperial Units
58
+ "mode": {"G90", "G91"}, # Absolute or Incremental Mode
59
+ "work_coordinates": {"G54", "G55", "G56", "G57", "G58", "G59"}, # Work Offsets
60
+ "plane": {"G17", "G18", "G19"}, # Selected Plane
61
  }
62
 
63
  # Create a set to track found codes and their line numbers
 
72
 
73
  # Check for presence of required codes
74
  for category, codes in required_groups.items():
75
+ # Only flag as missing if both options in a group are absent
76
  found = any(code in found_codes for code in codes)
77
  if not found:
78
  missing_codes = "/".join(sorted(codes))
 
87
 
88
  return missing_group_errors
89
 
90
+ def check_required_gcodes_position(lines_with_numbers):
91
+ """
92
+ Ensures required G-codes appear before movement commands.
93
+ Flags changes in critical settings (e.g., units) after movement commands.
94
+ """
95
+ issues = []
96
+ movement_seen = False
97
+ required_groups = {
98
+ "units": {"G20", "G21"},
99
+ "mode": {"G90", "G91"},
100
+ "work_coordinates": {"G54", "G55", "G56", "G57", "G58", "G59"},
101
+ "plane": {"G17", "G18", "G19"},
102
+ }
103
+ critical_gcodes = {
104
+ "units": {"G20", "G21"},
105
+ "plane": {"G17", "G18", "G19"},
106
+ }
107
+
108
+ # Track codes found before movement commands
109
+ codes_before_movement = set()
110
+
111
+ for original_line_number, line in lines_with_numbers:
112
+ tokens = line.split()
113
+
114
+ # Check if movement commands are encountered
115
+ if not movement_seen and any(cmd in tokens for cmd in {"G00", "G01", "G02", "G03"}):
116
+ movement_seen = True
117
+
118
+ if not movement_seen:
119
+ # Collect required G-codes found before movement
120
+ codes_before_movement.update(tokens)
121
+ else:
122
+ # After movement commands have been seen, check for critical G-codes
123
+ for token in tokens:
124
+ for category, codes in critical_gcodes.items():
125
+ if token in codes:
126
+ issues.append((original_line_number, f"(Warning) {token} appears after movement commands. Ensure this change is intentional -> {line.strip()}"))
127
+
128
+ # Check for missing required G-codes before movement commands
129
+ missing_groups = []
130
+ for category, codes in required_groups.items():
131
+ if not any(code in codes_before_movement for code in codes):
132
+ missing_codes = "/".join(sorted(codes))
133
+ missing_groups.append(f"({category}) {missing_codes}")
134
+
135
+ if missing_groups:
136
+ first_movement_line = next(
137
+ (line_num for line_num, line in lines_with_numbers if any(cmd in line for cmd in {"G00", "G01", "G02", "G03"})),
138
+ 1
139
+ )
140
+ issues.append((first_movement_line, f"(Error) Missing required G-codes before first movement: {', '.join(missing_groups)}"))
141
+
142
+ return issues
143
+
144
  def check_end_gcode(lines_with_numbers):
145
  """
146
  Checks that M30 is the last G-code command.
 
433
  # Preprocess G-code to remove comments and get cleaned lines with original line numbers
434
  lines_with_numbers = preprocess_gcode(gcode)
435
 
436
+ # Collect issues from all checks
437
  required_gcode_issues = check_required_gcodes(lines_with_numbers)
438
+ required_gcode_position_issues = check_required_gcodes_position(lines_with_numbers)
439
  spindle_issues = check_spindle(lines_with_numbers)
440
  feed_rate_issues = check_feed_rate(lines_with_numbers)
441
  depth_issues = check_depth_of_cut(lines_with_numbers, depth_max)
 
446
  # Combine all issues
447
  all_issues = (
448
  required_gcode_issues
449
+ + required_gcode_position_issues
450
  + spindle_issues
451
  + feed_rate_issues
452
  + depth_issues
 
472
  # Example usage
473
  gcode_sample = """
474
  %
475
+ G21 G90 G17 G54
476
  G00 X0 Y0 Z5.0
477
  M03 S1000
478
  G01 Z-0.1 F100 ; Plunge using rapid movement (should be G01)
479
+ G54
480
+ G01 Z-0.1
481
  G01 X10 Y10
482
  G01 X20 Y20
483
  G00 Z5.0 ; Retract using rapid movement (allowed since Z > 0)