8Servos2 Unit

The Servos8V2Unit class controls the Unit 8Servos2-I2C over I2C. The device provides eight configurable channels for GPIO input, GPIO output, ADC, servo, RGB, and PWM operation. It also provides power monitoring and device information APIs.

Support the following products:

Unit 8Servos2-I2C

Constants

Use the following constants with set_channel_mode():

  • MODE_INPUT: GPIO input mode.

  • MODE_OUTPUT: GPIO output mode.

  • MODE_ADC: ADC input mode.

  • MODE_SERVO: Servo control mode.

  • MODE_RGB: RGB output mode for WS2812 LEDs.

  • MODE_PWM: PWM duty output mode.

Use PULL_NONE, PULL_UP, or PULL_DOWN with set_input_pull().

Note

Channels 0-3 share one PWM frequency, and channels 4-7 share another. Setting the frequency of one channel changes every channel in the same group. Selecting servo mode sets the channel’s shared group to 50 Hz.

UiFlow2 Example

Servo control

Open the basic_8servos_v2_servo_control_example.m5f2 project in UiFlow2.

This example initializes Unit 8Servos2-I2C for servo control. Button A selects a channel or the all-channel option. Buttons B and C increase or decrease the servo angle in 10-degree steps. The screen displays the selected channel and current angle.

UiFlow2 Code Block:

example.png

Example output:

The selected servo output moves to the angle shown on the screen.

MicroPython Example

Servo control

This example initializes Unit 8Servos2-I2C for servo control. Button A selects a channel or the all-channel option. Buttons B and C increase or decrease the servo angle in 10-degree steps.

MicroPython Code Block:

  1# SPDX-FileCopyrightText: 2026 M5Stack Technology CO LTD
  2#
  3# SPDX-License-Identifier: MIT
  4
  5import os, sys, io
  6import M5
  7from M5 import *
  8from hardware import Pin
  9from hardware import I2C
 10from unit import Servos8V2Unit
 11
 12
 13label_title = None
 14label_channel = None
 15label_angle = None
 16label_sel = None
 17label_increase = None
 18label_decrease = None
 19i2c0 = None
 20servos8v2_0 = None
 21channel = None
 22angle = None
 23i = None
 24
 25
 26def btna_was_clicked_event(state):
 27    global \
 28        label_title, \
 29        label_channel, \
 30        label_angle, \
 31        label_sel, \
 32        label_increase, \
 33        label_decrease, \
 34        i2c0, \
 35        servos8v2_0, \
 36        channel, \
 37        angle, \
 38        i
 39    channel = (channel if isinstance(channel, (int, float)) else 0) + 1
 40    if channel >= 9:
 41        channel = 0
 42    if channel == 8:
 43        label_channel.setText(str("Channel: all"))
 44        for i in range(7):
 45            servos8v2_0.set_servo_angle(i, angle)
 46    else:
 47        label_channel.setText(str((str("Channel: ") + str(channel))))
 48        servos8v2_0.set_servo_angle(channel, angle)
 49
 50
 51def btnb_was_clicked_event(state):
 52    global \
 53        label_title, \
 54        label_channel, \
 55        label_angle, \
 56        label_sel, \
 57        label_increase, \
 58        label_decrease, \
 59        i2c0, \
 60        servos8v2_0, \
 61        channel, \
 62        angle, \
 63        i
 64    angle = angle + 10
 65    if angle >= 180:
 66        angle = 0
 67    if channel == 8:
 68        for i in range(7):
 69            servos8v2_0.set_servo_angle(i, angle)
 70    else:
 71        servos8v2_0.set_servo_angle(channel, angle)
 72    label_angle.setText(str((str("Angle: ") + str(angle))))
 73
 74
 75def btnc_was_clicked_event(state):
 76    global \
 77        label_title, \
 78        label_channel, \
 79        label_angle, \
 80        label_sel, \
 81        label_increase, \
 82        label_decrease, \
 83        i2c0, \
 84        servos8v2_0, \
 85        channel, \
 86        angle, \
 87        i
 88    angle = angle - 10
 89    if angle <= 0:
 90        angle = 180
 91    if channel == 8:
 92        for i in range(7):
 93            servos8v2_0.set_servo_angle(i, angle)
 94    else:
 95        servos8v2_0.set_servo_angle(channel, angle)
 96    label_angle.setText(str((str("Angle: ") + str(angle))))
 97
 98
 99def setup():
100    global \
101        label_title, \
102        label_channel, \
103        label_angle, \
104        label_sel, \
105        label_increase, \
106        label_decrease, \
107        i2c0, \
108        servos8v2_0, \
109        channel, \
110        angle, \
111        i
112
113    M5.begin()
114    Widgets.setRotation(1)
115    Widgets.fillScreen(0x000000)
116    label_title = Widgets.Label(
117        "Servo Control", 76, 2, 1.0, 0x1393E8, 0x000000, Widgets.FONTS.Montserrat24
118    )
119    label_channel = Widgets.Label(
120        "Channel: 1", 36, 77, 1.0, 0xFFFFFF, 0x000000, Widgets.FONTS.Montserrat24
121    )
122    label_angle = Widgets.Label(
123        "Angle: 0", 40, 112, 1.0, 0xFFFFFF, 0x000000, Widgets.FONTS.Montserrat24
124    )
125    label_sel = Widgets.Label(
126        "select", 43, 210, 1.0, 0xFFFFFF, 0x000000, Widgets.FONTS.Montserrat16
127    )
128    label_increase = Widgets.Label(
129        "+10", 143, 210, 1.0, 0xFFFFFF, 0x000000, Widgets.FONTS.Montserrat16
130    )
131    label_decrease = Widgets.Label(
132        "-10", 233, 210, 1.0, 0xFFFFFF, 0x000000, Widgets.FONTS.Montserrat16
133    )
134
135    BtnA.setCallback(type=BtnA.CB_TYPE.WAS_CLICKED, cb=btna_was_clicked_event)
136    BtnB.setCallback(type=BtnB.CB_TYPE.WAS_CLICKED, cb=btnb_was_clicked_event)
137    BtnC.setCallback(type=BtnC.CB_TYPE.WAS_CLICKED, cb=btnc_was_clicked_event)
138
139    i2c0 = I2C(0, scl=Pin(22), sda=Pin(21), freq=100000)
140    servos8v2_0 = Servos8V2Unit(i2c0, 0x25)
141    channel = 0
142    angle = 0
143    for i in range(7):
144        servos8v2_0.set_channel_mode(i, Servos8V2Unit.MODE_SERVO)
145        servos8v2_0.set_servo_angle(i, 0)
146
147
148def loop():
149    global \
150        label_title, \
151        label_channel, \
152        label_angle, \
153        label_sel, \
154        label_increase, \
155        label_decrease, \
156        i2c0, \
157        servos8v2_0, \
158        channel, \
159        angle, \
160        i
161    M5.update()
162
163
164if __name__ == "__main__":
165    try:
166        setup()
167        while True:
168            loop()
169    except (Exception, KeyboardInterrupt) as e:
170        try:
171            from utility import print_error_msg
172
173            print_error_msg(e)
174        except ImportError:
175            print("please update to latest firmware")

Example output:

The screen displays the selected channel and angle, and the selected servo output moves when the angle is changed.

API

Servos8V2Unit

class unit.servos8_v2.Servos8V2Unit(i2c, address=37)

Bases: object

Create a Unit 8Servos2 object.

Parameters:
  • i2c (machine.I2C | PAHUBUnit) – The I2C bus the Unit 8Servos2 is connected to.

  • address (int | list | tuple) – The I2C address of the device, range 0x25 to 0x34. Default is 0x25.

  • i2c

  • address

Raises:

UnitError – If the Unit 8Servos2 is not connected.

UiFlow2 Code Block:

init.png

MicroPython Code Block:

from hardware import I2C, Pin
from unit import Servos8V2Unit

i2c0 = I2C(0, scl=Pin(22), sda=Pin(21), freq=100000)
servos8v2_0 = Servos8V2Unit(i2c0, 0x25)
get_channel_mode(channel)

Get the current mode of a specific channel.

The channel mode values:

  • MODE_INPUT: 0x00

  • MODE_OUTPUT: 0x01

  • MODE_ADC: 0x02

  • MODE_SERVO: 0x03

  • MODE_RGB: 0x04

  • MODE_PWM: 0x05

Parameters:

channel (int) – The channel number (0 to 7).

Returns:

The mode of the specified channel.

Return type:

int

UiFlow2 Code Block:

get_channel_mode.png

MicroPython Code Block:

mode = servos8v2_0.get_channel_mode(0)
set_channel_mode(channel, mode)

Set the mode of a specific channel.

The channel mode values:

  • MODE_INPUT: 0x00

  • MODE_OUTPUT: 0x01

  • MODE_ADC: 0x02

  • MODE_SERVO: 0x03

  • MODE_RGB: 0x04

  • MODE_PWM: 0x05

When a channel is set to MODE_SERVO, the driver automatically sets its shared frequency group to 50 Hz. Channels 0-3 share one frequency, and channels 4-7 share another frequency.

Parameters:
  • channel (int) – The channel number (0 to 7).

  • mode (int) – The channel mode to set.

Return type:

None

UiFlow2 Code Block:

set_channel_mode.png

MicroPython Code Block:

servos8v2_0.set_channel_mode(0, Servos8V2Unit.MODE_SERVO)
set_input_pull(channel, pull)

Set the input pull configuration of a specific channel.

Parameters:
  • channel (int) – The channel number (0 to 7).

  • pull (int) – Pull configuration. Use PULL_NONE, PULL_UP, or PULL_DOWN.

Return type:

None

UiFlow2 Code Block:

set_input_pull.png

MicroPython Code Block:

servos8v2_0.set_input_pull(0, Servos8V2Unit.PULL_UP)
get_input_pull(channel)

Get the input pull configuration of a specific channel.

Parameters:

channel (int) – The channel number (0 to 7).

Returns:

Pull configuration of the specified channel.

Return type:

int

UiFlow2 Code Block:

get_input_pull.png

MicroPython Code Block:

pull = servos8v2_0.get_input_pull(0)
get_gpio_input_value(channel)

Get the GPIO input value of a specific channel.

Parameters:

channel (int) – The channel number (0 to 7).

Returns:

True for high level, False for low level.

Return type:

bool

UiFlow2 Code Block:

get_gpio_input_value.png

MicroPython Code Block:

level = servos8v2_0.get_gpio_input_value(0)
set_gpio_output_value(channel, value)

Set the GPIO output value of a specific channel.

Parameters:
  • channel (int) – The channel number (0 to 7).

  • value (bool) – Output value, False for low level or True for high level.

Return type:

None

UiFlow2 Code Block:

set_gpio_output_value.png

MicroPython Code Block:

servos8v2_0.set_gpio_output_value(0, True)
get_gpio_output_value(channel)

Get the GPIO output value of a specific channel.

Parameters:

channel (int) – The channel number (0 to 7).

Returns:

True for high level, False for low level.

Return type:

bool

UiFlow2 Code Block:

get_gpio_output_value.png

MicroPython Code Block:

level = servos8v2_0.get_gpio_output_value(0)
get_adc_input(channel)

Get the 12-bit ADC input value of a specific channel.

Parameters:

channel (int) – The channel number (0 to 7).

Returns:

ADC value, range 0 to 4095.

Return type:

int

UiFlow2 Code Block:

get_adc_input.png

MicroPython Code Block:

adc = servos8v2_0.get_adc_input(0)
set_servo_angle(channel, angle)

Set the servo angle of a specific channel.

Parameters:
  • channel (int) – The channel number (0 to 7).

  • angle (int) – Servo angle, range 0 to 180.

Return type:

None

UiFlow2 Code Block:

set_servo_angle.png

MicroPython Code Block:

servos8v2_0.set_servo_angle(0, 90)
get_servo_angle(channel)

Get the servo angle of a specific channel.

Parameters:

channel (int) – The channel number (0 to 7).

Returns:

Servo angle, range 0 to 180.

Return type:

int

UiFlow2 Code Block:

get_servo_angle.png

MicroPython Code Block:

angle = servos8v2_0.get_servo_angle(0)
set_rgb_config(channel, count, refresh=False)

Set the WS2812 LED count and refresh flag of a specific channel.

Parameters:
  • channel (int) – The channel number (0 to 7).

  • count (int) – WS2812 LED count, range 0 to 16.

  • refresh (bool) – Whether to trigger an RGB refresh. Default is False.

Return type:

None

UiFlow2 Code Block:

set_rgb_config.png

MicroPython Code Block:

servos8v2_0.set_rgb_config(0, 4, refresh=True)
get_rgb_config(channel)

Get the raw WS2812 config value of a specific channel.

Parameters:

channel (int) – The channel number (0 to 7).

Returns:

Raw RGB config byte.

Return type:

int

UiFlow2 Code Block:

get_rgb_config.png

MicroPython Code Block:

config = servos8v2_0.get_rgb_config(0)
get_rgb_count(channel)

Get the configured WS2812 LED count of a specific channel.

Parameters:

channel (int) – The channel number (0 to 7).

Returns:

WS2812 LED count, range 0 to 16.

Return type:

int

UiFlow2 Code Block:

get_rgb_count.png

MicroPython Code Block:

count = servos8v2_0.get_rgb_count(0)
refresh_rgb(channel)

Trigger WS2812 refresh for a specific channel.

Parameters:

channel (int) – The channel number (0 to 7).

Return type:

None

UiFlow2 Code Block:

refresh_rgb.png

MicroPython Code Block:

servos8v2_0.refresh_rgb(0)
set_rgb_buffer(index, color)

Set one WS2812 color buffer entry.

Parameters:
  • index (int) – WS2812 color buffer index, range 0 to 15.

  • color (int) – RGB888 color value in 0xRRGGBB format.

Return type:

None

UiFlow2 Code Block:

set_rgb_buffer.png

MicroPython Code Block:

servos8v2_0.set_rgb_buffer(0, 0xFF0000)
get_rgb_buffer(index)

Get one WS2812 color buffer entry.

Parameters:

index (int) – WS2812 color buffer index, range 0 to 15.

Returns:

RGB888 color value in 0xRRGGBB format.

Return type:

int

UiFlow2 Code Block:

get_rgb_buffer.png

MicroPython Code Block:

color = servos8v2_0.get_rgb_buffer(0)
set_pwm_duty(channel, duty)

Set the PWM duty of a specific channel.

Parameters:
  • channel (int) – The channel number (0 to 7).

  • duty (int) – PWM duty, range 0 to 100.

Return type:

None

UiFlow2 Code Block:

set_pwm_duty.png

MicroPython Code Block:

servos8v2_0.set_pwm_duty(0, 50)
get_pwm_duty(channel)

Get the PWM duty of a specific channel.

Parameters:

channel (int) – The channel number (0 to 7).

Returns:

PWM duty, range 0 to 100.

Return type:

int

UiFlow2 Code Block:

get_pwm_duty.png

MicroPython Code Block:

duty = servos8v2_0.get_pwm_duty(0)
set_pwm_freq(channel, freq)

Set the PWM frequency of a specific channel.

Channels 0-3 share one frequency, and channels 4-7 share another frequency. Setting the frequency of any channel changes the frequency of every channel in the same group.

Parameters:
  • channel (int) – The channel number (0 to 7).

  • freq (int) – PWM frequency in Hz, range 1 to 65535.

Return type:

None

UiFlow2 Code Block:

set_pwm_freq.png

MicroPython Code Block:

servos8v2_0.set_pwm_freq(0, 1000)
get_pwm_freq(channel)

Get the PWM frequency of a specific channel.

Channels 0-3 share one frequency, and channels 4-7 share another frequency. The returned value is the shared frequency of the channel’s group.

Parameters:

channel (int) – The channel number (0 to 7).

Returns:

PWM frequency in Hz.

Return type:

int

UiFlow2 Code Block:

get_pwm_freq.png

MicroPython Code Block:

freq = servos8v2_0.get_pwm_freq(0)
get_reference_voltage()

Get the reference voltage.

Returns:

Reference voltage in mV.

Return type:

int

UiFlow2 Code Block:

get_reference_voltage.png

MicroPython Code Block:

voltage = servos8v2_0.get_reference_voltage()
get_grove_voltage()

Get the Grove port voltage.

Returns:

Grove port voltage in mV.

Return type:

int

UiFlow2 Code Block:

get_grove_voltage.png

MicroPython Code Block:

voltage = servos8v2_0.get_grove_voltage()
get_dc_voltage()

Get the DC input voltage.

Returns:

DC input voltage in mV.

Return type:

int

UiFlow2 Code Block:

get_dc_voltage.png

MicroPython Code Block:

voltage = servos8v2_0.get_dc_voltage()
get_current()

Get the system current.

Returns:

System current in mA.

Return type:

int

UiFlow2 Code Block:

get_current.png

MicroPython Code Block:

current = servos8v2_0.get_current()
get_firmware_version()

Get the firmware version.

Returns:

Firmware version.

Return type:

int

UiFlow2 Code Block:

get_firmware_version.png

MicroPython Code Block:

version = servos8v2_0.get_firmware_version()
get_i2c_address()

Get the current I2C address.

Returns:

Current I2C address.

Return type:

int

UiFlow2 Code Block:

get_i2c_address.png

MicroPython Code Block:

address = servos8v2_0.get_i2c_address()
get_uid()

Get the 12-byte device UID.

Returns:

Tuple containing the 12 UID bytes.

Return type:

tuple

UiFlow2 Code Block:

get_uid.png

MicroPython Code Block:

uid = servos8v2_0.get_uid()