Skip to main content

Qt-based interface for a two-dimensional polargraph scanner

Project description

QPolargraph

Tests Documentation DOI License: GPL v3 Python 3.10+

A Qt-based instrument interface for a two-dimensional polargraph scanner. Built on QInstrument.

A polargraph translates a payload to any position within its scan area using two stepper motors and a timing belt. Originally developed by Jürg Lehni and Uli Franke as a drawing machine, the design scales easily to large areas, delivers millimeter-scale positioning accuracy, and is very cost-effective to build.

QScanner interface

Hardware

Component Description
2× Nema-17 stepper motor Mounted above and to either side of the scan area
GT2 timing belt Spans both motors; payload hangs from its midpoint
GT2 drive gear (25-tooth) One per motor; engages the belt
Adafruit Motor Shield v2 Drives both steppers from a single Arduino
Arduino (Uno or compatible) Runs the acam3 firmware; connects to the host via USB

The belt forms a V-shape between the two motors. Each motor changes the length of one side of the V, moving the payload in two dimensions.

Firmware

The Arduino must be flashed with hardware/arduino/acam3/acam3.ino before first use. The easiest way is to use the built-in installer:

qpolargraph-flash

This opens a dialog that detects the attached Arduino, installs any missing Arduino libraries (Adafruit Motor Shield V2 Library, AccelStepper), compiles, and uploads the firmware — all without opening the Arduino IDE. It requires arduino-cli to be installed and on PATH.

Alternatively, open hardware/arduino/acam3/acam3.ino in the Arduino IDE and upload manually.

The firmware and package versions are coupled: Motors.identify() checks that the connected Arduino reports the expected firmware version and that the Adafruit Motor Shield is detected at I2C address 0x60, refusing to open the port if either check fails.

Installation

Clone the repository and install in editable mode:

git clone https://github.com/davidgrier/QPolargraph
cd QPolargraph
python -m venv .qp
source .qp/bin/activate          # Windows: .qp\Scripts\activate
pip install -e ".[dev]"
pip install PyQt6                # or PyQt5, PySide2, PySide6

QInstrument is installed automatically as a dependency.

Calibration

Five geometric parameters describe the polargraph. Set them in the QPolargraphWidget control panel or pass them directly to Polargraph():

Parameter Default Description
ell 1.0 m Horizontal distance between the two motor pulley centres
y0 0.1 m Vertical distance from the pulleys to the home position
pitch 2.0 mm GT2 belt tooth pitch
circumference 25 Number of belt teeth on the drive gear
steps 200 Motor steps per revolution

Measure ell and y0 with a ruler after mounting the motors. pitch, circumference, and steps are determined by the belt and gear specifications and normally do not need to change.

Settings are saved to ~/.QScanner/ automatically when the application closes, so calibration only needs to be done once.

Quick start

Scanner application

python -m QPolargraph
# or, after installation:
qpolargraph

The application opens a live plot showing the belt geometry and the scan trajectory. Use the Scan button to start a polar-arc sweep, or Home / Center to move the payload to the home or centre position.

Embedding in your own application

Subclass QScanner to add experiment-specific data acquisition:

from qtpy.QtWidgets import QApplication
from qtpy import QtCore
from QPolargraph.QScanner import QScanner
import sys


class MyScanner(QScanner):

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.scanner.dataReady.connect(self.acquire)

    @QtCore.Slot(object)
    def acquire(self, position):
        x, y = position
        # measure something at (x, y) and call self.plotData(x, y, hue)


if __name__ == '__main__':
    app = QApplication(sys.argv)
    scanner = MyScanner()
    scanner.show()
    sys.exit(app.exec())

Controlling the hardware directly

from qtpy.QtCore import QCoreApplication
from QPolargraph.Polargraph import Polargraph
import sys

app = QCoreApplication(sys.argv)
pg = Polargraph(ell=0.8, y0=0.15).find()   # auto-detects USB port
print(pg.position)                           # (x, y, running) in metres
pg.moveTo(0.0, 0.3)
while pg.running():
    pass
pg.release()

Architecture

QInstrument.QSerialInstrument
└── Motors               # acam3 serial protocol: goto, speed, position, …
    └── Polargraph       # geometry: step indexes ↔ Cartesian coordinates

QInstrument.QInstrumentWidget
└── QRasterScanWidget    # scan-pattern parameter controls

QInstrument.QInstrumentWidget
└── QPolargraphWidget    # polargraph hardware controls

QtCore.QObject
└── QScanPattern         # base: rectangular perimeter trajectory
    ├── RasterScan       # row-by-row zigzag raster
    └── PolarScan        # arc-by-arc sweep centred on the left pulley

QtWidgets.QMainWindow
└── QScanner             # full application: live plot + scan controls

Development

Run the test suite:

source .qp/bin/activate
pytest tests/

Tests run automatically before every git push. To install the pre-push hook in a fresh clone:

git config core.hooksPath .githooks

Acknowledgements

Work on this project at New York University is supported by the National Science Foundation of the United States under award number DMR-2438983.

References

H. W. Gao, K. I. Mishra, A. Winters, S. Wolin, and D. G. Grier, "Flexible wide-field high-resolution scanning camera for continuous-wave acoustic holography," Review of Scientific Instruments 89, 114901 (2018). https://doi.org/10.1063/1.5053666

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

qpolargraph-1.1.5.tar.gz (40.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

qpolargraph-1.1.5-py3-none-any.whl (39.9 kB view details)

Uploaded Python 3

File details

Details for the file qpolargraph-1.1.5.tar.gz.

File metadata

  • Download URL: qpolargraph-1.1.5.tar.gz
  • Upload date:
  • Size: 40.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for qpolargraph-1.1.5.tar.gz
Algorithm Hash digest
SHA256 37ba5840752bd9381b9efe2dd180d2e0dc551b332876224d07cb5f7f1040aa4c
MD5 b06a8cdbd36550d4679f857baddc85c5
BLAKE2b-256 86fcca7d44a99aa7aa2da11daf65349781776a624238be75650df87f386df85d

See more details on using hashes here.

Provenance

The following attestation bundles were made for qpolargraph-1.1.5.tar.gz:

Publisher: publish.yml on davidgrier/QPolargraph

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file qpolargraph-1.1.5-py3-none-any.whl.

File metadata

  • Download URL: qpolargraph-1.1.5-py3-none-any.whl
  • Upload date:
  • Size: 39.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for qpolargraph-1.1.5-py3-none-any.whl
Algorithm Hash digest
SHA256 3ccebc606391b0d84d471525b1fa9cd209b6672b745e8b5dd7853723eebceb3a
MD5 c115a190515978b651ce199ecdad4d51
BLAKE2b-256 b11c7d0fe32ecb04d217b56389e1711bc17c387a89db72395f6cd47fbdd01304

See more details on using hashes here.

Provenance

The following attestation bundles were made for qpolargraph-1.1.5-py3-none-any.whl:

Publisher: publish.yml on davidgrier/QPolargraph

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page