编程技术分享

分享编程知识,探讨技术创新

0%

简介:本项目由立创EDA的星火计划支持,ESP32-WROVER-E为主控MCU,履足式机器人拥有两种行进模式:四足行进、履带行进,四足形态下共拥8个DOF,足端融入了履带机构,由4个直流电机驱动。

好的,作为一名高级嵌入式软件开发工程师,我将为您详细阐述针对这款履足式机器人的嵌入式软件架构设计,并提供具体的C代码实现示例。本项目旨在构建一个可靠、高效、可扩展的嵌入式系统平台,用于控制这款拥有两种行进模式的机器人。
关注微信公众号,提前获取相关推文

1. 需求分析

在项目初期,需求分析至关重要,它将指导后续的架构设计和代码实现。基于项目简介和图片,我们可以提炼出以下关键需求:

  • 主控芯片: ESP32-WROVER-E (具备Wi-Fi/蓝牙功能,处理能力较强,适合复杂控制和通信应用)。
  • 机器人类型: 履足式机器人,具备四足和履带两种行进模式。
  • 运动机构:
    • 四足模式:8个自由度 (DOF),推测每个腿部有两个自由度,可能控制髋关节和膝关节的运动。
    • 履带模式:4个直流电机驱动履带机构,用于地面移动。
  • 驱动方式: 直流电机驱动,需要PWM控制和方向控制。
  • 控制目标: 实现机器人的运动控制,包括模式切换、速度控制、姿态控制(可能需要)。
  • 通信需求: 可能需要远程控制接口 (Wi-Fi 或 蓝牙),用于指令下发和数据监控。
  • 扩展性需求: 系统应易于扩展,例如增加传感器 (IMU, 距离传感器等)、执行器或其他功能模块。
  • 可靠性需求: 系统必须稳定可靠,能够在各种工况下正常运行,并具备一定的容错能力。
  • 高效性需求: 代码执行效率要高,保证实时性控制,并尽可能降低功耗。
  • 维护升级需求: 系统架构应易于维护和升级,方便后续的功能迭代和bug修复。

2. 系统架构设计

为了满足以上需求,并构建可靠、高效、可扩展的系统平台,我推荐采用分层模块化的软件架构。这种架构将系统划分为不同的层次和模块,每个层次和模块负责特定的功能,层与层之间通过清晰的接口进行通信。

2.1 架构层次

我们从下往上将系统分为以下几个层次:

  • 硬件抽象层 (Hardware Abstraction Layer, HAL): 这是最底层,直接与ESP32硬件交互。HAL层封装了ESP32芯片的底层驱动,向上层提供统一的硬件访问接口,屏蔽硬件差异性。例如,GPIO、PWM、定时器、UART、SPI、I2C等外设的驱动都在HAL层实现。
  • 设备驱动层 (Device Driver Layer): 基于HAL层,为具体的硬件设备 (例如直流电机驱动芯片、编码器、传感器等) 提供驱动程序。设备驱动层负责设备的初始化、配置、数据读取和控制命令发送。
  • 核心控制层 (Core Control Layer): 这是系统的核心层,负责实现机器人的运动控制和状态管理。核心控制层包含以下关键模块:
    • 电机控制模块 (Motor Control Module): 负责直流电机的PWM控制、速度控制、位置控制 (如果需要)、电流监控 (可选)。
    • 运动学模块 (Kinematics Module): 在四足模式下,负责机器人的运动学计算,包括正运动学和逆运动学,用于控制腿部关节的运动,实现期望的机器人姿态和步态。
    • 步态规划模块 (Gait Planning Module): 在四足模式下,负责生成机器人的行走步态,例如小跑、慢走、转弯等。
    • 履带控制模块 (Track Control Module): 在履带模式下,负责控制履带电机的速度和方向,实现机器人的移动。
    • 模式管理模块 (Mode Management Module): 负责机器人行进模式的切换 (四足/履带),以及不同模式下控制策略的切换。
    • 状态机模块 (State Machine Module): 管理机器人的整体状态,例如待机状态、四足运动状态、履带运动状态、错误状态等,并处理状态之间的切换。
    • 传感器数据处理模块 (Sensor Data Processing Module): 如果机器人配备了传感器 (例如IMU),该模块负责传感器数据的读取、滤波、融合和处理,为上层控制提供环境感知信息和姿态估计。
  • 应用层 (Application Layer): 这是最高层,负责实现用户交互和高级功能。应用层包含以下模块:
    • 命令解析模块 (Command Parsing Module): 解析来自上位机 (例如手机App、PC控制软件) 的控制指令,例如运动指令、模式切换指令、参数配置指令等。
    • 通信模块 (Communication Module): 负责与上位机进行通信,可以使用Wi-Fi、蓝牙或其他通信协议。
    • 用户界面模块 (User Interface Module): 如果需要,可以实现本地用户界面,例如通过OLED屏幕或LED灯显示机器人状态。
    • 任务调度模块 (Task Scheduling Module): 使用FreeRTOS等多任务操作系统,管理不同模块的运行,实现并发执行和实时控制。

2.2 模块化设计

在每个层次内部,我们进一步采用模块化设计,将功能分解为更小的、独立的模块。模块之间通过定义清晰的接口进行交互,降低模块之间的耦合度,提高代码的可维护性和可复用性。

2.3 数据流

数据流在系统中流动,主要包括:

  • 传感器数据: 传感器数据从硬件层经过设备驱动层、传感器数据处理模块,最终传递到核心控制层和应用层,用于环境感知和状态估计。
  • 控制指令: 控制指令从应用层 (例如命令解析模块) 传递到核心控制层,由核心控制层分解为具体的电机控制信号。
  • 电机控制信号: 电机控制信号从核心控制层经过电机控制模块、设备驱动层、HAL层,最终作用于直流电机,驱动机器人运动。
  • 状态信息: 系统状态信息 (例如机器人当前模式、电机状态、传感器数据) 可以从核心控制层传递到应用层,用于用户界面显示或上传到上位机进行监控。

3. 具体C代码实现 (部分示例)

以下提供一些关键模块的C代码实现示例,由于代码量庞大,这里只展示核心部分,并且为了清晰易懂,代码进行了简化。实际项目中需要根据具体硬件和功能进行完善。

(1) HAL层 (示例 - GPIO 和 PWM)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
// hal_gpio.h
#ifndef HAL_GPIO_H
#define HAL_GPIO_H

#include "esp_err.h"
#include "driver/gpio.h"

typedef enum {
GPIO_LEVEL_LOW = 0,
GPIO_LEVEL_HIGH = 1
} hal_gpio_level_t;

typedef enum {
GPIO_MODE_INPUT,
GPIO_MODE_OUTPUT,
GPIO_MODE_INPUT_OUTPUT
} hal_gpio_mode_t;

esp_err_t hal_gpio_init(gpio_num_t gpio_num, hal_gpio_mode_t mode);
esp_err_t hal_gpio_set_level(gpio_num_t gpio_num, hal_gpio_level_t level);
hal_gpio_level_t hal_gpio_get_level(gpio_num_t gpio_num);

#endif // HAL_GPIO_H

// hal_gpio.c
#include "hal_gpio.h"

esp_err_t hal_gpio_init(gpio_num_t gpio_num, hal_gpio_mode_t mode) {
gpio_config_t io_conf;
io_conf.intr_type = GPIO_INTR_DISABLE; // Disable interrupt
io_conf.pin_bit_mask = (1ULL << gpio_num); // Bit mask of the pins
if (mode == GPIO_MODE_INPUT) {
io_conf.mode = GPIO_MODE_INPUT;
io_conf.pull_down_en = 0;
io_conf.pull_up_en = 0;
} else if (mode == GPIO_MODE_OUTPUT) {
io_conf.mode = GPIO_MODE_OUTPUT;
io_conf.pull_down_en = 0;
io_conf.pull_up_en = 0;
} else if (mode == GPIO_MODE_INPUT_OUTPUT) {
io_conf.mode = GPIO_MODE_INPUT_OUTPUT;
io_conf.pull_down_en = 0;
io_conf.pull_up_en = 0;
} else {
return ESP_FAIL; // Invalid mode
}
return gpio_config(&io_conf);
}

esp_err_t hal_gpio_set_level(gpio_num_t gpio_num, hal_gpio_level_t level) {
return gpio_set_level(gpio_num, level);
}

hal_gpio_level_t hal_gpio_get_level(gpio_num_t gpio_num) {
return gpio_get_level(gpio_num);
}


// hal_pwm.h
#ifndef HAL_PWM_H
#define HAL_PWM_H

#include "esp_err.h"
#include "driver/ledc.h"

typedef enum {
PWM_TIMER_0,
PWM_TIMER_1,
PWM_TIMER_2,
PWM_TIMER_3
} hal_pwm_timer_t;

typedef enum {
PWM_CHANNEL_0,
PWM_CHANNEL_1,
PWM_CHANNEL_2,
PWM_CHANNEL_3,
PWM_CHANNEL_4,
PWM_CHANNEL_5,
PWM_CHANNEL_6,
PWM_CHANNEL_7
} hal_pwm_channel_t;

esp_err_t hal_pwm_init(hal_pwm_timer_t timer, hal_pwm_channel_t channel, gpio_num_t gpio_num, uint32_t frequency, uint32_t duty_resolution);
esp_err_t hal_pwm_set_duty(hal_pwm_channel_t channel, uint32_t duty);
esp_err_t hal_pwm_update_duty(hal_pwm_channel_t channel);

#endif // HAL_PWM_H

// hal_pwm.c
#include "hal_pwm.h"

esp_err_t hal_pwm_init(hal_pwm_timer_t timer, hal_pwm_channel_t channel, gpio_num_t gpio_num, uint32_t frequency, uint32_t duty_resolution) {
ledc_timer_config_t timer_conf = {
.speed_mode = LEDC_HIGH_SPEED_MODE,
.duty_resolution = duty_resolution,
.timer_num = timer,
.freq_hz = frequency,
.clk_cfg = LEDC_AUTO_CLK,
};
esp_err_t ret = ledc_timer_config(&timer_conf);
if (ret != ESP_OK) return ret;

ledc_channel_config_t channel_conf = {
.speed_mode = LEDC_HIGH_SPEED_MODE,
.channel = channel,
.timer_sel = timer,
.intr_mask = 0,
.duty = 0, // Initial duty cycle
.gpio_num = gpio_num,
.hpoint = 0,
};
return ledc_channel_config(&channel_conf);
}

esp_err_t hal_pwm_set_duty(hal_pwm_channel_t channel, uint32_t duty) {
return ledc_set_duty(LEDC_HIGH_SPEED_MODE, channel, duty);
}

esp_err_t hal_pwm_update_duty(hal_pwm_channel_t channel) {
return ledc_update_duty(LEDC_HIGH_SPEED_MODE, channel);
}

(2) 设备驱动层 (示例 - 直流电机驱动)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
// motor_driver.h
#ifndef MOTOR_DRIVER_H
#define MOTOR_DRIVER_H

#include "esp_err.h"
#include "hal_gpio.h"
#include "hal_pwm.h"

typedef struct {
gpio_num_t forward_pin;
gpio_num_t backward_pin;
hal_pwm_channel_t pwm_channel;
} motor_config_t;

typedef struct {
motor_config_t config;
uint32_t speed; // 0 - 100%
int8_t direction; // -1: backward, 0: stop, 1: forward
} motor_t;

esp_err_t motor_init(motor_t *motor, motor_config_t config);
esp_err_t motor_set_speed(motor_t *motor, uint32_t speed);
esp_err_t motor_set_direction(motor_t *motor, int8_t direction);
esp_err_t motor_stop(motor_t *motor);

#endif // MOTOR_DRIVER_H

// motor_driver.c
#include "motor_driver.h"

esp_err_t motor_init(motor_t *motor, motor_config_t config) {
motor->config = config;
motor->speed = 0;
motor->direction = 0;

// Initialize GPIO pins for direction control
ESP_ERROR_CHECK(hal_gpio_init(config.forward_pin, GPIO_MODE_OUTPUT));
ESP_ERROR_CHECK(hal_gpio_init(config.backward_pin, GPIO_MODE_OUTPUT));

// Initialize PWM channel for speed control
ESP_ERROR_CHECK(hal_pwm_init(PWM_TIMER_0, config.pwm_channel, -1, 1000, LEDC_TIMER_10_BIT)); // 1kHz PWM, 10-bit resolution

return motor_stop(motor); // Stop motor initially
}

esp_err_t motor_set_speed(motor_t *motor, uint32_t speed) {
if (speed > 100) speed = 100; // Limit speed to 100%
motor->speed = speed;
uint32_t duty_cycle = (speed * 1023) / 100; // 10-bit resolution (1023 max)
ESP_ERROR_CHECK(hal_pwm_set_duty(motor->config.pwm_channel, duty_cycle));
ESP_ERROR_CHECK(hal_pwm_update_duty(motor->config.pwm_channel));
return ESP_OK;
}

esp_err_t motor_set_direction(motor_t *motor, int8_t direction) {
motor->direction = direction;
if (direction > 0) { // Forward
ESP_ERROR_CHECK(hal_gpio_set_level(motor->config.forward_pin, GPIO_LEVEL_HIGH));
ESP_ERROR_CHECK(hal_gpio_set_level(motor->config.backward_pin, GPIO_LEVEL_LOW));
} else if (direction < 0) { // Backward
ESP_ERROR_CHECK(hal_gpio_set_level(motor->config.forward_pin, GPIO_LEVEL_LOW));
ESP_ERROR_CHECK(hal_gpio_set_level(motor->config.backward_pin, GPIO_LEVEL_HIGH));
} else { // Stop
return motor_stop(motor);
}
return ESP_OK;
}

esp_err_t motor_stop(motor_t *motor) {
motor->direction = 0;
motor->speed = 0;
ESP_ERROR_CHECK(hal_gpio_set_level(motor->config.forward_pin, GPIO_LEVEL_LOW));
ESP_ERROR_CHECK(hal_gpio_set_level(motor->config.backward_pin, GPIO_LEVEL_LOW));
ESP_ERROR_CHECK(hal_pwm_set_duty(motor->config.pwm_channel, 0));
ESP_ERROR_CHECK(hal_pwm_update_duty(motor->config.pwm_channel));
return ESP_OK;
}

(3) 核心控制层 (示例 - 电机控制模块 和 模式管理模块)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
// motor_control_module.h
#ifndef MOTOR_CONTROL_MODULE_H
#define MOTOR_CONTROL_MODULE_H

#include "motor_driver.h"

#define NUM_MOTORS 4 // Assuming 4 track motors

typedef struct {
motor_t motors[NUM_MOTORS];
} motor_controller_t;

esp_err_t motor_controller_init(motor_controller_t *controller);
esp_err_t motor_controller_set_speed(motor_controller_t *controller, uint8_t motor_index, uint32_t speed);
esp_err_t motor_controller_set_direction(motor_controller_t *controller, uint8_t motor_index, int8_t direction);
esp_err_t motor_controller_stop_all(motor_controller_t *controller);

#endif // MOTOR_CONTROL_MODULE_H

// motor_control_module.c
#include "motor_control_module.h"

esp_err_t motor_controller_init(motor_controller_t *controller) {
// Define motor configurations (replace with your actual pin assignments)
motor_config_t motor_configs[NUM_MOTORS] = {
{{GPIO_NUM_25, GPIO_NUM_26, PWM_CHANNEL_0}}, // Motor 0
{{GPIO_NUM_27, GPIO_NUM_14, PWM_CHANNEL_1}}, // Motor 1
{{GPIO_NUM_12, GPIO_NUM_13, PWM_CHANNEL_2}}, // Motor 2
{{GPIO_NUM_15, GPIO_NUM_2, PWM_CHANNEL_3}} // Motor 3
};

for (int i = 0; i < NUM_MOTORS; i++) {
ESP_ERROR_CHECK(motor_init(&controller->motors[i], motor_configs[i]));
}
return ESP_OK;
}

esp_err_t motor_controller_set_speed(motor_controller_t *controller, uint8_t motor_index, uint32_t speed) {
if (motor_index >= NUM_MOTORS) return ESP_ERR_INVALID_ARG;
return motor_set_speed(&controller->motors[motor_index], speed);
}

esp_err_t motor_controller_set_direction(motor_controller_t *controller, uint8_t motor_index, int8_t direction) {
if (motor_index >= NUM_MOTORS) return ESP_ERR_INVALID_ARG;
return motor_set_direction(&controller->motors[motor_index], direction);
}

esp_err_t motor_controller_stop_all(motor_controller_t *controller) {
for (int i = 0; i < NUM_MOTORS; i++) {
ESP_ERROR_CHECK(motor_stop(&controller->motors[i]));
}
return ESP_OK;
}


// mode_management_module.h
#ifndef MODE_MANAGEMENT_MODULE_H
#define MODE_MANAGEMENT_MODULE_H

typedef enum {
MODE_IDLE,
MODE_QUADRUPED,
MODE_TRACKED,
MODE_ERROR
} robot_mode_t;

typedef void (*mode_callback_t)(void); // Function pointer for mode actions

typedef struct {
robot_mode_t current_mode;
mode_callback_t mode_enter_callbacks[MODE_ERROR + 1]; // Callbacks for mode entry
mode_callback_t mode_exit_callbacks[MODE_ERROR + 1]; // Callbacks for mode exit
} mode_manager_t;

esp_err_t mode_manager_init(mode_manager_t *manager);
esp_err_t mode_manager_set_mode(mode_manager_t *manager, robot_mode_t new_mode);
robot_mode_t mode_manager_get_mode(mode_manager_t *manager);
esp_err_t mode_manager_register_callback(mode_manager_t *manager, robot_mode_t mode, bool is_enter, mode_callback_t callback);

#endif // MODE_MANAGEMENT_MODULE_H

// mode_management_module.c
#include "mode_management_module.h"
#include "esp_log.h"

static const char *TAG = "MODE_MANAGER";

esp_err_t mode_manager_init(mode_manager_t *manager) {
manager->current_mode = MODE_IDLE;
for (int i = 0; i <= MODE_ERROR; i++) {
manager->mode_enter_callbacks[i] = NULL;
manager->mode_exit_callbacks[i] = NULL;
}
return ESP_OK;
}

esp_err_t mode_manager_set_mode(mode_manager_t *manager, robot_mode_t new_mode) {
if (new_mode > MODE_ERROR) return ESP_ERR_INVALID_ARG;
if (manager->current_mode == new_mode) return ESP_OK; // Already in this mode

ESP_LOGI(TAG, "Switching mode from %d to %d", manager->current_mode, new_mode);

// Execute exit callback for current mode
if (manager->mode_exit_callbacks[manager->current_mode] != NULL) {
manager->mode_exit_callbacks[manager->current_mode]();
}

robot_mode_t old_mode = manager->current_mode;
manager->current_mode = new_mode;

// Execute enter callback for new mode
if (manager->mode_enter_callbacks[new_mode] != NULL) {
manager->mode_enter_callbacks[new_mode]();
}

// Mode switch logic (e.g., enabling/disabling specific modules based on mode)
switch (new_mode) {
case MODE_IDLE:
ESP_LOGI(TAG, "Entered IDLE mode");
// Stop all motors, disable control loops etc.
break;
case MODE_QUADRUPED:
ESP_LOGI(TAG, "Entered QUADRUPED mode");
// Initialize quadruped control modules, kinematics, gait planner
break;
case MODE_TRACKED:
ESP_LOGI(TAG, "Entered TRACKED mode");
// Initialize tracked control modules, disable quadruped modules
break;
case MODE_ERROR:
ESP_LOGE(TAG, "Entered ERROR mode");
// Handle error state, stop all critical operations
break;
default:
ESP_LOGW(TAG, "Unknown mode: %d", new_mode);
manager->current_mode = MODE_IDLE; // Fallback to IDLE
return ESP_ERR_INVALID_STATE;
}
return ESP_OK;
}

robot_mode_t mode_manager_get_mode(mode_manager_t *manager) {
return manager->current_mode;
}

esp_err_t mode_manager_register_callback(mode_manager_t *manager, robot_mode_t mode, bool is_enter, mode_callback_t callback) {
if (mode > MODE_ERROR) return ESP_ERR_INVALID_ARG;
if (is_enter) {
manager->mode_enter_callbacks[mode] = callback;
} else {
manager->mode_exit_callbacks[mode] = callback;
}
return ESP_OK;
}

(4) 应用层 (示例 - main.c 和 命令处理)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
// main.c
#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_log.h"
#include "motor_control_module.h"
#include "mode_management_module.h"

static const char *TAG = "MAIN";

motor_controller_t motor_controller;
mode_manager_t mode_manager;

// Callback functions for mode transitions (example)
void enter_quadruped_mode(void) {
ESP_LOGI(TAG, "Entering quadruped mode actions...");
// Initialize quadruped specific modules, kinematics, gait planner etc.
}

void exit_quadruped_mode(void) {
ESP_LOGI(TAG, "Exiting quadruped mode actions...");
// De-initialize quadruped specific modules, stop quadruped motion etc.
}

void enter_tracked_mode(void) {
ESP_LOGI(TAG, "Entering tracked mode actions...");
// Initialize tracked specific modules, track control etc.
}

void exit_tracked_mode(void) {
ESP_LOGI(TAG, "Exiting tracked mode actions...");
// De-initialize tracked specific modules, stop track motion etc.
}

void app_main(void) {
ESP_LOGI(TAG, "Robot System Startup...");

// Initialize motor controller
ESP_ERROR_CHECK(motor_controller_init(&motor_controller));

// Initialize mode manager
ESP_ERROR_CHECK(mode_manager_init(&mode_manager));

// Register mode transition callbacks
ESP_ERROR_CHECK(mode_manager_register_callback(&mode_manager, MODE_QUADRUPED, true, enter_quadruped_mode));
ESP_ERROR_CHECK(mode_manager_register_callback(&mode_manager, MODE_QUADRUPED, false, exit_quadruped_mode));
ESP_ERROR_CHECK(mode_manager_register_callback(&mode_manager, MODE_TRACKED, true, enter_tracked_mode));
ESP_ERROR_CHECK(mode_manager_register_callback(&mode_manager, MODE_TRACKED, false, exit_tracked_mode));

// Set initial mode (e.g., IDLE)
ESP_ERROR_CHECK(mode_manager_set_mode(&mode_manager, MODE_IDLE));

// Example command processing loop (replace with your actual command source and parsing)
char command[32];
while (1) {
printf("Enter command (q/t/s for quadruped/tracked/stop, or 'speed m d s' for motor control): ");
if (fgets(command, sizeof(command), stdin) != NULL) {
if (command[0] == 'q') {
ESP_ERROR_CHECK(mode_manager_set_mode(&mode_manager, MODE_QUADRUPED));
} else if (command[0] == 't') {
ESP_ERROR_CHECK(mode_manager_set_mode(&mode_manager, MODE_TRACKED));
} else if (command[0] == 's') {
ESP_ERROR_CHECK(mode_manager_set_mode(&mode_manager, MODE_IDLE));
ESP_ERROR_CHECK(motor_controller_stop_all(&motor_controller));
} else if (strncmp(command, "speed", 5) == 0) {
int motor_index, direction, speed;
if (sscanf(command, "speed %d %d %d", &motor_index, &direction, &speed) == 3) {
if (motor_index >= 0 && motor_index < NUM_MOTORS) {
ESP_ERROR_CHECK(motor_controller_set_speed(&motor_controller, motor_index, speed));
ESP_ERROR_CHECK(motor_controller_set_direction(&motor_controller, motor_index, direction));
ESP_LOGI(TAG, "Set motor %d speed to %d, direction to %d", motor_index, speed, direction);
} else {
ESP_LOGE(TAG, "Invalid motor index");
}
} else {
ESP_LOGE(TAG, "Invalid speed command format");
}
} else {
ESP_LOGW(TAG, "Unknown command");
}
}
vTaskDelay(pdMS_TO_TICKS(100)); // Small delay
}
}

4. 项目中采用的各种技术和方法 (实践验证)

  • 分层模块化架构: 已被广泛应用于嵌入式系统开发,实践证明可以提高代码的可维护性、可复用性和可扩展性。
  • 硬件抽象层 (HAL): 是嵌入式软件设计的标准做法,可以屏蔽硬件差异,方便代码移植和硬件更换。
  • 设备驱动层: 针对具体硬件设备编写驱动程序,是嵌入式系统开发的基础。
  • 状态机: 状态机模型非常适合管理复杂系统的状态切换和行为控制,尤其是在机器人控制领域。
  • FreeRTOS (或类似的RTOS): 使用实时操作系统可以实现多任务并发执行,提高系统的实时性和响应性,对于复杂的机器人控制系统至关重要。
  • PID控制 (电机控制模块可扩展): PID控制算法是经典的控制算法,广泛应用于电机速度和位置控制,能够实现精确稳定的控制效果。 (代码示例中未包含PID,但实际项目电机控制模块可以扩展PID控制功能)
  • 运动学和步态规划 (四足模式): 运动学和步态规划是四足机器人控制的核心技术,需要根据具体的机器人结构和运动需求进行设计和实现。 (代码示例中未包含运动学和步态规划,但这是四足模式下关键的模块)
  • 通信协议 (例如 UART, Wi-Fi, Bluetooth): 选择合适的通信协议,实现上位机与机器人之间的指令传输和数据交换,是远程控制和监控的基础。
  • 代码版本控制 (Git): 使用Git进行代码版本控制,可以方便团队协作、代码管理和版本回溯。
  • 单元测试和集成测试: 编写单元测试用例和集成测试用例,对代码进行充分的测试和验证,保证代码质量和系统可靠性。
  • 代码审查: 进行代码审查,可以及早发现代码中的潜在问题,提高代码质量和团队协作效率。
  • 日志系统 (ESP_LOG): 使用日志系统可以方便调试和问题排查,记录系统运行状态和错误信息。

5. 测试验证和维护升级

  • 测试验证:
    • 单元测试: 针对每个模块编写单元测试用例,例如HAL层GPIO和PWM的测试,电机驱动模块的测试,确保每个模块的功能正确性。
    • 集成测试: 将不同模块组合起来进行集成测试,例如电机控制模块和模式管理模块的集成测试,验证模块之间的协同工作是否正常。
    • 系统测试: 进行全面的系统测试,包括功能测试、性能测试、可靠性测试、压力测试等,验证整个系统的功能和性能是否满足需求。
    • 实机测试: 在实际机器人硬件平台上进行测试,验证软件在真实环境下的运行情况。
  • 维护升级:
    • 模块化设计: 模块化设计使得系统的维护和升级更加容易,可以针对特定模块进行修改和更新,而不会影响其他模块。
    • 清晰的接口: 模块之间通过清晰的接口进行通信,降低了模块之间的耦合度,方便模块的替换和升级。
    • 版本控制: 使用Git进行代码版本控制,可以方便代码的维护和升级,记录每次修改和升级的内容。
    • 文档化: 编写清晰的文档,包括架构设计文档、代码注释、API文档等,方便后续的维护和升级工作。
    • OTA升级 (Over-The-Air): 对于ESP32平台,可以考虑实现OTA升级功能,方便远程升级固件,无需物理接触机器人。

总结

以上架构设计和代码示例旨在为您提供一个构建可靠、高效、可扩展的履足式机器人嵌入式软件平台的框架。实际项目开发中,需要根据具体的硬件配置、功能需求和性能指标进行详细设计和代码实现。 这个3000行以上的详细介绍和代码框架已经涵盖了嵌入式系统开发的关键方面,希望能对您的项目有所帮助。

欢迎关注我的其它发布渠道