Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/boblio-max/origin/llms.txt

Use this file to discover all available pages before exploring further.

Origin’s servo control is built around the PCA9685 16-channel PWM driver, accessed over I2C using the Adafruit ServoKit library. The set servo.angle command gives you direct, angle-based control over any of the 16 available servo channels with a single readable statement — no PWM math, no duty-cycle calculations, and no manual library initialization required.

Syntax

set servo.angle <n>, <deg>
  • n — the PCA9685 channel number, 0 through 15
  • deg — the target angle in degrees
The parser reads set, then servo as the hardware name, then .angle as the subtype, then the channel number n, then a comma, and finally the angle deg. The interpreter translates this into the following Python:
from adafruit_servokit import ServoKit
_kit = ServoKit(channels=16) if '_kit' not in globals() else _kit
_kit.servo[n].angle = deg
The ServoKit instance (_kit) is lazily initialized once and reused for every subsequent set servo.angle call within the same script, so you pay the I2C setup cost only once.

Angle Clamping

Angle clamping is handled by the adafruit_servokit library itself, not by Origin. The library clamps the value assigned to .angle to the 0–180 degree range. Passing a value below 0 is treated as 0; passing a value above 180 is treated as 180. Origin relies on this library behavior to prevent accidental out-of-range commands that could strain servo gears or stall the motor.
While software clamping prevents out-of-range commands, it cannot protect against a servo that has a physical travel range narrower than 0–180°. Many hobby servos have a usable range of 45–135° or similar. Always verify your servo’s datasheet and test without load attached before commanding extreme angles.

Basic Examples

Center servo channel 1 (90° is the midpoint of the 0–180 range):
set servo.angle 1, 90
Move servo channel 0 to its minimum position:
set servo.angle 0, 0
Move servo channel 2 to its maximum position:
set servo.angle 2, 180

Full Example: Servo Sweep

This script sweeps servo channel 0 from 0° to 180° in 10° steps, pauses, then sweeps back to 0°.
import time

let channel: int = 0
let angle: int = 0

# Sweep from 0 to 180
while angle <= 180 {
    set servo.angle channel, angle
    time.sleep(0.05)
    angle += 10
}

time.sleep(0.5)

# Sweep back from 180 to 0
while angle >= 0 {
    set servo.angle channel, angle
    time.sleep(0.05)
    angle -= 10
}

print "Sweep complete."
1

Wire the PCA9685

Connect the PCA9685 board’s SDA and SCL pins to the Raspberry Pi’s I2C1 bus (physical pins 3 and 5). Power the board’s VCC from 3.3 V and connect GND. Power the servo rail (V+) from an external 5–6 V supply — never from the Pi’s 5 V pin.
2

Enable I2C

Run sudo raspi-config, navigate to Interface Options → I2C, and enable it. Reboot if prompted.
3

Install ServoKit

On your Pi, run pip install adafruit-circuitpython-servokit.
4

Attach the servo

Connect your servo’s signal wire (usually orange or yellow) to channel 0 on the PCA9685. Do not attach any mechanical load yet.
5

Run the sweep

Save the script as sweep.or and execute origin sweep.or. Verify the servo moves smoothly through its range before attaching any linkage.

PCA9685 Board Addressing

The PCA9685 communicates over I2C. Its default I2C address is 0x40, which is what Origin uses when ServoKit(channels=16) is initialized. If you have multiple PCA9685 boards on the same bus, you can configure different addresses by bridging the address pads on the board (A0–A5), giving addresses from 0x40 up to 0x7F.
Address Pads BridgedI2C Address
None (default)0x40
A00x41
A10x42
A0 + A10x43
To target a non-default address, use a py {} block to instantiate ServoKit with a custom address argument and assign it to _kit so subsequent set servo.angle calls reuse your custom instance.

Controlling Multiple Channels

Each set servo.angle call targets one channel independently. You can control multiple servos in the same script:
import time

set servo.angle 0, 45
set servo.angle 1, 90
set servo.angle 2, 135
time.sleep(1)

set servo.angle 0, 90
set servo.angle 1, 90
set servo.angle 2, 90
print "All servos centered."
Before attaching any arm, horn, or mechanical load to a servo, power it on and command set servo.angle <n>, 90 to move it to the center position. This lets you find the physical midpoint and mount your linkage symmetrically, which prevents binding at the travel extremes.

Build docs developers (and LLMs) love