增加景点播报功能原型 后期需修改
This commit is contained in:
parent
cf05010be5
commit
21790a8b22
|
|
@ -0,0 +1,29 @@
|
||||||
|
#ifndef ATTR_BROADCAST_H
|
||||||
|
#define ATTR_BROADCAST_H
|
||||||
|
#include "cm_os.h"
|
||||||
|
#include "nmea/nmea.h"
|
||||||
|
|
||||||
|
|
||||||
|
// 景点信息
|
||||||
|
typedef struct {
|
||||||
|
double longitude; // 经度
|
||||||
|
double latitude; // 纬度
|
||||||
|
char name[50]; // 景点名称
|
||||||
|
char description[200]; // 景点描述
|
||||||
|
} Attraction;
|
||||||
|
|
||||||
|
|
||||||
|
// 初始化景点播报系统
|
||||||
|
void attr_broadcast_init(void);
|
||||||
|
|
||||||
|
// 添加景点
|
||||||
|
void attr_broadcast_add_attraction(double lon, double lat,
|
||||||
|
const char* name, const char* desc);
|
||||||
|
// 停止景点播报任务
|
||||||
|
void attr_broadcast_stop(void);
|
||||||
|
|
||||||
|
// 设置播报距离阈值 (米)
|
||||||
|
void attr_broadcast_set_distance_threshold(double threshold);
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* ATTR_BROADCAST_H */
|
||||||
|
|
@ -0,0 +1,254 @@
|
||||||
|
#include "cm_iomux.h"
|
||||||
|
#include "cm_gpio.h"
|
||||||
|
#include "stdio.h"
|
||||||
|
#include "stdlib.h"
|
||||||
|
#include "stdarg.h"
|
||||||
|
#include "stdbool.h"
|
||||||
|
#include "math.h"
|
||||||
|
#include "cm_os.h"
|
||||||
|
#include "cm_mem.h"
|
||||||
|
#include "cm_sys.h"
|
||||||
|
#include "cm_uart.h"
|
||||||
|
|
||||||
|
#include "app_common.h"
|
||||||
|
#include "app_uart.h"
|
||||||
|
|
||||||
|
#include "attr_broadcast.h"
|
||||||
|
#include "gps_config.h"
|
||||||
|
#include "local_tts.h"
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
#include "app_uart.h"
|
||||||
|
#define DEBUG(fmt, args...) app_printf("[GPS]" fmt, ##args)
|
||||||
|
#else
|
||||||
|
#include "app_uart.h"
|
||||||
|
#define DEBUG(fmt, ...)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define MAX_ATTRACTIONS 50 // 最大景点数量
|
||||||
|
#define PLAY_DISTANCE_THRESHOLD 50.0 // 有效播报距离(米)
|
||||||
|
#define DISTANCE_CHANGE_THRESHOLD 10.0 // 距离变化阈值(米)
|
||||||
|
#define TTS_PRIORITY 5 // TTS播报优先级
|
||||||
|
|
||||||
|
static osMutexId_t attractions_mutex = NULL;
|
||||||
|
static AttractionNode* attractions_head = NULL;
|
||||||
|
static BroadcastState broadcast_state = {0};
|
||||||
|
static osThreadId_t guide_task_id = NULL;
|
||||||
|
static int tts_speed = 5;
|
||||||
|
static int tts_volume = 10;
|
||||||
|
|
||||||
|
|
||||||
|
static nmeaPARSER parser;
|
||||||
|
|
||||||
|
typedef enum { false, true } bool; // 手动定义布尔类型
|
||||||
|
|
||||||
|
// 全局景点链表
|
||||||
|
typedef struct AttractionNode {
|
||||||
|
Attraction attraction;
|
||||||
|
struct AttractionNode* next;
|
||||||
|
} AttractionNode;
|
||||||
|
|
||||||
|
// 播报状态
|
||||||
|
typedef struct {
|
||||||
|
AttractionNode* last_broadcast; // 上次播报的景点
|
||||||
|
double last_distance; // 上次播报时的距离
|
||||||
|
uint8_t is_playing; // TTS是否正在播放
|
||||||
|
} BroadcastState;
|
||||||
|
|
||||||
|
//位置信息
|
||||||
|
typedef struct {
|
||||||
|
double longitude;
|
||||||
|
double latitude;
|
||||||
|
} Location;
|
||||||
|
|
||||||
|
|
||||||
|
//计算到景点的距离
|
||||||
|
double location_service_calculate_distance(Location loc1, Location loc2) {
|
||||||
|
// 使用Haversine公式计算真实距离
|
||||||
|
const double R = 6371000; // 地球半径(米)
|
||||||
|
double dLat = (loc2.latitude - loc1.latitude) * M_PI / 180.0;
|
||||||
|
double dLon = (loc2.longitude - loc1.longitude) * M_PI / 180.0;
|
||||||
|
|
||||||
|
double a = sin(dLat/2) * sin(dLat/2) +
|
||||||
|
cos(loc1.latitude * M_PI / 180.0) *
|
||||||
|
cos(loc2.latitude * M_PI / 180.0) *
|
||||||
|
sin(dLon/2) * sin(dLon/2);
|
||||||
|
|
||||||
|
double c = 2 * atan2(sqrt(a), sqrt(1-a));
|
||||||
|
return R * c;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取当前位置
|
||||||
|
Location location_service_get_current(void) {
|
||||||
|
Location current = {0};
|
||||||
|
|
||||||
|
// 加锁保护全局数据
|
||||||
|
if (osMutexAcquire(gps_mutex, 100) == osOK) {
|
||||||
|
// 检查数据是否有效
|
||||||
|
if (gps_data.info.sig > 0 && gps_data.info.fix > 0) {
|
||||||
|
current.longitude = gps_data.dpos.lon;
|
||||||
|
current.latitude = gps_data.dpos.lat;
|
||||||
|
}
|
||||||
|
osMutexRelease(gps_mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
return current;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 添加景点
|
||||||
|
void attr_broadcast_add_attraction(double lon, double lat,
|
||||||
|
const char* name, const char* desc) {
|
||||||
|
if (attractions_mutex == NULL) return;
|
||||||
|
|
||||||
|
osMutexAcquire(attractions_mutex, osWaitForever);
|
||||||
|
|
||||||
|
AttractionNode* new_node = malloc(sizeof(AttractionNode));
|
||||||
|
if (!new_node) {
|
||||||
|
osMutexRelease(attractions_mutex);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 填充景点信息
|
||||||
|
new_node->attraction.longitude = lon;
|
||||||
|
new_node->attraction.latitude = lat;
|
||||||
|
strncpy(new_node->attraction.name, name, sizeof(new_node->attraction.name)-1);
|
||||||
|
strncpy(new_node->attraction.description, desc, sizeof(new_node->attraction.description)-1);
|
||||||
|
|
||||||
|
// 添加到链表头部
|
||||||
|
new_node->next = attractions_head;
|
||||||
|
attractions_head = new_node;
|
||||||
|
|
||||||
|
osMutexRelease(attractions_mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 设置播报距离阈值 (米)
|
||||||
|
void attr_broadcast_set_distance_threshold(double threshold) {
|
||||||
|
if (threshold > 0) {
|
||||||
|
broadcast_state.distance_threshold = threshold;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//设置tts参数
|
||||||
|
void attr_broadcast_set_tts_params(int speed, int volume) {
|
||||||
|
tts_speed = speed;
|
||||||
|
tts_volume = volume;
|
||||||
|
|
||||||
|
if (guide_task_id != NULL) {
|
||||||
|
// 如果任务已启动,更新TTS参数
|
||||||
|
local_tts_set(tts_speed, tts_volume, CM_LOCAL_TTS_DIGIT_AUTO);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// 根据当前位置查找最近的景区节点
|
||||||
|
static AttractionNode* find_nearest_attraction(Location current_pos) {
|
||||||
|
if (attractions_head == NULL) return NULL;
|
||||||
|
|
||||||
|
osMutexAcquire(attractions_mutex, osWaitForever);
|
||||||
|
|
||||||
|
AttractionNode* current = attractions_head;
|
||||||
|
AttractionNode* nearest = attractions_head;
|
||||||
|
double min_distance = location_service_calculate_distance(
|
||||||
|
(Location){current->attraction.longitude, current->attraction.latitude},
|
||||||
|
current_pos
|
||||||
|
);
|
||||||
|
|
||||||
|
while (current != NULL) {
|
||||||
|
double distance = location_service_calculate_distance(
|
||||||
|
(Location){current->attraction.longitude, current->attraction.latitude},
|
||||||
|
current_pos
|
||||||
|
);
|
||||||
|
|
||||||
|
if (distance < min_distance) {
|
||||||
|
min_distance = distance;
|
||||||
|
nearest = current;
|
||||||
|
}
|
||||||
|
|
||||||
|
current = current->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
osMutexRelease(attractions_mutex);
|
||||||
|
return nearest;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void play_attraction_info(AttractionNode* attraction, double distance) {
|
||||||
|
if (!attraction) return;
|
||||||
|
|
||||||
|
// 构建播报文本
|
||||||
|
char buffer[300];
|
||||||
|
snprintf(buffer, sizeof(buffer), "您已到达%s,%s。距离%.1f米。",
|
||||||
|
attraction->attraction.name,
|
||||||
|
attraction->attraction.description,
|
||||||
|
distance);
|
||||||
|
|
||||||
|
// 调用TTS接口播放文本
|
||||||
|
local_tts_text_play(buffer, 0, 1);
|
||||||
|
|
||||||
|
// 更新播报状态
|
||||||
|
broadcast_state.last_broadcast = attraction;
|
||||||
|
broadcast_state.last_distance = distance;
|
||||||
|
broadcast_state.is_playing = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void attr_broadcast_task(void* arg) {
|
||||||
|
(void)arg; // 避免未使用参数警告
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
// 获取当前位置
|
||||||
|
Location current_pos = location_service_get_current();
|
||||||
|
|
||||||
|
// 查找最近景点
|
||||||
|
AttractionNode* nearest = find_nearest_attraction(current_pos);
|
||||||
|
|
||||||
|
if (nearest != NULL) {
|
||||||
|
// 计算距离
|
||||||
|
double distance = location_service_calculate_distance(
|
||||||
|
(Location){nearest->attraction.longitude, nearest->attraction.latitude},
|
||||||
|
current_pos
|
||||||
|
);
|
||||||
|
|
||||||
|
// 检查是否在有效范围内
|
||||||
|
if (distance <= broadcast_state.distance_threshold) {
|
||||||
|
// 检查是否需要播报
|
||||||
|
bool should_play = false;
|
||||||
|
|
||||||
|
if (broadcast_state.last_broadcast == NULL) {
|
||||||
|
should_play = true; // 首次播报
|
||||||
|
}
|
||||||
|
else if (broadcast_state.last_broadcast != nearest) {
|
||||||
|
should_play = true; // 新景点
|
||||||
|
}
|
||||||
|
else if (fabs(distance - broadcast_state.last_distance) > 10.0) {
|
||||||
|
should_play = true; // 同一景点但距离变化大
|
||||||
|
}
|
||||||
|
|
||||||
|
// 触发播报
|
||||||
|
if (should_play && !broadcast_state.is_playing) {
|
||||||
|
play_attraction_info(nearest, distance);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 5秒检测一次
|
||||||
|
osDelay(5000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void attr_broadcast_init(void) {
|
||||||
|
// 初始化互斥锁
|
||||||
|
if (attractions_mutex == NULL) {
|
||||||
|
attractions_mutex = osMutexNew(NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 初始化状态
|
||||||
|
memset(&broadcast_state, 0, sizeof(broadcast_state));
|
||||||
|
broadcast_state.distance_threshold = 50.0; // 默认阈值50米
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue