Skip to content

Commit 3c3705c

Browse files
committed
Add 8Servos2
1 parent 4136fa0 commit 3c3705c

19 files changed

Lines changed: 6408 additions & 9 deletions

File tree

README.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,3 +143,16 @@ https://docs.m5stack.com/en/products/sku/U227
143143

144144
## License
145145
- [MIT](https://github.com/m5stack/M5Chain/blob/main/LICENSE)
146+
147+
# Unit 8Servos2 Chain
148+
149+
## Overview
150+
Unit 8Servos2 Chain is an 8-channel multifunction output node in the M5Stack Chain series. It supports GPIO input and output, ADC sampling, servo angle control, RGB LED buffer control, PWM duty configuration, and voltage/current monitoring through the Chain UART daisy-chain protocol. It is suitable for robot control, smart toys, servo expansion, and mixed GPIO/PWM interaction applications.
151+
152+
### SKU: U223
153+
154+
## Related Link
155+
https://docs.m5stack.com/en/products/sku/U223
156+
157+
## License
158+
- [MIT](https://github.com/m5stack/M5Chain/blob/main/LICENSE)
Lines changed: 297 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,297 @@
1+
/*
2+
* SPDX-FileCopyrightText: 2026 M5Stack Technology CO LTD
3+
*
4+
* SPDX-License-Identifier: MIT
5+
*/
6+
7+
#include "M5Chain.h"
8+
9+
// Serial Pin Definitions / 串口引脚定义
10+
#define TXD_PIN (GPIO_NUM_32) /**< Transmit Pin / 发送引脚 */
11+
#define RXD_PIN (GPIO_NUM_33) /**< Receive Pin / 接收引脚 */
12+
13+
// Configuration Constants / 配置常量
14+
#define LOOP_DELAY_MS (500) /**< Loop delay in milliseconds / 循环延迟(毫秒) */
15+
16+
// Global Objects and Variables / 全局对象和变量
17+
Chain M5Chain; /**< M5Chain instance / M5Chain实例 */
18+
device_list_t *devices_list = NULL; /**< Device list pointer / 设备列表指针 */
19+
uint16_t device_nums = 0; /**< Device count / 设备数量 */
20+
uint8_t operation_status = 0; /**< Operation status / 操作状态 */
21+
chain_status_t chain_status = CHAIN_OK; /**< Chain status / 链路状态 */
22+
23+
// Function Declarations / 函数声明
24+
void printDeviceList(device_list_t *devices);
25+
void updateDeviceList();
26+
bool initializeAdcModes();
27+
bool readAndDisplayAdcValues();
28+
29+
void setup()
30+
{
31+
Serial.begin(115200);
32+
Serial.println("M5Chain Unit 8Servos2 Chain ADC Test");
33+
34+
// Initialize M5Chain communication / 初始化M5Chain通信
35+
M5Chain.begin(&Serial2, 115200, RXD_PIN, TXD_PIN);
36+
37+
// Update device list / 更新设备列表
38+
updateDeviceList();
39+
40+
// Initialize all ADC modes / 初始化所有ADC模式
41+
if (!initializeAdcModes()) {
42+
Serial.println("ADC mode initialization failed / ADC模式初始化失败");
43+
}
44+
}
45+
46+
void loop()
47+
{
48+
// Validate device list validity / 验证设备列表有效性
49+
if (!devices_list) {
50+
Serial.println("Device list is NULL / 设备列表为空");
51+
delay(LOOP_DELAY_MS);
52+
return;
53+
}
54+
55+
// Read and display ADC values / 读取并显示ADC值
56+
if (!readAndDisplayAdcValues()) {
57+
Serial.println("ADC reading or validation failed / ADC读取或验证失败");
58+
}
59+
60+
delay(LOOP_DELAY_MS);
61+
}
62+
63+
/**
64+
* @brief Initialize ADC modes for all 8Servos2 devices / 初始化所有8Servos2设备的ADC模式
65+
*
66+
* Set all channels to ADC mode and verify the operation / 将所有通道设置为ADC模式并验证操作
67+
*
68+
* @return true if successful / 成功返回true
69+
* @return false if failed / 失败返回false
70+
*/
71+
bool initializeAdcModes()
72+
{
73+
if (!devices_list) {
74+
Serial.println("Device list is NULL, cannot initialize / 设备列表为空,无法初始化");
75+
return false;
76+
}
77+
78+
// Prepare ADC mode configuration / 准备ADC模式配置
79+
user_gpio_mode_t mode[SERVOS2_GPIO_NUM_MAX];
80+
for (uint8_t i = 0; i < SERVOS2_GPIO_NUM_MAX; i++) {
81+
mode[i] = USER_GPIO_ADC_MODE;
82+
}
83+
84+
bool all_success = true;
85+
86+
// Iterate through all devices / 遍历所有设备
87+
for (uint8_t i = 0; i < devices_list->count; i++) {
88+
// Check device type / 检查设备类型
89+
if (devices_list->devices[i].device_type != UNIT_8SERVOS2_CHAIN_TYPE_CODE) {
90+
continue;
91+
}
92+
93+
uint8_t device_id = devices_list->devices[i].id;
94+
95+
// Write operation: Set ADC mode for all channels / 写入操作:设置所有通道ADC模式
96+
chain_status = M5Chain.setServosModeAll(device_id, mode, SERVOS2_GPIO_NUM_MAX, &operation_status);
97+
98+
// Validate write operation / 验证写入操作
99+
if (chain_status != CHAIN_OK) {
100+
Serial.printf(
101+
"Device ID[%d] set all channel ADC mode failed (communication error) / "
102+
"设备ID[%d]设置所有通道ADC模式失败(通信错误)\r\n",
103+
device_id, device_id);
104+
all_success = false;
105+
continue;
106+
}
107+
108+
if (operation_status != 1) {
109+
Serial.printf(
110+
"Device ID[%d] set all channel ADC mode failed (operation status error) / "
111+
"设备ID[%d]设置所有通道ADC模式失败(操作状态异常)\r\n",
112+
device_id, device_id);
113+
all_success = false;
114+
continue;
115+
}
116+
117+
// Read verification: Confirm mode was set correctly / 读取验证:确认模式设置正确
118+
user_gpio_mode_t read_mode[SERVOS2_GPIO_NUM_MAX];
119+
if (M5Chain.getServosModeAll(device_id, read_mode, SERVOS2_GPIO_NUM_MAX) != CHAIN_OK) {
120+
Serial.printf("Device ID[%d] read all channel ADC mode failed / 设备ID[%d]读取所有通道ADC模式失败\r\n",
121+
device_id, device_id);
122+
all_success = false;
123+
continue;
124+
}
125+
126+
// Verify data consistency for all channels / 验证所有通道的数据一致性
127+
uint8_t err_count = 0;
128+
for (uint8_t j = 0; j < SERVOS2_GPIO_NUM_MAX; j++) {
129+
if (read_mode[j] != USER_GPIO_ADC_MODE) {
130+
err_count++;
131+
Serial.printf(
132+
"Device ID[%d] channel %d mode verification failed: expected ADC_MODE, got %d / "
133+
"设备ID[%d]通道%d模式验证失败:期望ADC_MODE,实际%d\r\n",
134+
device_id, j, read_mode[j], device_id, j, read_mode[j]);
135+
}
136+
}
137+
138+
if (err_count == 0) {
139+
Serial.printf(
140+
"Device ID[%d] all channel ADC mode set and verified successfully / "
141+
"设备ID[%d]所有通道ADC模式设置并验证成功\r\n",
142+
device_id, device_id);
143+
} else {
144+
Serial.printf("Device ID[%d] has %d channels with incorrect mode / 设备ID[%d]有%d个通道模式不正确\r\n",
145+
device_id, err_count, device_id, err_count);
146+
all_success = false;
147+
}
148+
}
149+
150+
return all_success;
151+
}
152+
153+
/**
154+
* @brief Read and display ADC values from all channels / 读取并显示所有通道的ADC值
155+
*
156+
* Process: Verify mode -> Read ADC values -> Display values /
157+
* 流程:验证模式 -> 读取ADC值 -> 显示数值
158+
*
159+
* @return true if successful / 成功返回true
160+
* @return false if failed / 失败返回false
161+
*/
162+
bool readAndDisplayAdcValues()
163+
{
164+
bool all_success = true;
165+
166+
// Iterate through all devices / 遍历所有设备
167+
for (uint8_t i = 0; i < devices_list->count; i++) {
168+
// Check device type / 检查设备类型
169+
if (devices_list->devices[i].device_type != UNIT_8SERVOS2_CHAIN_TYPE_CODE) {
170+
continue;
171+
}
172+
173+
uint8_t device_id = devices_list->devices[i].id;
174+
user_gpio_mode_t mode[SERVOS2_GPIO_NUM_MAX];
175+
uint16_t adc_val[SERVOS2_GPIO_NUM_MAX];
176+
177+
// Step 1: Read and verify current mode / 步骤1:读取并验证当前模式
178+
if (M5Chain.getServosModeAll(device_id, mode, SERVOS2_GPIO_NUM_MAX) != CHAIN_OK) {
179+
Serial.printf(
180+
"Device ID[%d] get all channel ADC mode failed (communication error) / "
181+
"设备ID[%d]获取所有通道ADC模式失败(通信错误)\r\n",
182+
device_id, device_id);
183+
all_success = false;
184+
continue;
185+
}
186+
187+
// Verify all channels are in ADC mode / 验证所有通道都处于ADC模式
188+
uint8_t err_count = 0;
189+
for (uint8_t j = 0; j < SERVOS2_GPIO_NUM_MAX; j++) {
190+
if (mode[j] != USER_GPIO_ADC_MODE) {
191+
err_count++;
192+
}
193+
}
194+
195+
if (err_count != 0) {
196+
Serial.printf("Device ID[%d] has %d channels not in ADC mode / 设备ID[%d]有%d个通道不在ADC模式\r\n",
197+
device_id, err_count, device_id, err_count);
198+
all_success = false;
199+
continue;
200+
}
201+
202+
// Step 2: Read ADC values from all channels / 步骤2:读取所有通道的ADC值
203+
if (M5Chain.getServosAdcValueAll(device_id, adc_val, SERVOS2_GPIO_NUM_MAX) != CHAIN_OK) {
204+
Serial.printf(
205+
"Device ID[%d] get all channel ADC value failed (communication error) / "
206+
"设备ID[%d]获取所有通道ADC值失败(通信错误)\r\n",
207+
device_id, device_id);
208+
all_success = false;
209+
continue;
210+
}
211+
212+
// Step 3: Display ADC values for all channels / 步骤3:显示所有通道的ADC值
213+
Serial.printf("=== Device ID[%d] ADC Values / 设备ID[%d] ADC值 ===\r\n", device_id, device_id);
214+
for (uint8_t j = 0; j < SERVOS2_GPIO_NUM_MAX; j++) {
215+
Serial.printf(" Channel %d: %d (0x%04X) / 通道 %d: %d (0x%04X)\r\n", j, adc_val[j], adc_val[j], j,
216+
adc_val[j], adc_val[j]);
217+
}
218+
Serial.println("==========================================");
219+
}
220+
221+
return all_success;
222+
}
223+
224+
/**
225+
* @brief Print device list information / 打印设备列表信息
226+
*
227+
* @param devices Device list pointer / 设备列表指针
228+
*/
229+
void printDeviceList(device_list_t *devices)
230+
{
231+
if (devices == NULL) {
232+
Serial.println("Device list is NULL / 设备列表为空");
233+
return;
234+
}
235+
236+
Serial.print("Device count / 设备数量: ");
237+
Serial.println(devices->count);
238+
239+
for (uint8_t i = 0; i < devices->count; i++) {
240+
Serial.printf("Device #%d - ID: %d, Type: 0x%02X / 设备 #%d - ID: %d, 类型: 0x%02X\r\n", i,
241+
devices->devices[i].id, devices->devices[i].device_type, i, devices->devices[i].id,
242+
devices->devices[i].device_type);
243+
}
244+
}
245+
246+
/**
247+
* @brief Update device list / 更新设备列表
248+
*
249+
* Detect connected devices and retrieve device information / 检测连接的设备并获取设备信息
250+
*/
251+
void updateDeviceList()
252+
{
253+
// Check device connection status / 检查设备连接状态
254+
if (!M5Chain.isDeviceConnected()) {
255+
Serial.println("Devices not connected / 设备未连接");
256+
return;
257+
}
258+
259+
Serial.println("Devices connected / 设备已连接");
260+
261+
// Get device count / 获取设备数量
262+
chain_status = M5Chain.getDeviceNum(&device_nums);
263+
if (chain_status != CHAIN_OK) {
264+
Serial.printf("Get device count failed, error code: %d / 获取设备数量失败,错误码: %d\r\n", chain_status,
265+
chain_status);
266+
return;
267+
}
268+
269+
// Allocate device list memory / 分配设备列表内存
270+
devices_list = (device_list_t *)malloc(sizeof(device_list_t));
271+
if (!devices_list) {
272+
Serial.println("Memory allocation failed / 内存分配失败");
273+
return;
274+
}
275+
276+
devices_list->count = device_nums;
277+
devices_list->devices = (device_info_t *)malloc(sizeof(device_info_t) * device_nums);
278+
279+
if (!devices_list->devices) {
280+
Serial.println("Device info memory allocation failed / 设备信息内存分配失败");
281+
free(devices_list);
282+
devices_list = NULL;
283+
return;
284+
}
285+
286+
// Get device list / 获取设备列表
287+
if (M5Chain.getDeviceList(devices_list)) {
288+
Serial.println("Get device list success / 获取设备列表成功");
289+
printDeviceList(devices_list);
290+
} else {
291+
Serial.println("Get device list failed / 获取设备列表失败");
292+
// Clean up allocated memory / 清理已分配的内存
293+
free(devices_list->devices);
294+
free(devices_list);
295+
devices_list = NULL;
296+
}
297+
}

0 commit comments

Comments
 (0)