Skip to main content

Python library for controlling SciGlob scientific instrumentation: Head Sensors, Trackers, Filter Wheels, and more

Project description

SciGlob Library

Python library for controlling SciGlob scientific instrumentation

Python 3.9+ License: MIT


Overview

SciGlob Library provides a unified Python interface for controlling scientific instruments used in atmospheric monitoring systems, including:

Component Description Protocol
Head Sensor Main communication hub (SciGlobHSN1, SciGlobHSN2) RS-232
Tracker Azimuth/Zenith motor control (Directed Perceptions, LuftBlickTR1) via Head Sensor
Filter Wheels FW1, FW2 with 9 positions each via Head Sensor
Shadowband Shadowband arm positioning via Head Sensor
Temperature Controller TETech1 (16-bit), TETech2 (32-bit) RS-232
Humidity Sensor HDC2080EVM RS-232
GPS/Positioning GlobalSat (GPS), Novatel (GPS+Gyro) RS-232

Installation

From Source

git clone https://github.com/SciGlob/SciGlob-Library.git
cd SciGlob-Library
pip install -e .

With Development Dependencies

pip install -e ".[dev]"

Quick Start

Head Sensor with Tracker & Filter Wheels

from sciglob import HeadSensor

with HeadSensor(port="/dev/ttyUSB0") as hs:
    # Get device info
    print(f"Device: {hs.device_id}")
    print(f"Type: {hs.sensor_type}")
    
    # Read internal sensors (SciGlobHSN2 only)
    if hs.sensor_type == "SciGlobHSN2":
        print(f"Temperature: {hs.get_temperature()}°C")
        print(f"Humidity: {hs.get_humidity()}%")
        print(f"Pressure: {hs.get_pressure()} mbar")
    
    # Control tracker (azimuth/zenith motors)
    tracker = hs.tracker
    tracker.move_to(zenith=45.0, azimuth=180.0)
    print(f"Position: {tracker.get_position()}")
    
    # Control filter wheel
    fw1 = hs.filter_wheel_1
    fw1.set_filter("OPEN")
    print(f"Current filter: {fw1.current_filter}")

Tracker Commands

# Movement in degrees
tracker.move_to(zenith=45.0, azimuth=180.0)  # Absolute position
tracker.move_relative(delta_zenith=10.0, delta_azimuth=-20.0)  # Relative
tracker.pan(azimuth=90.0)   # Azimuth only
tracker.tilt(zenith=30.0)   # Zenith only

# Movement in steps
tracker.move_to_steps(zenith_steps=4500, azimuth_steps=-1200)

# Get position
zenith, azimuth = tracker.get_position()       # In degrees
azi_steps, zen_steps = tracker.get_position_steps()  # In steps

# Special commands
tracker.home()          # Go to home position
tracker.park()          # Go to parking position
tracker.reset()         # Soft reset
tracker.power_reset()   # Power cycle

# LuftBlickTR1 specific
if tracker.is_luftblick:
    temps = tracker.get_motor_temperatures()
    alarms = tracker.get_motor_alarms()
    tracker.check_alarms()  # Raises exception if alarm present

Filter Wheel Commands

# Select by position (1-9)
fw1.set_position(5)

# Select by filter name
fw1.set_filter("U340")

# Get current state
print(fw1.position)       # Current position number
print(fw1.current_filter) # Current filter name

# Get filter configuration
print(fw1.get_filter_map())        # {1: "OPEN", 2: "U340", ...}
print(fw1.get_available_filters()) # ["OPEN", "U340", ...]

# Reset to home
fw1.reset()

Temperature Controller

from sciglob import TemperatureController

with TemperatureController(port="/dev/ttyUSB1", controller_type="TETech1") as tc:
    # Read temperature
    print(f"Current: {tc.get_temperature()}°C")
    print(f"Setpoint: {tc.get_setpoint()}°C")
    
    # Set temperature
    tc.set_temperature(25.0)
    
    # Control output
    tc.enable_output()
    tc.disable_output()

Humidity Sensor

from sciglob import HumiditySensor

with HumiditySensor(port="/dev/ttyUSB2") as hs:
    print(f"Temperature: {hs.get_temperature()}°C")
    print(f"Humidity: {hs.get_humidity()}%")

GPS Positioning

from sciglob import GlobalSatGPS, NovatelGPS

# Simple GPS
with GlobalSatGPS(port="/dev/ttyUSB3") as gps:
    pos = gps.get_position()
    print(f"Lat: {pos['latitude']}, Lon: {pos['longitude']}")

# GPS + Gyroscope
with NovatelGPS(port="/dev/ttyUSB4") as gps:
    pos = gps.get_position()
    orient = gps.get_orientation()
    print(f"Yaw: {orient['yaw']}°, Pitch: {orient['pitch']}°")

Architecture

┌─────────────────────────────────────────────────────────────────┐
│                        Application                               │
└─────────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌─────────────────────────────────────────────────────────────────┐
│                    SciGlob Library API                          │
│  ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐   │
│  │  Head   │ │ Tracker │ │ Filter  │ │  Temp   │ │  GPS    │   │
│  │ Sensor  │ │         │ │  Wheel  │ │ Control │ │         │   │
│  └────┬────┘ └────┬────┘ └────┬────┘ └────┬────┘ └────┬────┘   │
│       │          │          │          │          │            │
│       └──────────┴──────────┘          │          │            │
│                  │                      │          │            │
└──────────────────┼──────────────────────┼──────────┼────────────┘
                   │                      │          │
                   ▼                      ▼          ▼
           ┌────────────┐          ┌────────────────────────┐
           │ Head Sensor│          │   Independent Devices  │
           │   RS-232   │          │       RS-232           │
           │  (9600 bd) │          │      (9600 bd)         │
           └────────────┘          └────────────────────────┘

Device Commands Quick Reference

Head Sensor

Command Response Description
? Device ID Query identification
HTt? HT!<value> Temperature (÷100 = °C)
HTh? HT!<value> Humidity (÷1024 = %)
HTp? HT!<value> Pressure (÷100 = mbar)

Tracker

Command Response Description
TRp<steps> TR0 Pan (azimuth only)
TRt<steps> TR0 Tilt (zenith only)
TRb<azi>,<zen> TR0 Move both axes
TRw TRh<azi>,<zen> Query position
TRr TR0 Soft reset
TRs TR0 Power reset

Filter Wheel

Command Response Description
F1<1-9> F10 Set FW1 position
F2<1-9> F20 Set FW2 position
F1r F10 Reset FW1
F2r F20 Reset FW2

Error Handling

from sciglob import (
    HeadSensor,
    ConnectionError,
    TrackerError,
    PositionError,
    FilterWheelError,
    MotorAlarmError,
)

try:
    with HeadSensor(port="/dev/ttyUSB0") as hs:
        # This will raise PositionError if out of limits
        hs.tracker.move_to(zenith=100.0, azimuth=180.0)
        
except ConnectionError as e:
    print(f"Connection failed: {e}")
except PositionError as e:
    print(f"Position out of range: {e.position} not in [{e.min_pos}, {e.max_pos}]")
except MotorAlarmError as e:
    print(f"Motor alarm on {e.axis}: code {e.alarm_code}")
except TrackerError as e:
    print(f"Tracker error: {e}")

Configuration

Head Sensor Configuration

hs = HeadSensor(
    port="/dev/ttyUSB0",
    baudrate=9600,
    tracker_type="LuftBlickTR1",     # or "Directed Perceptions"
    degrees_per_step=0.01,           # 100 steps per degree
    motion_limits=[0, 90, 0, 360],   # [zen_min, zen_max, azi_min, azi_max]
    home_position=[0.0, 180.0],      # [zenith_home, azimuth_home]
    fw1_filters=["OPEN", "U340", "BP300", "LPNIR", "ND1", "ND2", "ND3", "ND4", "OPAQUE"],
    fw2_filters=["OPEN", "DIFF", "U340+DIFF", ...],
)

Logging

import logging

# Enable debug logging
logging.basicConfig(level=logging.DEBUG)
logging.getLogger("sciglob").setLevel(logging.DEBUG)

# Or for specific components
logging.getLogger("sciglob.Tracker").setLevel(logging.DEBUG)
logging.getLogger("sciglob.serial").setLevel(logging.DEBUG)

Requirements

  • Python 3.9+
  • pyserial >= 3.5
  • pyyaml >= 6.0

License

MIT License - see LICENSE for details.


Documentation


Contributing

  1. Fork the repository
  2. Create a feature branch
  3. Make your changes
  4. Run tests: pytest
  5. Submit a pull request

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

sciglob-0.1.0.tar.gz (53.0 kB view details)

Uploaded Source

Built Distribution

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

sciglob-0.1.0-py3-none-any.whl (40.9 kB view details)

Uploaded Python 3

File details

Details for the file sciglob-0.1.0.tar.gz.

File metadata

  • Download URL: sciglob-0.1.0.tar.gz
  • Upload date:
  • Size: 53.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.8

File hashes

Hashes for sciglob-0.1.0.tar.gz
Algorithm Hash digest
SHA256 5a3d6c185e6b77f190820a6397db1bd5fd31729df0284aba15909c49f10d12d1
MD5 56fc69f2a7d02ad39cc7780c15e0cb93
BLAKE2b-256 4dfefc2b16c3f2d89e05c7e17ad4de121dbc2b8d910175e31b9ffb90d035766c

See more details on using hashes here.

File details

Details for the file sciglob-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: sciglob-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 40.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.8

File hashes

Hashes for sciglob-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 688d64942e119349fdef5795375aea619b7b29f0d8e8a6d7284a4e171c915f2e
MD5 2f4c40c81a2fb069dfadf05daa3b3381
BLAKE2b-256 f241ec0e0762b526dc372a23df72ec7fdf10a34698b6bc4d52281516e16d793e

See more details on using hashes here.

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