diff --git a/clock.svg b/clock.svg new file mode 100644 index 0000000..1da12f5 --- /dev/null +++ b/clock.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/main.py b/main.py index e0be193..8e0ffec 100644 --- a/main.py +++ b/main.py @@ -1,17 +1,23 @@ import hardware as hw import controller as ctl import GCode_Interpreterdc as gci +import svgtroppagcode as sgc + +instr = sgc.svg_to_gcode("test.svg").split("\n") + b = "socket.sock" sh = hw.SimuHardware(b) ctrl = ctl.DummyController() gtm1 = gci.GCodeToMotors(ctrl, sh) -gtm1.instruction_converter("G1 X25.000 Y25.000 F2.000") -gtm1.instruction_converter("G1 X30.000 Y25.000 F2.000") -gtm1.instruction_converter("G3 X30.000 Y45.000 I0 J10 F0.100") +for i in instr: + gtm1.instruction_converter(i) +# gtm1.instruction_converter("G1 X25.000 Y25.000 F2.000") +# gtm1.instruction_converter("G1 X30.000 Y25.000 F2.000") +# gtm1.instruction_converter("G3 X30.000 Y45.000 I0 J10 F0.100") # gtm1.instruction_converter("G5 X50.000 Y45.000 I-5 J-5 P10 J5 F0.5000") -gtm1.instruction_converter("G1 X50.000 Y50.000 F2.000") -gtm1.instruction_converter("G1 X50.000 Y100.000 F2.000") -gtm1.instruction_converter("G1 X100.000 Y-50.000 F2.000") +# gtm1.instruction_converter("G1 X50.000 Y50.000 F2.000") +# gtm1.instruction_converter("G1 X50.000 Y100.000 F2.000") +# gtm1.instruction_converter("G1 X100.000 Y-50.000 F2.000") gtm1.instruction_converter("G1 X-50.000 Y-100.000 F2.000") gtm1.instruction_converter("G1 X-100.000 Y50.000 F2.000") diff --git a/simulator.py b/simulator.py old mode 100755 new mode 100644 diff --git a/svgtroppagcode.py b/svgtroppagcode.py index 86f9d78..f752c10 100644 --- a/svgtroppagcode.py +++ b/svgtroppagcode.py @@ -5,31 +5,52 @@ import toppra.algorithm as algo import numpy as np -# Function to extract paths from an SVG file +# Function to extract and subdivide paths into continuous subpaths def extract_svg_paths(svg_file): - paths, *attributes = svgpathtools.svg2paths(svg_file) - return paths + paths, attributes = svgpathtools.svg2paths(svg_file) + continuous_paths = [] + + for path in paths: + subpath = [] + last_point = None + for seg in path: + if last_point is not None and seg.start != last_point: + continuous_paths.append(svgpathtools.Path(*subpath)) + subpath = [] + subpath.append(seg) + last_point = seg.end + if subpath: + continuous_paths.append(svgpathtools.Path(*subpath)) + + return continuous_paths # Function to compute time-reparametrized velocities using toppra based on segment type def compute_reparametrized_speeds(path, velocity_limit=100, acceleration_limit=500): sampled_points = [] ss = [] - current_s = 0 + current_s = 0.0 - for seg in path: + for k, seg in enumerate(path): num_samples = 20 if isinstance(seg, svgpathtools.CubicBezier) else 10 - segment_points = [seg.point(t) for t in np.linspace(0, 1, num_samples)] - sampled_points.extend(segment_points) - ss.extend(np.linspace(current_s, current_s + 1, num_samples)) - current_s += 1 + n = len(path) + if k < n - 1: + segment_points = np.array([[seg.point(t).real, seg.point(t).imag] for t in np.linspace(0, 1, num_samples)][:-1]) + sampled_points.append(segment_points) + ss.extend(list(np.linspace(current_s, current_s + 1, num_samples))[:-1]) + current_s += 1 + else: + segment_points = np.array([[seg.point(t).real, seg.point(t).imag] for t in np.linspace(0, 1, num_samples)]) + sampled_points.append(segment_points) + ss.extend(np.linspace(current_s, current_s + 1, num_samples)) + current_s += 1 - waypoints = np.array([(p.real, p.imag) for p in sampled_points]) - ss = np.array(ss) - velocity_limits = np.array([[-velocity_limit, velocity_limit]] * len(ss)) - acceleration_limits = np.array([[-acceleration_limit, acceleration_limit]] * len(ss)) + sampled_points = np.vstack(sampled_points) + ss = np.array(ss) # Ensure correct shape + velocity_limits = np.array([[-velocity_limit, velocity_limit]] * sampled_points.shape[1]) + acceleration_limits = np.array([[-acceleration_limit, acceleration_limit]] * sampled_points.shape[1]) - pc = ta.SplineInterpolator(ss, waypoints) + pc = ta.SplineInterpolator(ss, sampled_points) constraints = [ constraint.JointVelocityConstraint(velocity_limits), constraint.JointAccelerationConstraint(acceleration_limits) @@ -37,16 +58,12 @@ def compute_reparametrized_speeds(path, velocity_limit=100, acceleration_limit=5 instance = algo.TOPPRA(constraints, pc, solver_wrapper="seidel") sd_sq = instance.compute_parameterization(0, 0) - - return list(sd_sq) + return list(np.sqrt(sd_sq[1])) + -# Function to convert a path to G-code using computed speeds def path_to_gcode(path, speeds): gcode = [] - gcode.append("G21 ; Set units to mm") - gcode.append("G90 ; Absolute positioning") - speed_index = 0 for seg in path: num_samples = 20 if isinstance(seg, svgpathtools.CubicBezier) else 10 @@ -55,7 +72,6 @@ def path_to_gcode(path, speeds): speed = speeds[speed_index] if speed_index < len(speeds) else 1000 gcode.append(f"G1 X{point.real:.3f} Y{point.imag:.3f} F{speed}") speed_index += 1 - gcode.append("M05 ; Stop spindle") return '\n'.join(gcode) @@ -63,14 +79,17 @@ def path_to_gcode(path, speeds): # Main function to process SVG to G-code def svg_to_gcode(svg_file): paths = extract_svg_paths(svg_file) - gcode_output = [] + gcode_output = ["G21 ; Set units to mm", "G90 ; Absolute positioning"] for path in paths: + p_start = path.point(0) + gcode_output.append(f"G0 X{p_start.real:.3f} Y{p_start.imag:.3f}") speeds = compute_reparametrized_speeds(path) gcode_output.append(path_to_gcode(path, speeds)) return '\n'.join(gcode_output) +print(svg_to_gcode("clock.svg")) # Example usage # print(svg_to_gcode("drawing.svg"))