Skip to content

connormmckelvey/Haplink

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

10 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Haplink™ Communication Protocol

License: MIT Python Version

Haplink is a lightweight, high-performance communication library for haptic robotic devices. It provides a robust bidirectional serial protocol for real-time parameter control and telemetry streaming between embedded devices (Arduino/microcontrollers) and host computers (Python).


Features

Core Capabilities

  • Bidirectional Communication: Send parameters to devices and receive telemetry data
  • Type-Safe Protocol: Support for UINT8, INT16, INT32, FLOAT, and DOUBLE data types
  • Real-Time Performance: Optimized for low-latency control loops in haptic applications
  • Error Detection: XOR checksum validation for reliable data transmission
  • Simple API: Clean, intuitive interfaces for both firmware and host software

Firmware (C++ for Arduino)

  • Zero-copy packet parsing
  • Interrupt-safe design
  • Registry-based variable binding (up to 32 parameters + 32 telemetry variables)
  • Minimal memory footprint
  • Full Firmware Documentation

Python Client

  • Object-oriented API with type hints
  • Automatic packet synchronization
  • Connection management with timeout detection
  • Human-readable variable naming
  • Full Python Documentation

Installation

Python Client

Install directly from GitHub:

# Latest version
pip install git+https://github.com/connormmckelvey/Haplink.git#subdirectory=python

Requirements: Python 3.8+ and pyserial>=3.5

→ Detailed Python installation guide

Firmware Library (Arduino)

Install if using Platform.io:

#inside your platformio.ini
lib_deps =
    https://github.com/Connormmckelvey/Haplink.git

Install from GitHub:

# Clone the repository
git clone https://github.com/connormmckelvey/Haplink.git

# Copy to Arduino libraries
# Windows:
cp -r Haplink/firmware/src ~/Documents/Arduino/libraries/Haplink
# macOS/Linux:
cp -r Haplink/firmware/src ~/Arduino/libraries/Haplink

Then restart Arduino IDE and use: #include <haplink.h>

→ Detailed firmware installation guide


Quick Start

Firmware Side (Arduino)

#include <haplink.h>

Haplink haplink;

// Variables to expose
float targetPosition = 0.0;
float currentPosition = 0.0;
float currentVelocity = 0.0;

void setup() {
    Serial.begin(115200);
    
    // Initialize Haplink with Serial port
    haplink.begin(Serial);
    
    // Register parameter (writable from host)
    haplink.registerParam(1, &targetPosition, HL_FLOAT);
    
    // Register telemetry (readable by host)
    haplink.registerTelemetry(1, &currentPosition, HL_FLOAT);
    haplink.registerTelemetry(2, &currentVelocity, HL_FLOAT);
}

void loop() {
    // Process incoming commands
    haplink.update();
    
    // Your control logic here
    currentPosition += currentVelocity * 0.01;
    currentVelocity = (targetPosition - currentPosition) * 0.5;
    
    // Send telemetry data (optional: automatic streaming coming soon)
    haplink.sendTelemetry(1); // Send position
    haplink.sendTelemetry(2); // Send velocity
    
    delay(10); // 100 Hz loop
}

Python Side (Host)

from haplink import Haplink, DataType
import time

# Connect to device
haplink = Haplink('COM5', baudrate=115200)  # Use '/dev/ttyUSB0' on Linux
haplink.connect()

# Register variables (IDs must match Arduino sketch)
haplink.register_param(1, 'target_position', DataType.FLOAT)
haplink.register_telemetry(1, 'current_position', DataType.FLOAT)
haplink.register_telemetry(2, 'current_velocity', DataType.FLOAT)

# Control loop
for i in range(100):
    # Receive telemetry from device
    haplink.update()
    
    # Read telemetry values
    position = haplink.get_telemetry('current_position')
    velocity = haplink.get_telemetry('current_velocity')
    
    # Send new target position
    target = 0.5 * (1 + i / 100.0)
    haplink.set_param('target_position', target)
    
    print(f"Target: {target:.3f} | Position: {position} | Velocity: {velocity}")
    time.sleep(0.01)

# Cleanup
haplink.disconnect()

Documentation

Complete API References

Quick API Overview

Python

# Connection
haplink = Haplink('COM5', baudrate=115200)
haplink.connect()

# Registration
haplink.register_param(id, 'name', DataType.FLOAT)
haplink.register_telemetry(id, 'name', DataType.FLOAT)

# Usage
haplink.set_param('name', value)
value = haplink.get_telemetry('name')
haplink.update()  # Call regularly

Arduino

// Initialization
haplink.begin(Serial);

// Registration
haplink.registerParam(id, &variable, HL_FLOAT);
haplink.registerTelemetry(id, &variable, HL_FLOAT);

// Usage
haplink.update();  // Call in loop()
haplink.sendTelemetry(id);
haplink.sendAllTelemetry();

Protocol Specification

Haplink uses a simple, robust 13-byte packet protocol optimized for real-time communication.

Packet Structure (13 bytes)

Byte Field Description
0 Header Start byte (0xAA)
1 Packet Type Command type
2 ID Parameter or telemetry identifier
3 Data Type Type code (1-5)
4-11 Data Payload (8 bytes, little-endian)
12 Checksum XOR of bytes 1-11

Packet Types

Type Code Direction Description
PARAM_WRITE 0xA1 Host → Device Write parameter value
PARAM_READ 0xA2 Host → Device Request parameter value
TELEMETRY 0xB1 Device → Host Stream telemetry data
HEARTBEAT 0xC1 Bidirectional Keep-alive signal

Supported Data Types

  • UINT8 (1 byte): Unsigned 8-bit integer
  • INT16 (2 bytes): Signed 16-bit integer
  • INT32 (4 bytes): Signed 32-bit integer
  • FLOAT (4 bytes): IEEE 754 single-precision
  • DOUBLE (8 bytes): IEEE 754 double-precision

All data is little-endian and padded to 8 bytes. Packets use XOR checksum for error detection.


Examples

Complete Position Control System

Arduino (more examples →):

#include <haplink.h>

Haplink haplink;
float targetPos = 0.0;
float currentPos = 0.0;

void setup() {
    Serial.begin(115200);
    haplink.begin(Serial);
    haplink.registerParam(1, &targetPos, HL_FLOAT);
    haplink.registerTelemetry(1, &currentPos, HL_FLOAT);
}

void loop() {
    haplink.update();
    currentPos += (targetPos - currentPos) * 0.1;  // Simple controller
    haplink.sendTelemetry(1);
    delay(10);
}

Python (more examples →):

from haplink import Haplink, DataType
import time

haplink = Haplink('COM5')
haplink.connect()
haplink.register_param(1, 'target', DataType.FLOAT)
haplink.register_telemetry(1, 'position', DataType.FLOAT)

for angle in range(0, 360, 5):
    target = angle / 360.0
    haplink.set_param('target', target)
    haplink.update()
    print(f"Pos: {haplink.get_telemetry('position'):.2f}")
    time.sleep(0.05)

haplink.disconnect()

See also:


Troubleshooting

Common Issues

Issue Quick Fix
connect() returns False Verify port name, check baud rate matches (115200), ensure Arduino is powered
Telemetry stays None Call haplink.update() in Python loop, call sendTelemetry() in Arduino
Variables not updating Ensure IDs match on both sides, check data types match
Checksum errors Try lower baud rate, check USB cable quality

For detailed troubleshooting guides:


Contributing

Contributions are welcome! Please:

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/amazing-feature)
  3. Commit changes (git commit -m 'Add amazing feature')
  4. Push to branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

License

MIT License - see LICENSE for details.


Author

Connor McKelvey


Acknowledgments

Built for the haptic robotics research community. Special thanks to the HERO research group at The University of Texas, and the members of the Freshman Research Initative.


Support & Resources


About

Arduino Firmware and Python library designed for robust serial communication between haptic robotics applications.

Topics

Resources

License

Stars

Watchers

Forks

Contributors