编程技术分享

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

0%

简介:本作品具有水质监测,自主巡航,双重运动遥控,数据云传输以及微信小程序等功能,旨在解决水质监测作业环境恶劣、重复性强、采样时间长的作业特点和任务需求,实现快速、高效、精确的完成水质监测任务。

好的,作为一名高级嵌入式软件开发工程师,我将为您详细阐述这个水质监测自主巡航船项目的嵌入式软件架构设计,并提供相应的C代码示例。
关注微信公众号,提前获取相关推文

项目背景与需求分析

正如您所描述的,这个项目旨在开发一款能够自主或遥控巡航的水质监测船,以解决传统人工水质监测作业中存在的环境恶劣、重复性强、采样时间长等问题。项目的核心需求可以归纳为以下几点:

  1. 水质监测功能:

    • 集成多种水质传感器,实时采集水体pH值、温度、溶解氧、浊度、电导率等关键参数。
    • 具备数据处理能力,对传感器数据进行校准、滤波、单位转换等处理,保证数据准确性。
    • 能够存储监测数据,并支持数据上传至云平台。
  2. 自主巡航功能:

    • 具备自主导航能力,能够按照预设路径或目标点进行自主巡航。
    • 具备环境感知能力,能够避开障碍物,确保航行安全。
    • 能够根据水质监测任务,自主规划巡航路线。
  3. 双重运动遥控功能:

    • 支持无线遥控,方便用户在必要时手动控制船只运动。
    • 遥控方式需要稳定可靠,响应及时。
  4. 数据云传输功能:

    • 通过无线通信模块(如4G/NB-IoT/WiFi)将监测数据实时上传至云平台。
    • 支持数据断点续传,保证数据完整性。
    • 云平台需要提供数据存储、分析、可视化等功能,方便用户进行远程监控和管理。
  5. 微信小程序功能:

    • 开发微信小程序,作为用户与系统的交互界面。
    • 小程序需要能够显示实时监测数据、控制船只运动、设置巡航任务、查看历史数据等功能。
  6. 系统可靠性、高效性、可扩展性:

    • 系统需要能够在水面复杂环境中稳定可靠运行。
    • 系统需要高效节能,延长续航时间。
    • 系统需要具备良好的可扩展性,方便后续功能升级和传感器扩展。

代码设计架构:分层模块化架构

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

分层架构的优势:

  • 高内聚低耦合: 每个模块专注于自身的功能,模块之间的依赖性降低,提高代码的可维护性和可重用性。
  • 易于开发和测试: 模块化设计使得开发人员可以并行开发不同的模块,单元测试可以针对每个模块独立进行。
  • 可扩展性强: 当需要添加新功能或修改现有功能时,只需要修改或添加相应的模块,而不会对整个系统造成大的影响。
  • 层次清晰,易于理解: 分层结构使得系统架构清晰明了,方便开发人员理解和维护。

本项目的分层模块化架构设计:

我将本项目系统架构设计为以下五个层次,从底层硬件到上层应用,层层抽象,构建清晰的系统框架:

  1. 硬件抽象层 (Hardware Abstraction Layer, HAL):

    • 功能: 封装底层硬件操作,向上层提供统一的硬件访问接口。
    • 模块:
      • 传感器驱动模块: 负责各种水质传感器(pH、温度、溶解氧、浊度、电导率等)、GPS模块、IMU模块、电机驱动模块、无线通信模块(4G/NB-IoT/WiFi)、存储模块(Flash/SD卡)的驱动程序。
      • 底层外设驱动模块: 负责GPIO、ADC、I2C、SPI、UART、Timer等底层外设的驱动程序。
    • 作用: 屏蔽底层硬件差异,使得上层应用代码可以独立于具体的硬件平台。当更换硬件平台时,只需要修改HAL层代码,而无需修改上层应用代码。
  2. 驱动层 (Driver Layer):

    • 功能: 基于HAL层提供的接口,实现更高级别的设备驱动,并提供设备管理和控制功能。
    • 模块:
      • 传感器管理模块: 负责传感器初始化、数据采集、数据预处理(如校准、滤波)、数据格式转换等。
      • 电机控制模块: 负责电机驱动控制、速度控制、转向控制、运动控制算法(如PID控制)。
      • 导航定位模块: 负责GPS数据解析、IMU数据处理、姿态解算、定位算法、航向计算。
      • 通信管理模块: 负责无线通信模块的初始化、连接管理、数据收发、协议封装解封装。
      • 存储管理模块: 负责文件系统管理、数据存储、数据读取、数据日志记录。
      • 电源管理模块: 负责电池电量监测、低功耗管理、电源模式切换。
    • 作用: 为上层应用层提供更高级别、更易于使用的设备操作接口。
  3. 服务层 (Service Layer):

    • 功能: 实现核心业务逻辑,提供各种系统服务。
    • 模块:
      • 水质监测服务模块: 负责周期性地触发传感器数据采集、数据处理、数据存储,并向上层应用提供水质监测数据接口。
      • 自主巡航服务模块: 负责接收巡航任务指令、路径规划、导航控制、避障控制、航行状态管理,并向上层应用提供巡航控制接口。
      • 遥控控制服务模块: 负责接收遥控指令、解析遥控指令、控制电机运动,并向上层应用提供遥控控制接口。
      • 数据传输服务模块: 负责将监测数据上传至云平台、处理网络连接状态、数据重传机制,并向上层应用提供数据传输接口。
      • 系统配置服务模块: 负责系统参数配置、设备参数配置、网络配置、用户配置等,并向上层应用提供配置管理接口。
      • 错误日志服务模块: 负责系统错误日志记录、错误信息上报、错误诊断,方便系统调试和维护。
    • 作用: 将底层的驱动程序和上层的应用逻辑连接起来,实现系统的核心功能。
  4. 应用层 (Application Layer):

    • 功能: 实现用户交互界面和应用程序逻辑。
    • 模块:
      • 主应用程序模块 (main.c): 负责系统初始化、任务调度、用户界面管理、系统状态监控。
      • 微信小程序接口模块: 负责与微信小程序进行数据交互,接收小程序指令,向上层服务模块发送指令,并将系统数据推送给小程序。
      • 遥控器接口模块: 负责接收遥控器指令,解析遥控指令,向上层遥控控制服务模块发送指令。
    • 作用: 为用户提供操作界面,实现用户与系统的交互,并协调各个服务模块完成任务。
  5. 操作系统层 (Operating System Layer, OS Layer,可选):

    • 功能: 提供任务调度、内存管理、进程间通信、系统资源管理等功能。
    • 选择: 对于资源有限的嵌入式系统,可以选择使用实时操作系统 (RTOS) 如 FreeRTOS、RT-Thread、uCOS-III,或者使用轻量级操作系统 (如基于事件驱动的调度器),甚至在简单的应用场景下可以不使用操作系统,直接基于裸机开发。
    • 本项目: 考虑到本项目的功能复杂性,以及对实时性和可靠性的要求,推荐使用RTOS。RTOS可以更好地管理系统资源,提高系统的实时性和稳定性,方便多任务并发执行,简化代码结构。

架构示意图:

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
+-----------------------+
| 应用层 (Application Layer) |
| +-------------------+ +-------------------+ +-------------------+ |
| | 主应用程序模块 | | 微信小程序接口模块 | | 遥控器接口模块 | |
| +-------------------+ +-------------------+ +-------------------+ |
+-----------------------+
|
| (服务调用接口)
V
+-----------------------+
| 服务层 (Service Layer) |
| +-------------------+ +-------------------+ +-------------------+ +-------------------+ +-------------------+ +-------------------+ |
| | 水质监测服务模块 | | 自主巡航服务模块 | | 遥控控制服务模块 | | 数据传输服务模块 | | 系统配置服务模块 | | 错误日志服务模块 | |
| +-------------------+ +-------------------+ +-------------------+ +-------------------+ +-------------------+ +-------------------+ |
+-----------------------+
|
| (驱动接口)
V
+-----------------------+
| 驱动层 (Driver Layer) |
| +-------------------+ +-------------------+ +-------------------+ +-------------------+ +-------------------+ +-------------------+ +-------------------+ |
| | 传感器管理模块 | | 电机控制模块 | | 导航定位模块 | | 通信管理模块 | | 存储管理模块 | | 电源管理模块 | | ... | |
| +-------------------+ +-------------------+ +-------------------+ +-------------------+ +-------------------+ +-------------------+ +-------------------+ |
+-----------------------+
|
| (HAL接口)
V
+-----------------------+
| 硬件抽象层 (HAL Layer) |
| +-------------------+ +-------------------+ +-------------------+ +-------------------+ +-------------------+ +-------------------+ +-------------------+ |
| | 传感器驱动模块 | | 电机驱动模块 | | GPS驱动模块 | | 通信模块驱动 | | 存储模块驱动 | | 外设驱动模块 | | ... | |
| +-------------------+ +-------------------+ +-------------------+ +-------------------+ +-------------------+ +-------------------+ +-------------------+ |
+-----------------------+
|
| (硬件操作)
V
+-----------------------+
| 硬件设备 (Hardware) |
| +-------------------+ +-------------------+ +-------------------+ +-------------------+ +-------------------+ +-------------------+ +-------------------+ |
| | 水质传感器 | | 电机 | | GPS模块 | | 4G/NB-IoT/WiFi | | Flash/SD卡 | | MCU/外设 | | ... | |
| +-------------------+ +-------------------+ +-------------------+ +-------------------+ +-------------------+ +-------------------+ +-------------------+ |
+-----------------------+

C代码实现示例 (部分模块)

为了演示这种分层模块化架构的具体实现,我将提供部分关键模块的C代码示例。由于代码量较大,我将重点展示架构的核心思想和关键模块的实现方式,并对代码进行详细注释。

1. 硬件抽象层 (HAL) - 传感器驱动模块 (以 pH 传感器为例)

  • hal_sensor_ph.h: 定义 pH 传感器 HAL 接口
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#ifndef HAL_SENSOR_PH_H
#define HAL_SENSOR_PH_H

#include <stdint.h>
#include <stdbool.h>

// pH 传感器 HAL 初始化函数
bool hal_ph_sensor_init(void);

// 读取 pH 传感器原始 ADC 值
uint16_t hal_ph_sensor_read_adc(void);

// 设置 pH 传感器供电状态 (例如,为了省电,可以控制传感器电源开关)
void hal_ph_sensor_power_control(bool enable);

#endif // HAL_SENSOR_PH_H
  • hal_sensor_ph.c: 实现 pH 传感器 HAL 接口 (假设 pH 传感器通过 ADC 读取)
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
#include "hal_sensor_ph.h"
#include "hal_adc.h" // 假设 HAL 层提供了 ADC 驱动接口
#include "hal_gpio.h" // 假设 HAL 层提供了 GPIO 驱动接口,用于控制传感器电源

#define PH_SENSOR_ADC_CHANNEL ADC_CHANNEL_1 // pH 传感器连接的 ADC 通道
#define PH_SENSOR_POWER_GPIO GPIO_PIN_5 // pH 传感器电源控制 GPIO 引脚

bool hal_ph_sensor_init(void) {
// 初始化 ADC 模块 (假设 hal_adc_init() 已经完成通用 ADC 初始化)
if (!hal_adc_channel_init(PH_SENSOR_ADC_CHANNEL)) {
return false;
}

// 初始化 GPIO 引脚,用于控制传感器电源
hal_gpio_init(PH_SENSOR_POWER_GPIO, GPIO_OUTPUT);
hal_ph_sensor_power_control(true); // 默认上电

return true;
}

uint16_t hal_ph_sensor_read_adc(void) {
return hal_adc_read_value(PH_SENSOR_ADC_CHANNEL);
}

void hal_ph_sensor_power_control(bool enable) {
if (enable) {
hal_gpio_set_output(PH_SENSOR_POWER_GPIO, GPIO_HIGH); // 使能电源
} else {
hal_gpio_set_output(PH_SENSOR_POWER_GPIO, GPIO_LOW); // 关闭电源
}
}

2. 驱动层 (Driver) - 传感器管理模块 (Sensor Management Module)

  • driver_sensor.h: 定义传感器管理模块接口
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#ifndef DRIVER_SENSOR_H
#define DRIVER_SENSOR_H

#include <stdint.h>
#include <stdbool.h>

// 定义传感器数据结构体
typedef struct {
float ph_value;
float temperature_value;
float dissolved_oxygen_value;
float turbidity_value;
float conductivity_value;
// 可以根据实际项目需求添加更多传感器数据
} sensor_data_t;

// 初始化所有传感器
bool sensor_manager_init(void);

// 采集所有传感器数据
bool sensor_manager_read_data(sensor_data_t *data);

#endif // DRIVER_SENSOR_H
  • driver_sensor.c: 实现传感器管理模块,调用 HAL 层接口
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
#include "driver_sensor.h"
#include "hal_sensor_ph.h" // pH 传感器 HAL
#include "hal_sensor_temperature.h" // 温度传感器 HAL (假设已实现)
#include "hal_sensor_do.h" // 溶解氧传感器 HAL (假设已实现)
#include "hal_sensor_turbidity.h" // 浊度传感器 HAL (假设已实现)
#include "hal_sensor_conductivity.h" // 电导率传感器 HAL (假设已实现)

// 传感器校准参数 (实际项目中需要根据传感器特性进行校准)
#define PH_SENSOR_ADC_TO_PH_SLOPE 0.01 // 假设斜率
#define PH_SENSOR_ADC_TO_PH_OFFSET 7.00 // 假设偏移量

#define TEMPERATURE_SENSOR_ADC_TO_TEMP_SLOPE 0.1 // 假设斜率
#define TEMPERATURE_SENSOR_ADC_TO_TEMP_OFFSET 25.0 // 假设偏移量

// ... 其他传感器校准参数 ...

bool sensor_manager_init(void) {
if (!hal_ph_sensor_init()) {
return false;
}
// 初始化其他传感器 HAL ...
return true;
}

bool sensor_manager_read_data(sensor_data_t *data) {
if (data == NULL) {
return false;
}

// 读取 pH 传感器数据并进行转换
uint16_t ph_adc_value = hal_ph_sensor_read_adc();
data->ph_value = (float)ph_adc_value * PH_SENSOR_ADC_TO_PH_SLOPE + PH_SENSOR_ADC_TO_PH_OFFSET;

// 读取温度传感器数据并进行转换 (假设已实现)
uint16_t temp_adc_value = hal_temperature_sensor_read_adc();
data->temperature_value = (float)temp_adc_value * TEMPERATURE_SENSOR_ADC_TO_TEMP_SLOPE + TEMPERATURE_SENSOR_ADC_TO_TEMP_OFFSET;

// 读取其他传感器数据并进行转换 ...

return true;
}

3. 服务层 (Service) - 水质监测服务模块 (Water Quality Monitoring Service)

  • service_water_quality.h: 定义水质监测服务接口
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#ifndef SERVICE_WATER_QUALITY_H
#define SERVICE_WATER_QUALITY_H

#include "driver_sensor.h"
#include <stdbool.h>

// 初始化水质监测服务
bool water_quality_service_init(void);

// 执行一次水质监测任务 (采集数据并存储)
bool water_quality_service_run_once(void);

// 获取最新的水质监测数据
bool water_quality_service_get_latest_data(sensor_data_t *data);

#endif // SERVICE_WATER_QUALITY_H
  • service_water_quality.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
#include "service_water_quality.h"
#include "driver_sensor.h"
#include "driver_storage.h" // 假设驱动层提供了存储管理模块

#define WATER_QUALITY_DATA_LOG_FILE "water_quality_log.txt" // 水质数据日志文件名

static sensor_data_t latest_sensor_data; // 存储最新的传感器数据

bool water_quality_service_init(void) {
if (!sensor_manager_init()) {
return false;
}
// 初始化存储模块 (例如,文件系统)
if (!storage_manager_init()) {
return false;
}
return true;
}

bool water_quality_service_run_once(void) {
sensor_data_t current_data;
if (!sensor_manager_read_data(&current_data)) {
return false;
}

// 数据存储 (例如,写入日志文件)
if (!storage_manager_append_data(WATER_QUALITY_DATA_LOG_FILE, &current_data, sizeof(sensor_data_t))) {
// 错误处理,例如记录错误日志
}

// 更新最新数据
latest_sensor_data = current_data;

return true;
}

bool water_quality_service_get_latest_data(sensor_data_t *data) {
if (data == NULL) {
return false;
}
*data = latest_sensor_data; // 复制最新数据
return true;
}

4. 应用层 (Application) - 主应用程序模块 (main.c)

  • 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
#include "service_water_quality.h"
#include "service_autonomous_cruise.h" // 假设已实现自主巡航服务模块
#include "service_remote_control.h" // 假设已实现遥控控制服务模块
#include "service_data_transmission.h" // 假设已实现数据传输服务模块
#include "driver_communication.h" // 假设驱动层提供了通信管理模块
#include "driver_navigation.h" // 假设驱动层提供了导航定位模块
#include "driver_motor_control.h" // 假设驱动层提供了电机控制模块
#include <stdio.h>
#include <unistd.h> // For sleep()

int main() {
printf("水质监测自主巡航船系统启动...\n");

// 初始化各个服务模块
if (!water_quality_service_init()) {
printf("水质监测服务初始化失败!\n");
return -1;
}
if (!autonomous_cruise_service_init()) {
printf("自主巡航服务初始化失败!\n");
return -1;
}
if (!remote_control_service_init()) {
printf("遥控控制服务初始化失败!\n");
return -1;
}
if (!data_transmission_service_init()) {
printf("数据传输服务初始化失败!\n");
return -1;
}
if (!communication_manager_init()) {
printf("通信管理模块初始化失败!\n");
return -1;
}
if (!navigation_manager_init()) {
printf("导航定位模块初始化失败!\n");
return -1;
}
if (!motor_control_manager_init()) {
printf("电机控制模块初始化失败!\n");
return -1;
}

printf("系统初始化完成,开始运行...\n");

while (1) {
// 1. 执行水质监测任务
if (water_quality_service_run_once()) {
printf("水质监测数据采集成功!\n");
sensor_data_t current_data;
water_quality_service_get_latest_data(&current_data);
printf("pH: %.2f, 温度: %.2f, 溶解氧: %.2f, 浊度: %.2f, 电导率: %.2f\n",
current_data.ph_value, current_data.temperature_value,
current_data.dissolved_oxygen_value, current_data.turbidity_value,
current_data.conductivity_value);

// 2. 数据传输 (假设周期性上传数据到云平台)
data_transmission_service_send_data(&current_data, sizeof(sensor_data_t));
} else {
printf("水质监测数据采集失败!\n");
}

// 3. 检查遥控指令 (假设遥控控制服务周期性检查遥控指令)
remote_control_service_process_commands();

// 4. 自主巡航控制 (根据当前状态和任务进行自主巡航控制)
autonomous_cruise_service_run_step();

sleep(5); // 周期性任务,例如每 5 秒执行一次
}

return 0;
}

代码说明:

  • 模块化设计: 代码示例清晰地展示了分层模块化架构的思想。每个模块(HAL, Driver, Service, Application)都有明确的职责和接口。
  • 接口清晰: 模块之间通过头文件定义的接口进行交互,例如 hal_sensor_ph.h, driver_sensor.h, service_water_quality.h 等。
  • 代码可读性: 代码添加了详细的注释,方便理解每个模块的功能和实现细节。
  • 示例代码: 代码示例只是为了演示架构思想,实际项目中需要根据具体的硬件平台和需求进行完善和扩展。例如,需要实现更多传感器驱动、电机控制算法、导航算法、通信协议、数据处理逻辑等。

项目中采用的关键技术和方法

除了分层模块化架构,本项目在开发过程中还应用了以下关键技术和方法:

  1. 实时操作系统 (RTOS): 使用 RTOS (如 FreeRTOS) 可以有效地管理系统资源,提高系统的实时性和稳定性,支持多任务并发执行,简化代码结构。
  2. 事件驱动编程: 在驱动层和服务层,可以采用事件驱动编程模型,提高系统的响应速度和效率。例如,传感器数据采集完成、遥控指令接收到、网络数据到达等事件可以触发相应的处理函数。
  3. 状态机设计: 对于复杂的系统行为,例如自主巡航、遥控控制等,可以使用状态机来管理系统的不同状态和状态转换,提高代码的可维护性和可理解性。
  4. 数据滤波和校准: 传感器数据通常会受到噪声和误差的影响,需要采用数据滤波算法(如滑动平均滤波、卡尔曼滤波)和校准方法(如两点校准、多点校准)来提高数据的准确性和可靠性。
  5. PID控制算法: 在电机控制模块,可以使用 PID 控制算法来实现精确的速度控制和位置控制,保证船只的稳定航行和准确运动。
  6. 无线通信技术: 根据项目需求选择合适的无线通信技术,例如 4G/NB-IoT 用于云数据传输,WiFi 用于近距离通信和调试,LoRa 用于远距离低功耗通信。
  7. 低功耗设计: 对于电池供电的嵌入式系统,低功耗设计至关重要。可以采用电源管理芯片、低功耗MCU、优化软件算法等方法来降低系统功耗,延长续航时间。
  8. 软件测试和验证: 在开发过程中,需要进行充分的软件测试和验证,包括单元测试、集成测试、系统测试、性能测试、稳定性测试等,确保系统的功能和性能满足需求。
  9. 版本控制和代码管理: 使用版本控制系统 (如 Git) 进行代码管理,方便团队协作开发、代码版本回溯、bug 追踪和修复。

项目可扩展性和未来展望

采用分层模块化架构使得本项目具有良好的可扩展性。未来可以根据需求方便地添加新功能和模块,例如:

  • 扩展传感器类型: 可以添加更多水质传感器(如重金属传感器、藻类传感器)或环境传感器(如气象传感器),扩展水质监测和环境监测能力。
  • 增加图像识别功能: 可以集成摄像头和图像识别算法,实现水面漂浮物识别、水质异常检测等功能。
  • 优化自主巡航算法: 可以采用更先进的路径规划算法、避障算法、环境感知算法,提高自主巡航的智能化水平和适应性。
  • 扩展通信功能: 可以增加卫星通信模块,提高数据传输的覆盖范围和可靠性。
  • 云平台功能升级: 可以扩展云平台的数据分析、可视化、预警功能,为用户提供更全面的水质监测和管理服务。

总结

本项目的水质监测自主巡航船系统,采用分层模块化架构进行软件设计,能够构建一个可靠、高效、可扩展的嵌入式系统平台。通过合理的模块划分、清晰的接口定义、以及关键技术的应用,可以有效地完成水质监测、自主巡航、遥控控制、数据云传输等功能,满足项目需求。提供的C代码示例展示了架构的核心思想和关键模块的实现方式,为实际项目开发提供了参考。

希望这个详细的架构设计和代码示例能够帮助您理解嵌入式系统开发流程和代码架构设计。如果您有任何疑问或需要进一步的帮助,请随时提出。

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