things / servo-xiao

layout
schematic

README

Servo Thing

It’s a servo, innit!

Software

import Thing from '../../../src/lib/thing'
import Serializers from '../../../src/lib/osapjs/utils/serializers'

export default class servo extends Thing {

  // calibrated-angle-bounds,
  private pulseBounds = [500, 2500] // pulse-width bounds
  private angleBounds = [0, 180]  // angular bounds

  async setRGB(r, g, b) {
    let datagram = new Uint8Array(3);
    datagram[0] = r * 255;
    datagram[1] = g * 255;
    datagram[2] = b * 255;
    await this.send("setRGB", datagram);
  }

  async setLED(state) {
    let datagram = new Uint8Array([state > 0]);
    await this.send("setLED", datagram);
  }

  async writeMicroseconds(us: number){
    try {
      us = Math.round(us);
      console.log(us)
      let datagram = new Uint8Array(2);
      Serializers.writeUint16(datagram, 0, us);
      await this.send("writeMicroseconds", datagram);
    } catch (err) {
      throw err
    }
  }


  async writeAngle(angle: number){
    try {
      // constrain to as-specified bounds,
      if (angle < this.angleBounds[0]) angle = this.angleBounds[0]
      if (angle > this.angleBounds[1]) angle = this.angleBounds[1]
      // interpolate with microseconds-bounds match,
      let interp = (angle - this.angleBounds[0]) / (this.angleBounds[1] - this.angleBounds[0])
      interp = interp * (this.pulseBounds[1] - this.pulseBounds[0]) + this.pulseBounds[0]
      // and sendy
      await this.writeMicroseconds(interp)
    } catch (err) {
      throw err
    }
  }


  setCalibration(_pulseBounds, _angleBounds){
    if (!Array.isArray(_pulseBounds) || !Array.isArray(_angleBounds)) {
      throw new Error(`input args for setCalibration are both arrays`)
    }
    this.pulseBounds = _pulseBounds
    this.angleBounds = _angleBounds
  }


  public api = [
    {
      name: "writeMicroseconds",
      args: [
        "us: 0 to 2^16"
      ]
    },
    {
      name: "writeAngle",
      args: [
        "angle: num"
      ]
    },
    {
      name: "setCalibration",
      args: [
        "pulseBounds: [minMicros, maxMicros]",
        "angleBounds: [minAngle, maxAngle]"
      ]
    }
  ]
}

Firmware

#include <osap.h>
#include <Servo.h>

#define PIN_SERVO 29

Servo servo;

OSAP_Runtime osap;
OSAP_Gateway_USBSerial serLink(&Serial);
OSAP_Port_DeviceNames namePort("servo");

uint8_t rgb[3] = {0, 0, 255};
boolean ledState = false;

void writeMicroseconds(uint8_t* data, size_t len) {
  uint16_t pulse_us = data[1] * 256 + data[0];

  servo.writeMicroseconds(pulse_us);
}

void updateRGB() {
  if (ledState) {
    analogWrite(PIN_LED_R, 255-rgb[0]);
    analogWrite(PIN_LED_G, 255-rgb[1]);
    analogWrite(PIN_LED_B, 255-rgb[2]);
  } else {
    analogWrite(PIN_LED_R, 255);
    analogWrite(PIN_LED_G, 255);
    analogWrite(PIN_LED_B, 255);
  }
}

void onRGBPacket(uint8_t* data, size_t len){
  rgb[0] = data[0];
  rgb[1] = data[1];
  rgb[2] = data[2];
  ledState = true;
  updateRGB();
}

void onLEDPacket(uint8_t* data, size_t len){
  ledState = data[0] > 0;
  updateRGB();
}

OSAP_Port_Named setRGB("setRGB", onRGBPacket);
OSAP_Port_Named setLED("setLED", onLEDPacket);
OSAP_Port_Named writeMicroseconds_port("writeMicroseconds", writeMicroseconds);

void setup() {
  osap.begin();
  analogWriteResolution(8);
  pinMode(PIN_LED_R, OUTPUT);
  pinMode(PIN_LED_G, OUTPUT);
  pinMode(PIN_LED_B, OUTPUT);
  updateRGB();

  servo.attach(PIN_SERVO, 500, 2500);
}

void loop() {
  osap.loop();
}