项目实训 - 智能车系统 - 第十二周记录
日期:5.9 – 5.15
项目进度
本周工作进展:
- 修改信号量销毁(如果不是第一次创建,不赋值 修改lastnumber+nownumber) 与可视化对接信号量的一系列问题
- 测试雷达+雷达驱动测试
- 总体测试
1、信号量版本修改
在与可视化对接的时候,由于可视化的编写原因,需要将信号量销毁之后才能退出程序。所以需要添加销毁函数:
int destory_sem(int semid)
{
if (semctl(semid, 0, IPC_RMID)>=0)
{
return 0;
}
else
{
perror("Destory error");
return -1;
}
}
在程序入口处添加signal函数,捕捉ctrl+c信号,回调函数中销毁信号量,从而使可视化正常退出。
eg:
signal(SIGINT, exit_process);
static void exit_process(int sig)
{
destory_sem(pubImuOdometry_sharemem_image->pub_sem_id);
destory_sem(pubImuOdometry_sharemem_image->sub_sem_id);
destory_sem(pubImuOdometry_sharemem_imu->pub_sem_id);
destory_sem(pubImuOdometry_sharemem_imu->sub_sem_id);
destory_sem(pubCloudImuPath_sharemem->pub_sem_id);
destory_sem(pubCloudImuPath_sharemem->sub_sem_id);
destory_sem(pubCloudImuPath_sharemem_navigation->pub_sem_id);
destory_sem(pubCloudImuPath_sharemem_navigation->sub_sem_id);
destory_sem(pubCloudImuPath_sharemem_recorder->pub_sem_id);
destory_sem(pubCloudImuPath_sharemem_recorder->sub_sem_id);
exit(0);
}
在测试中发现问题:接收端会被阻塞,检查后发现,是在创建信号量和获取信号量的操作时,我的函数实现都会将信号量重新赋值,从而导致信号量混乱。
- 解决:通过修改信号量的创建方式,判断信号量是否为首次创建。如果是,则赋初始值;如果不是,则不赋值。
问题2:仍会出现阻塞问题。经过排查,发现是与上一个通信机制版本的判断方式发生冲突,进行简单修改后即可。
解决上述问题后,调试成功。
通信机制最终版:
#include "communicator1.h"
/**
* @brief used to define share memory
* @param fd:共享内存区域ID
* @param point:共享内存区域首地址
*
*/
key_t get_id(const string fileName)
{
key_t ret = 0;
for(int i = 0; i < fileName.size(); i++)
{
ret += fileName[i];
}
//cout<<fileName<<' '<<ret<<endl;
return ret + 1000000;
}
/**
* @brief Create a Sem object
*
* @param sem_key
* @return int 返回信号量标识符;失败返回-1
* 如果未创建信号量,则创建新信号量;否则不做处理
*/
int createSem(const string sem_key)
{
key_t key = get_id(sem_key);
cout<<"sem id "<<get_id(sem_key)<<endl;
int sem_flag = IPC_CREAT | IPC_EXCL | 0666;
return semget(key, 1, sem_flag);
}
/**
* @brief Get the Sem object
*
* @param sem_key
* @return int
* 同 createSem
*/
int getSem(const string sem_key)
{
return createSem(sem_key);
}
union semun{
int val; //使用的值
struct semid_ds *buf; //IPC_STAT、IPC_SET 使用的缓存区
unsigned short *arry; //GETALL,、SETALL 使用的数组
struct seminfo *__buf; // IPC_INFO(Linux特有) 使用的缓存区
};
/**
* @brief init sem
*
* @param semid
* @param val
* @return int 初始化失败返回-1;否则返回0
* 默认初始化信号量集中的第一个 0 (只有一个)
*/
int initSem(int semid, int val)
{
union semun _semun;
_semun.val = val;
if (semctl(semid, 0, SETVAL, _semun)<0)
{
perror("InitSem");
return -1;
}
return 0;
}
// struct sembuf{
// short sem_num; //除非使用一组信号量,否则它为0
// short sem_op; //信号量在一次操作中需要改变的数据,通常是两个数,
// //一个是-1,即P(等待)操作,
// //一个是+1,即V(发送信号)操作。
// short sem_flg; //通常为SEM_UNDO,使操作系统跟踪信号量,
// //并在进程没有释放该信号量而终止时,操作系统释放信号量
// };
int pSem(int semid)
{
struct sembuf _sf;
_sf.sem_num = 0;
_sf.sem_op = -1;
_sf.sem_flg = 0;
if(semop(semid, &_sf, 1) < 0) {
perror("P error");
return -1;
}
}
int vSem(int semid)
{
struct sembuf _sf;
_sf.sem_num = 0;
_sf.sem_op = 1;
_sf.sem_flg = 0;
if(semop(semid, &_sf, 1) < 0) {
perror("V error");
return -1;
}
}
int destory_sem(int semid)
{
if (semctl(semid, 0, IPC_RMID)>=0)
{
return 0;
}
else
{
perror("Destory error");
return -1;
}
}
int createSem_second(const string sem_key)
{
key_t key = get_id(sem_key);
int sem_flag = IPC_CREAT | 0666;
return semget(key, 1, sem_flag);
}
/**
* @brief 创建共享内存的同时
*
*/
/**
* @brief Create a shm object
*
* @param shm_key 共享内存键值
* @param shm_num 共享内存字节长度
* @param shm_flag 权限 (默认权限为读写权限)
*
* @param sem_key pub信号量
* @return void*
*/
MemoryDefinition* createShareMemory(const string shm_key, size_t shm_num,const string sem_key)//, int shm_flag = 1)
{
//cout<<"size "<<shm_num<<endl;
MemoryDefinition* shm_point = new MemoryDefinition();;
int shm_flag = IPC_CREAT | 0666;
int fd = shmget(get_id(shm_key), shm_num, shm_flag);
void* point;
if(fd != -1) {
//
point = shmat(fd, 0, 0);
if((int*)point != (int*)-1) {
//初始化
memset(point, 0, shm_num);
shm_point->fd = fd;
shm_point->point = point;
// return shm_point;
} else {
perror("get shareMemory error1");
//exit(EXIT_FAILURE);
}
} else {
perror("get shareMemory error2");
//exit(EXIT_FAILURE);
}
//创建信号量 两个信号量
int temp_semid_pub = createSem(sem_key+"pub");
if(temp_semid_pub < 0) {
// //创建失败
// perror("create sem error");
//说明之前已经创建过,不需要init了
//重新创建一次
temp_semid_pub = createSem_second(sem_key+"pub");
if(temp_semid_pub < 0) {
perror("create second sem error");
} else {
shm_point->pub_sem_id = temp_semid_pub;
}
}
else {
//初始值
int temp_init_semid = initSem(temp_semid_pub, 1); // 发布者创建的信号量 对应生产者 初值为1
if(temp_init_semid < 0) {
perror("init sem error");
} else {
//赋初始值成功
shm_point->pub_sem_id = temp_semid_pub;
}
}
int temp_semid_sub = getSem(sem_key+"sub");
if(temp_semid_sub < 0) {
//创建失败
temp_semid_sub = createSem_second(sem_key+"sub");
if(temp_semid_sub < 0) {
perror("create second sem error");
} else {
shm_point->sub_sem_id = temp_semid_sub;
}
} else {
//初始值
int temp_init_semid = initSem(temp_semid_sub, 0); // 发布者创建的信号量 对应生产者 初值为1
if(temp_init_semid < 0) {
perror("init sem error");
} else {
//赋初始值成功
shm_point->sub_sem_id = temp_semid_sub;
}
}
cout<<"sem: "<<sem_key<<" "<<shm_point->sub_sem_id<<" "<<shm_point->pub_sem_id<<endl;
return shm_point;
}
/**
* @brief 连接共享内存
*
* @param shm_key 共享内存键值
* @param shm_num 共享内存字节长度
* @param shm_flag 权限 (默认权限为读写权限)
* @return void*
*/
MemoryDefinition* connectShareMemory(const string shm_key, size_t shm_num, const string sem_key)//, int shm_flag = 1)
{
//cout<<"size "<<shm_num<<endl;
MemoryDefinition* shm_point = new MemoryDefinition();
int shm_flag = IPC_CREAT | 0666;
int fd = shmget(get_id(shm_key), shm_num, shm_flag);
void* point;
if(fd != -1) {
//
point = shmat(fd, 0, 0);
if((int*)point != (int*)-1) {
shm_point->fd = fd;
shm_point->point = point;
// return shm_point;
} else {
perror("get shareMemory error3");
//exit(EXIT_FAILURE);
}
} else {
perror("get shareMemory error4");
//exit(EXIT_FAILURE);
}
//创建信号量
int temp_semid_sub = getSem(sem_key+"sub");
if(temp_semid_sub < 0) {
//创建失败
temp_semid_sub = createSem_second(sem_key+"sub");
if(temp_semid_sub < 0) {
perror("create second sem error");
} else {
shm_point->sub_sem_id = temp_semid_sub;
}
} else {
//初始值
int temp_init_semid = initSem(temp_semid_sub, 0); // 发布者创建的信号量 对应生产者 初值为1
if(temp_init_semid < 0) {
perror("init sem error");
} else {
//赋初始值成功
shm_point->sub_sem_id = temp_semid_sub;
}
}
int temp_semid_pub = createSem(sem_key+"pub");
if(temp_semid_pub < 0) {
// //创建失败
// perror("create sem error");
//说明之前已经创建过,不需要init了
//重新创建一次
temp_semid_pub = createSem_second(sem_key+"pub");
if(temp_semid_pub < 0) {
perror("create second sem error");
} else {
shm_point->pub_sem_id = temp_semid_pub;
}
}
else {
//初始值
int temp_init_semid = initSem(temp_semid_pub, 1); // 发布者创建的信号量 对应生产者 初值为1
if(temp_init_semid < 0) {
perror("init sem error");
} else {
//赋初始值成功
shm_point->pub_sem_id = temp_semid_pub;
}
}
cout<<"sem: "<<sem_key<<" "<<shm_point->sub_sem_id<<" "<<shm_point->pub_sem_id<<endl;
return shm_point;
}
void unMap(const MemoryDefinition* definition)
{
//size_t write_size = sizeof(ExampleList);
shmdt(definition->point);
// cout << "...Finish unmap share Memory and close the normal file!" << endl;
}
并且实践中发现:当一对多时,无需开辟多块内存空间,可以公用一块,只开多对信号量即可。
并且在项目中使用配置文件,设置本次项目启动后,一对多的信号量中哪些需要开启。
接收端:
接收完毕:
发布端:
2、测试雷达+雷达驱动测试
首先使用rslidar的ros版本驱动测试雷达的正确性。
需要雷达和板子在一个局域网下,给板子配置静态IP。连接后启动驱动,结果:
之后修改驱动:进行去除ros代码、修改cmake文件
重新编译、调bug后,调试成功:
安装参考:https://blog.csdn.net/weixin_53073284/article/details/122680587
3、总体测试
整个智能车系统的流程如下:
目前由于条件收到限制,所以现在的测试在上述中进行简化:
- 原始数据采集由数据包提供
- 下发速度那里暂不测试
- 上位机控制端尚未完善,暂不测试
- 数据部分由于数据包中的车道线信息无,所以单独测试
之后按照上述流程进行进一步测试。
技术难点
整合项目
bug记录
没啥大bug
其他
无