Bala2 Module

The Bala2 Module is part of the M5Stack stackable module series. The module communicates with the host via the I2C interface, and its built-in microcontroller manages PWM control for the motor, reads the encoder count, and outputs control signals for the servo.

Support the following products:

Bala2

Bala2-Fire

UiFlow2 Example

Servo control

Open the servo_control_example.m5f2 project in UiFlow2.

Control the servo to swing back and forth between 0° and 180°.

UiFlow2 Code Block:

servo_control_example.png

Example output:

None

Motor control

Open the motor_control_example.m5f2 project in UiFlow2.

Run the program, and the car’s motors will first rotate forward, gradually accelerating to the maximum speed, then gradually decelerating to a stop. Next, the motors will reverse, similarly accelerating to the maximum speed before gradually slowing down to a stop. Finally, the car will come to a complete stop, with the motor speed returning to zero.

UiFlow2 Code Block:

motor_control_example.png

Example output:

None

Read encoder

Open the read_encoder_example.m5f2 project in UiFlow2.

Run the program and manually rotate the wheels to observe the screen display.

UiFlow2 Code Block:

read_encoder_example.png

Example output:

None

Car control

Open the car_control_example.m5f2 project in UiFlow2.

Save the program to the controller, place the car on its side, and turn it on. After the gyroscope calibration is complete, the car will automatically stand upright and maintain balance. It will then perform a series of actions, including turning left, turning right, moving forward, and moving backward. Finally, it will stop and return to the balanced state.

UiFlow2 Code Block:

car_control_example.png

Example output:

None

MicroPython Example

Servo control

Control the servo to swing back and forth between 0° and 180°.

MicroPython Code Block:

 1# SPDX-FileCopyrightText: 2025 M5Stack Technology CO LTD
 2#
 3# SPDX-License-Identifier: MIT
 4
 5import os, sys, io
 6import M5
 7from M5 import *
 8from module import Bala2Module
 9import time
10
11
12title0 = None
13label_servo1 = None
14label_servo1_val = None
15module_bala2_0 = None
16t_dir = None
17last_time = None
18angle = None
19
20
21def setup():
22    global title0, label_servo1, label_servo1_val, module_bala2_0, t_dir, last_time, angle
23    M5.begin()
24    Widgets.fillScreen(0x222222)
25    title0 = Widgets.Title("Bala2 Servo Control", 3, 0xFFFFFF, 0x0000FF, Widgets.FONTS.DejaVu24)
26    label_servo1 = Widgets.Label("Angle:", 54, 85, 1.0, 0xFFFFFF, 0x222222, Widgets.FONTS.DejaVu18)
27    label_servo1_val = Widgets.Label("0", 125, 85, 1.0, 0xFFFFFF, 0x222222, Widgets.FONTS.DejaVu18)
28    module_bala2_0 = Bala2Module(0)
29    t_dir = True
30    angle = 0
31    last_time = time.ticks_ms()
32
33
34def loop():
35    global title0, label_servo1, label_servo1_val, module_bala2_0, t_dir, last_time, angle
36    M5.update()
37    if (time.ticks_diff((time.ticks_ms()), last_time)) > 10:
38        last_time = time.ticks_ms()
39        angle = angle + 1
40        if angle > 180:
41            angle = 0
42            t_dir = not t_dir
43        if t_dir:
44            module_bala2_0.set_servo_angle(1, angle)
45        else:
46            module_bala2_0.set_servo_angle(1, 180 - angle)
47        label_servo1_val.setText(str(angle))
48
49
50if __name__ == "__main__":
51    try:
52        setup()
53        while True:
54            loop()
55    except (Exception, KeyboardInterrupt) as e:
56        try:
57            from utility import print_error_msg
58
59            print_error_msg(e)
60        except ImportError:
61            print("please update to latest firmware")

Example output:

None

Motor control

Run the program, and the car’s motors will first rotate forward, gradually accelerating to the maximum speed, then gradually decelerating to a stop. Next, the motors will reverse, similarly accelerating to the maximum speed before gradually slowing down to a stop. Finally, the car will come to a complete stop, with the motor speed returning to zero.

MicroPython Code Block:

 1# SPDX-FileCopyrightText: 2025 M5Stack Technology CO LTD
 2#
 3# SPDX-License-Identifier: MIT
 4
 5import os, sys, io
 6import M5
 7from M5 import *
 8from module import Bala2Module
 9import time
10
11
12title0 = None
13module_bala2_0 = None
14i = None
15
16
17def setup():
18    global title0, module_bala2_0, i
19    M5.begin()
20    Widgets.fillScreen(0x222222)
21    title0 = Widgets.Title("Bala2 Motor Control", 3, 0xFFFFFF, 0x0000FF, Widgets.FONTS.DejaVu24)
22
23    module_bala2_0 = Bala2Module(0)
24    for i in range(1, 1001):
25        module_bala2_0.set_motor_speed(i, i)
26        time.sleep_ms(10)
27    for i in range(1, 1001):
28        module_bala2_0.set_motor_speed(1000 - i, 1000 - i)
29        time.sleep_ms(10)
30    for i in range(1, 1001):
31        module_bala2_0.set_motor_speed(0 - i, 0 - i)
32        time.sleep_ms(10)
33    for i in range(-1000, 1):
34        module_bala2_0.set_motor_speed(i, i)
35        time.sleep_ms(10)
36    module_bala2_0.set_motor_speed(0, 0)
37
38
39def loop():
40    global title0, module_bala2_0, i
41    M5.update()
42
43
44if __name__ == "__main__":
45    try:
46        setup()
47        while True:
48            loop()
49    except (Exception, KeyboardInterrupt) as e:
50        try:
51            from utility import print_error_msg
52
53            print_error_msg(e)
54        except ImportError:
55            print("please update to latest firmware")

Example output:

None

Read encoder

Run the program and manually rotate the wheels to observe the screen display.

MicroPython Code Block:

 1# SPDX-FileCopyrightText: 2025 M5Stack Technology CO LTD
 2#
 3# SPDX-License-Identifier: MIT
 4
 5import os, sys, io
 6import M5
 7from M5 import *
 8from module import Bala2Module
 9import time
10
11
12title0 = None
13label_enc1 = None
14label_enc2 = None
15label_enc1_val = None
16label_enc2_val = None
17module_bala2_0 = None
18last_time = None
19enc_value = None
20enc1 = None
21enc2 = None
22
23
24def setup():
25    global \
26        title0, \
27        label_enc1, \
28        label_enc2, \
29        label_enc1_val, \
30        label_enc2_val, \
31        module_bala2_0, \
32        last_time, \
33        enc_value, \
34        enc1, \
35        enc2
36    M5.begin()
37    Widgets.fillScreen(0x222222)
38    title0 = Widgets.Title("Bala2 Encoder Read", 3, 0xFFFFFF, 0x0000FF, Widgets.FONTS.DejaVu24)
39    label_enc1 = Widgets.Label("Enc1", 54, 85, 1.0, 0xFFFFFF, 0x222222, Widgets.FONTS.DejaVu18)
40    label_enc2 = Widgets.Label("Enc2", 208, 85, 1.0, 0xFFFFFF, 0x222222, Widgets.FONTS.DejaVu18)
41    label_enc1_val = Widgets.Label("0", 50, 125, 1.0, 0xFFFFFF, 0x222222, Widgets.FONTS.DejaVu18)
42    label_enc2_val = Widgets.Label("0", 202, 125, 1.0, 0xFFFFFF, 0x222222, Widgets.FONTS.DejaVu18)
43    module_bala2_0 = Bala2Module(0)
44    module_bala2_0.set_encoder_value(0, 0)
45    last_time = time.ticks_ms()
46
47
48def loop():
49    global \
50        title0, \
51        label_enc1, \
52        label_enc2, \
53        label_enc1_val, \
54        label_enc2_val, \
55        module_bala2_0, \
56        last_time, \
57        enc_value, \
58        enc1, \
59        enc2
60    M5.update()
61    if (time.ticks_diff((time.ticks_ms()), last_time)) > 100:
62        last_time = time.ticks_ms()
63        enc_value = module_bala2_0.get_encoder_value()
64        enc1 = enc_value[0]
65        enc2 = enc_value[1]
66        label_enc1_val.setText(str(enc1))
67        label_enc2_val.setText(str(enc2))
68
69
70if __name__ == "__main__":
71    try:
72        setup()
73        while True:
74            loop()
75    except (Exception, KeyboardInterrupt) as e:
76        try:
77            from utility import print_error_msg
78
79            print_error_msg(e)
80        except ImportError:
81            print("please update to latest firmware")

Example output:

None

Car control

Save the program to the controller, place the car on its side, and turn it on. After the gyroscope calibration is complete, the car will automatically stand upright and maintain balance. It will then perform a series of actions, including turning left, turning right, moving forward, and moving backward. Finally, it will stop and return to the balanced state.

MicroPython Code Block:

 1# SPDX-FileCopyrightText: 2025 M5Stack Technology CO LTD
 2#
 3# SPDX-License-Identifier: MIT
 4
 5import os, sys, io
 6import M5
 7from M5 import *
 8from module import Bala2Module
 9import time
10
11
12title0 = None
13module_bala2_0 = None
14i = None
15
16
17def setup():
18    global title0, module_bala2_0, i
19    M5.begin()
20    Widgets.fillScreen(0x222222)
21    title0 = Widgets.Title("Self-Balancing Robot", 3, 0xFFFFFF, 0x0000FF, Widgets.FONTS.DejaVu24)
22    module_bala2_0 = Bala2Module(0)
23    module_bala2_0.calibrate()
24    module_bala2_0.start()
25    time.sleep_ms(2000)
26    module_bala2_0.set_turn_speed(-100)
27    time.sleep_ms(1000)
28    module_bala2_0.set_turn_speed(100)
29    time.sleep_ms(1000)
30    module_bala2_0.set_turn_speed(0)
31    time.sleep_ms(2000)
32    for i in range(20):
33        module_bala2_0.set_angle_pid_target(0 - i)
34        time.sleep_ms(100)
35    time.sleep_ms(2000)
36    for i in range(20):
37        module_bala2_0.set_angle_pid_target(i - 20)
38        time.sleep_ms(100)
39    for i in range(20):
40        module_bala2_0.set_angle_pid_target(i)
41        time.sleep_ms(100)
42    time.sleep_ms(2000)
43    for i in range(20):
44        module_bala2_0.set_angle_pid_target(20 - i)
45        time.sleep_ms(100)
46    module_bala2_0.set_angle_pid_target(0)
47
48
49def loop():
50    global title0, module_bala2_0, i
51    M5.update()
52
53
54if __name__ == "__main__":
55    try:
56        setup()
57        while True:
58            loop()
59    except (Exception, KeyboardInterrupt) as e:
60        try:
61            from utility import print_error_msg
62
63            print_error_msg(e)
64        except ImportError:
65            print("please update to latest firmware")

Example output:

None

API

Bala2Module

class module.bala2.Bala2Module(timer_id=0)

Create an Bala2Module object.

Parameters:

timer_id (int) – Timer ID from 0 to 3 (Use a timer to periodically call the balance control program.)

UiFlow2 Code Block:

init.png

MicroPython Code Block:

from module import Bala2Module

module_bala2_0 = Bala2Module(timer_id = 0)
calibrate()

Calibrate sensor

UiFlow2 Code Block:

calibrate.png

MicroPython Code Block:

module_bala2_0.calibrate()
set_motor_speed(left, right)

Set motor speed

Parameters:
  • left (int) – The speed of the left motor. Range: -1023 ~ 1023.

  • right (int) – The speed of the right motor. Range: -1023 ~ 1023.

UiFlow2 Code Block:

set_motor_speed.png

MicroPython Code Block:

module_bala2_0.set_motor_speed(left, right)
set_encoder_value(left, right)

Set encoder value

Parameters:
  • left (int) – The value of the left encoder. Range: -2^31 ~ 2^31.

  • right (int) – The value of the right encoder. Range: -2^31 ~ 2^31.

UiFlow2 Code Block:

set_encoder_value.png

MicroPython Code Block:

module_bala2_0.set_encoder_value(left, right)
get_encoder_value()

The left, right encoder value returned in a 2-tuple

Returns:

left, right encoder value

Return type:

tuple[int, int]

UiFlow2 Code Block:

get_encoder_value.png

MicroPython Code Block:

module_bala2_0.get_encoder_value()
set_servo_angle(pos, angle)

Set servo angle

Parameters:
  • pos (int) – The position of the output cahnnel. Range: 1 ~ 4.

  • angle (int) – The value of the right encoder. Range: 0 ~ 180.

UiFlow2 Code Block:

set_servo_angle.png

MicroPython Code Block:

module_bala2_0.set_servo_angle(pos, angle)
start()

Start the balance car (car upright balance)

UiFlow2 Code Block:

start.png

MicroPython Code Block:

module_bala2_0.start()
stop()

Stop the balance car (stop the balance control of the car)

UiFlow2 Code Block:

stop.png

MicroPython Code Block:

module_bala2_0.stop()
get_angle()

Get the tilt angle of the balance car

Returns:

The angle of the car

Return type:

int

Data is valid only when the car is running (start() is called).

UiFlow2 Code Block:

get_angle.png

MicroPython Code Block:

module_bala2_0.get_angle()
set_angle_pid(kp, ki, kd)

Set angle PID parameters

Parameters:
  • kp (float) – Proportional gain

  • ki (float) – Integral gain

  • kd (float) – Derivative gain

UiFlow2 Code Block:

set_angle_pid.png

MicroPython Code Block:

module_bala2_0.set_angle_pid(kp, ki, kd)
get_angle_pid()

The angle loop PID parameters returned in a 3-tuple

Returns:

kp, ki, kd parameters

Return type:

tuple[float, float, float]

UiFlow2 Code Block:

get_angle_pid.png

MicroPython Code Block:

module_bala2_0.get_angle_pid()
set_angle_pid_target(angle=0)

Set angle loop PID control target.

Parameters:

angle (float) – The angle of the angle loop PID control target. Default is 0.

UiFlow2 Code Block:

set_angle_pid_target.png

MicroPython Code Block:

module_bala2_0.set_angle_pid_target(angle)
get_angle_pid_target()

Get angle loop PID control target

Returns:

The angle loop PID control target

Return type:

float

UiFlow2 Code Block:

get_angle_pid_target.png

MicroPython Code Block:

module_bala2_0.get_angle_pid_target()
set_speed_pid(kp, ki, kd)

Set speed loop PID parameters.

Parameters:
  • kp (float) – Proportional gain

  • ki (float) – Integral gain

  • kd (float) – Derivative gain

UiFlow2 Code Block:

set_speed_pid.png

MicroPython Code Block:

module_bala2_0.set_speed_pid(kp, ki, kd)
get_speed_pid()

The speed loop PID parameters returned in a 3-tuple

Returns:

kp, ki, kd parameters

Return type:

tuple[float, float, float]

UiFlow2 Code Block:

get_speed_pid.png

MicroPython Code Block:

module_bala2_0.get_speed_pid()
set_speed_pid_target(speed=0)

Set speed loop PID control target.

Parameters:

speed (float) – The speed of the speed loop PID control target. Default is 0.

UiFlow2 Code Block:

set_speed_pid_target.png

MicroPython Code Block:

module_bala2_0.set_speed_pid_target(speed)
get_speed_pid_target()

Get speed loop PID control target

Returns:

The speed loop PID control target

Return type:

float

UiFlow2 Code Block:

get_speed_pid_target.png

MicroPython Code Block:

module_bala2_0.get_speed_pid_target()
set_turn_speed(speed)

Set turning speed

Parameters:

speed (float) – The speed of the left and right motor offset

UiFlow2 Code Block:

set_turn_speed.png

MicroPython Code Block:

module_bala2_0.set_turn_speed(speed)