Generating a QR code on a PCB with pcbnew's Python API
Encode text into a QR code, then engrave each module onto a PCB's copper or silkscreen by script — with pcbnew or KiCad's IPC API.
A QR code on a PCB — pointing to documentation, a serial number, or just for style — isn’t complicated once you have the code’s matrix: you just reproduce each dark module as a shape on the board. This project combines QR encoding (a standard Python library, independent of KiCad) with the double loop already seen in the footprint grid tutorial.
Encoding the text into a QR code
This step is the same regardless of which KiCad API comes next: the qrcode library builds a boolean matrix, independently of pcbnew.
import qrcode
qr = qrcode.QRCode(box_size=1, border=0)
qr.add_data("https://scriptedpcb.com")
qr.make()
matrix = qr.get_matrix() # grid of booleans: True = dark module
Drawing each module on the PCB
Loop over the matrix and add a filled rectangle for each dark module:
from pcbnew import PCB_SHAPE, SHAPE_T_RECT, VECTOR2I, FromMM, F_SilkS
module_mm = 0.5
for row, cols in enumerate(matrix):
for col, dark in enumerate(cols):
if not dark:
continue
shape = PCB_SHAPE(board)
shape.SetShape(SHAPE_T_RECT)
x0, y0 = FromMM(col * module_mm), FromMM(row * module_mm)
shape.SetStart(VECTOR2I(x0, y0))
shape.SetEnd(VECTOR2I(x0 + FromMM(module_mm), y0 + FromMM(module_mm)))
shape.SetFilled(True)
shape.SetLayer(F_SilkS)
board.Add(shape)Same loop, with a higher-level call to create a filled rectangle directly:
from kicad.geometry import Vector2
module_mm = 0.5
for row, cols in enumerate(matrix):
for col, dark in enumerate(cols):
if not dark:
continue
shape = board.create_rectangle(
start=Vector2.from_mm(col * module_mm, row * module_mm),
end=Vector2.from_mm((col + 1) * module_mm, (row + 1) * module_mm),
layer="F.SilkS",
filled=True,
)
board.update_items(shape)Try it below: adjust the module size and margin to see the total board space the code needs.
Going further
Engraving the QR code on copper (F_Cu/F.Cu) instead of silkscreen makes it a wear- and light-resistant identifier. Always keep a quiet zone of at least 2 blank modules all around the code so it stays scannable — a QR scanner needs that empty margin to lock onto the corner finder patterns.