Optimizing My Pen Plotter Workflow with Custom Zsh Scripts (Sovol SO-1 + vpype + juicy-gcode)


If you’ve ever spent more time fighting with G-code settings than actually watching a pen move across paper, you know the "plotting headache." Recently, I’ve been refining the pipeline for my Sovol SO-1. The goal was simple: move from a raw SVG to a finished plot with as little friction as possible. By leveraging AI to help script the "boring stuff," I’ve landed on a workflow that handles optimization, file management, and multi-color layers with single-line commands.

The Tech Stack

  • Hardware/Management: OctoPrint by Gina Häußge (The essential interface for wireless management).
  • Firmware: Marlin Firmware (The engine powering the Sovol SO-1's movement).
  • Optimization: vpype by Antoine Beyeler (The "Swiss Army knife" of plotter tools).
  • Conversion: juicy-gcode by Egon Elbre (A high-performance SVG-to-G-code converter).
  • Automation: Custom Zsh scripts.

Update: juicy-gcode & G-code Flavor

I recently upgraded to the latest version of juicy-gcode, which required updating my G-code flavor configuration to ensure compatibility with the Sovol SO-1's servo-based pen lift.

Below is the sovol_config.yaml file I use. This file lives in the configs directory within the main Plotter folder (~/Plotter/configs/sovol_config.yaml). It defines the startup sequence, the shutdown routine, and the specific servo commands (M280) for the pen-up and pen-down movements.

The Config: sovol_config.yaml
begin: |
  M280P0S30
  G90
  G21
  G28 X Y
  G1 F1000
  M201 X1000 Y1000 Z1000 E1000
  M204 P1000.00 R1000.00 T1000.00
  M205 S0.00 T0.00 B20000 X5.00 Y5.00 Z0.40 E.500
end: |
  G4 P50
  M280P0S30
  G1 X0 Y0
toolon: |
  M280P0S29
  G4 P25
  M280P0S28
  G4 P25
  M280P0S27
  G4 P25
  M280P0S26
  G4 P25
  M280P0S25
  G4 P25
  M280P0S24
  G4 P25
  M280P0S23
  G4 P25
  M280P0S22
  G4 P25
  M280P0S21
  G4 P25
  M280P0S20
  G4 P50
tooloff: |
  G4 P100
  M280P0S30
  G4 P100

1. The Power of Project Structure

Organization is half the battle. To keep things clean, everything is contained within a root Plotter folder in the home directory. This folder contains two primary sub-directories: configs for machine-specific settings and projects for the actual artwork.

~/Plotter/
├── configs/
│ └── sovol_config.yaml
└── projects/
└── [project_name]/
├── code/ # Python/HTML generators
├── svg/ # Source/Generated SVGs
├── gcode/ # Machine-ready files
├── temp/ # Optimized intermediate SVGs
├── export/ # Previews and combined files
└── notes.md # Pen order and settings

To automate this, I use a script called newplot. It scaffolds the folders and a notes.md template in one go.

The Script: newplot
#!/bin/zsh

name="$1"

if [[ -z "$name" ]]; then
  echo "Usage: newplot project_name"
  exit 1
fi

base="$HOME/Plotter/projects/$name"

if [[ -d "$base" ]]; then
  echo "Project already exists"
  exit 1
fi

mkdir -p "$base"/{code,svg,gcode,temp,export}

cat <<EOF > "$base/notes.md"
# Project: $name

## Pen Order
1.
2.
3.

## Notes

EOF

echo "Created project: $base"

Example Usage:
newplot pulley


2. The "One-Command" Conversion

The heart of this workflow is turning an SVG into G-code that doesn't waste time. I use vpype to perform critical tasks like linemerge, linesimplify, and linesort (which minimizes "pen-up" travel time).

I wrapped this logic into plotsvg. Now, converting a file is a single command (assuming you are in the project's svg folder):
plotsvg drawing.svg

The Script: plotsvg
#!/bin/zsh

input="$1"

project_root=$(cd "$(dirname "$input")/.." && pwd)
base=$(basename "$input" .svg)

temp_svg="$project_root/temp/${base}_opt.svg"
out="$project_root/gcode/${base}.gcode"

vpype read "$input" \
  linemerge \
  linesimplify \
  reloop \
  linesort \
  write "$temp_svg"

juicy-gcode "$temp_svg" \
  -f "$HOME/Plotter/configs/sovol_config.yaml" \
  -o "$out"

echo "Created: $out"

Example Usage:
plotsvg pulley.svg


3. Physical Alignment: The Corner Brackets

A crucial part of my setup isn't a digital tool, but a physical alignment technique. To ensure the paper is exactly where the plotter expects it to be, I use a dedicated corner brackets SVG.

The Process:

  1. Prep the Bed: I apply 3M tape directly onto the mirror (the plotter's bed).
  2. Mark the Bounds: I run the "corner brackets" G-code first. This draws small "L" markers directly onto the tape.
  3. Align the Paper: I use these drawn brackets as a perfect physical guide to place my paper.
  4. Secure: Once the paper is aligned with the marks on the tape, I tape it in place and start the actual plot.

This ensures the artwork is perfectly squared and positioned every single time, especially useful for multi-color jobs where I'm swapping pens and restarting files.


4. Multi-Color Workflow

For multi-color plots, I export a separate SVG for each pen (e.g., sky_blue.svg, grass_green.svg). Using the plotmulti script, I can batch-process an entire project in seconds.

The Script: plotmulti
#!/bin/zsh

for input in "$@"; do

  project_root=$(cd "$(dirname "$input")/.." && pwd)
  base=$(basename "$input" .svg)

  temp_svg="$project_root/temp/${base}_opt.svg"
  out="$project_root/gcode/${base}.gcode"

  vpype read "$input" \
    linemerge \
    linesimplify \
    reloop \
    linesort \
    write "$temp_svg"

  juicy-gcode "$temp_svg" \
    -f "$HOME/Plotter/configs/sovol_config.yaml" \
    -o "$out"

  echo "Created: $out"
done

Execution: plotmulti black.svg red.svg blue.svg
Load the first pen → run the first file → swap pen → run next.


Key Lessons Learned

  • Structure Matters: A consistent place for temp files and notes prevents the "Which version was this?" confusion.
  • Physical Registration is King: Using the 3M tape/mirror trick for paper alignment is a 30-second insurance policy against a ruined piece of paper.
  • Optimization is Essential: Running vpype reduces wear and tear on the plotter's motors by eliminating unnecessary, jerky movements.
  • Automate the Repetitive: One-line commands let me focus on the art rather than the syntax of shell scripts or YAML configurations.

Happy Plotting!

Comments