Welcome to STM32-BoardCar repository
13.K230 road sign indication action (voice)
k230 road sign indication action
k230 road sign indication action1. Software-hardware environment2. Brief principle1. Hardware schematic2. Physical connection diagram3. Communication protocol3. Partial code analysis4. Experimental phenomenonRoad sign image
This tutorial is a comprehensive experiment combining multiple peripherals. You can first understand a single peripheral and then conduct this experiment.
1. Software-hardware environment
STM32F103CubeIDE
STM32 robot development board
k230 module: external
Type-C data cable or ST-Link
Download or simulate the development board
2. Brief principle
1. Hardware schematic

2. Physical connection diagram
Motor1 -> upper left motor (left front wheel of the car) Motor3 -> upper right motor (right front wheel of the car)
Motor2 -> lower left motor (left rear wheel of the car) Motor4 -> Lower right motor (right rear wheel of the car)
Motor wiring

Voice module wiring
| Intelligent voice interaction module | STM32 |
|---|---|
| 5V | 5V |
| GND | GND |
| TX1 | PC11 |
| RX1 | PC10 |

K230 wiring (Note: The wiring in the figure below is for position reference only. We are equipped with K230 dual-head PH2.0 4Pin all-black wire, with fool-proof design, no need to worry about wiring problems)

3. Communication protocol
| Experimental routine | Start symbol | msg | End symbol |
|---|---|---|---|
| Road sign recognition | $ | # |
msg: go_straight, turn_right, hoking
MCU part:
Receive the data sent by k230 through the serial port, and parse and process each byte of the data. After we extract the valid data into the array. Process the returned signpost information, and then the MCU takes corresponding actions according to the parsed signpost
3. Partial code analysis
yb_protocol.c
x//* * @Brief: 数据分析 Data analysis * @Note: 解析传入的数据帧,提取字段值并处理 * Parse the incoming data frame, extract field values and process them * @Parm: 传入接受到的一个数据帧和长度 Pass in a received data frame and length * @Retval: 无返回值 No return value */void Pto_Data_Parse(uint8_t *data_buf, uint8_t num){ uint8_t pto_head = data_buf[0]; uint8_t pto_tail = data_buf[num-1]; // 验证帧头和帧尾 Verify frame header and footer if (!(pto_head == PTO_HEAD && pto_tail == PTO_TAIL)) { return; }
uint8_t data_index = 1; uint8_t field_index[PTO_BUF_LEN_MAX] = {0}; int i = 0;
// 处理分隔符,将逗号替换为字符串结束符,记录字段位置 // Process delimiters, replace commas with string terminators and record field positions for (i = 1; i < num-1; i++) { if (data_buf[i] == ',') { data_buf[i] = 0; field_index[data_index] = i; data_index++; } }
// 处理无分隔符的情况,整个数据作为标签处理 // Handle the case without delimiters, treat the entire data as a label if (data_index == 1) { uint8_t len = num - 2; memcpy(lubiao, (char*)data_buf+1, len); lubiao[len] = '\0'; // 确保字符串以'\0'结尾 Ensure the string ends with '\0' } else { // 处理多字段情况 Process multiple fields for (i = 0; i < data_index; i++) { uint8_t start = field_index[i] + 1; uint8_t len; if (i == data_index - 1) { // 最后一个字段,长度计算到帧尾前 // Last field, length calculated up to before the frame footer len = (num - 1) - start; } else { // 中间字段,长度为下一个分隔符位置减去当前起始位置 // Middle field, length is the next delimiter position minus the current start position len = field_index[i + 1] - start; } // 根据字段索引和总数处理不同类型的数据 // Process different types of data based on field index and total count if (i == 6 && data_index == 7) { memcpy(msg, (char*)data_buf + start, len); msg[len] = '\0'; // 确保字符串以'\0'结尾 Ensure the string ends with '\0' } else if (i == 2 && data_index == 3) { memcpy(game, (char*)data_buf + start, len); game[len] = '\0'; // 确保字符串以'\0'结尾 Ensure the string ends with '\0' } else { // 其他字段转换为整数值 // Convert other fields to integer values values[i] = Pto_Char_To_Int((char*)data_buf + start); } } // 帧长度验证,检查协议定义的长度与实际长度是否一致 // Frame length verification, check if the protocol-defined length matches the actual length uint8_t pto_len = values[0]; if (pto_len != num) { printf("pto_len error:%d , data_len:%d\n", pto_len, num); return; }
// 提取协议ID Extract protocol ID pto_id = values[1]; }
// 提取坐标和尺寸信息 Extract coordinate and dimension information int x = values[2]; int y = values[3]; int w = values[4]; int h = values[5];
// 打印坐标和尺寸信息 Print coordinate and dimension information printf("dmcode:x:%d, y:%d, w:%d, h:%d,\n", x, y, w, h);
// 打印游戏信息 Print game information printf("msg:%s\n", game);
// 调试信息已注释 Debug information commented out // printf("game:%d\n", pto_id); // printf("msg:%s\n", msg);}app_motor.c
xxxxxxxxxx//控制小车运行,输入的参数分别为x、y、z三个轴上的速度值//Control the movement of the car. The input parameters are the speed values on the x, y, and z axes.void wheel_Ctrl(int16_t V_x, int16_t V_y, int16_t V_z){ float robot_APB = Motion_Get_APB();// speed_lr = -V_y; speed_lr = 0; speed_fb = V_x; speed_spin = (V_z / 1000.0f) * robot_APB; if (V_x == 0 && V_y == 0 && V_z == 0) { Motion_Stop(STOP_BRAKE); return; }
speed_L1_setup = speed_fb + speed_lr - speed_spin; speed_L2_setup = speed_fb - speed_lr - speed_spin; speed_R1_setup = speed_fb - speed_lr + speed_spin; speed_R2_setup = speed_fb + speed_lr + speed_spin;
if (speed_L1_setup > 1000) speed_L1_setup = 1000; if (speed_L1_setup < -1000) speed_L1_setup = -1000; if (speed_L2_setup > 1000) speed_L2_setup = 1000; if (speed_L2_setup < -1000) speed_L2_setup = -1000; if (speed_R1_setup > 1000) speed_R1_setup = 1000; if (speed_R1_setup < -1000) speed_R1_setup = -1000; if (speed_R2_setup > 1000) speed_R2_setup = 1000; if (speed_R2_setup < -1000) speed_R2_setup = -1000;
Motion_Set_Speed(speed_L1_setup, speed_L2_setup, speed_R1_setup, speed_R2_setup);}app_irtracking.c
xxxxxxxxxx// 路标逻辑控制 - Road Sign Logic Controlvoid Car_lubiao(void){ // 蜂鸣器鸣笛 - Buzzer Honking if (strcmp("honking", lubiao) == 0 ) { Set_Buzzer(1); // 开启蜂鸣器 - Turn on buzzer HAL_Delay(500); // 延时500毫秒 - Delay 500ms Set_Buzzer(0); // 关闭蜂鸣器 - Turn off buzzer } // 直行 - Go Straight else if (strcmp("go_straight", lubiao) == 0 ) { // 小车前进 - Car moves forward Motion_Set_Speed(250,250,250,250); HAL_Delay(1000); // 延时1秒 - Delay 1s HAL_Delay(1000); // 延时1秒 - Delay 1s wheel_State(0,0); // 停止车轮 - Stop wheels } // 右转 - Turn Right else if (strcmp("turn_right", lubiao) == 0 ) { Motion_Set_Speed(500,500,0,0); // 准备右转 - Prepare right turn HAL_Delay(1000); // 延时1秒 - Delay 1s Motion_Set_Speed(250,250,250,250);// 右转后前进 - Move forward after turning HAL_Delay(1000); // 延时1秒 - Delay 1s wheel_State(0,0); // 停止车轮 - Stop wheels }}4. Experimental phenomenon
Turn on the power switch, wait for the system to initialize, the screen will display the camera image, start to recognize road signs, and make corresponding actions. Note: Connect our AI voice interaction integration module and then there will be voice broadcast after recognizing the road sign! Users who have not purchased the voice module do not have to worry. When the voice module is not connected, K230 can still implement this case, but there is no voice broadcast function.

Voice module command words
| Command words | Function type | Broadcast sentence | Broadcast mode | Send protocol | Receive protocol |
|---|---|---|---|---|---|
| RIGHT-TURN-SIGN-DETECTED | Command words | Recognize the right turn sign the car turns right | By | AA 55 FF 61 FB | AA 55 FF 61 FB |
| HORN-SIGN-DETECTED | Command words | Recognize the horn sign the car honks | By | AA 55 FF 62 FB | AA 55 FF 62 FB |
| FORWARD-SIGN-DETECTED | Command words | Recognize the forward sign the car moves forward | By | AA 55 FF 63 FB | AA 55 FF 63 FB |
Voice module firmware burning
xBurning the CI1302_EN_ SingleMic_V00916_UART1_115200_2M.bin file we provide can realize all cases related to the intelligent voice interaction module of this car. Only one burning is required. For the burning method, see [Voice Interaction Control Tutorial] [Section 6] Voice Module Firmware Burning
K230 Code Burning
Required tools: K230, SD card, CanMV IDE K230
We find the detct_guide.py file in the project folder, then drag it to CanMV IDE K230, and then choose to save the opened script as main.py to CanMV

Road sign image
go_straight:

turn_right:

honking:
