rm记录第三阶段(完):多线程学习,及其调用相机及其处理,串口学习-------及其最后总结:RM2021 see you!

Posted 神佑我调参侠

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了rm记录第三阶段(完):多线程学习,及其调用相机及其处理,串口学习-------及其最后总结:RM2021 see you!相关的知识,希望对你有一定的参考价值。

上一篇文章也是成功的用opencv调用了对象,那么下一步就是用多线程来使用相机了:

多线程学习:

以前也是学习过了,但是现在也忘的差不多了,那就在学习一次。其实我感觉我最好可以过一遍操作系统,因为我不是计算机专业的吗,然后系统的学又没那么多时间,所以的话真的想要以后考研的时候可以考408然后补一下这方面的知识。现在开始:

首先在CmakeLists.txt中要加入这几行代码:

find_package(Threads)
target_link_libraries(main ${CMAKE_THREAD_LIBS_INIT})

然后开始吧:先看下几个多线程的例子,然后的话我们先感受一下:(这里说个小插曲吧,其实啥呢,我其实真的最近对其有些懈怠,但是学长说我的意识,不要完全不去想这些东西,可以去学习,但是不要完全不去管这些,rm的程序马上要解决了,下一步的话,赶紧准备智能车吧,我现在感觉对传统视觉有了大体的认识了,但是对机器学习还是不行,要开始准备了,然后的话就是多线程和接下来的串口也是我们在智能车时肯定会用到的,怎么说呢,今天也是在寝室待了几个点,感受很深呀,怎么说呢,舍友的话令我印象深刻,你想得到的更多,那就得付出更多,就得花费更多的时间,是呀,那就来吧!)

在此之前我们先看下这个:

int pthread_create(pthread_t *restrict tidp,const pthread_attr_t *restrict attr, void *(*start_rtn)(void),void *restrict arg);

    返回值:若是成功建立线程返回0,否则返回错误的编号
    形式参数:
                pthread_t *restrict tidp 要创建的线程的线程id指针
                const pthread_attr_t *restrict attr 创建线程时的线程属性
                void* (start_rtn)(void) 返回值是void类型的指针函数
                void *restrict arg   start_rtn的行参

一会结和例子说一下:

#include <iostream>
#include"stdio.h"
// 必须的头文件
#include <pthread.h>
 
using namespace std;
 
#define NUM_THREADS 5
 
// 线程的运行函数
void* say_hello(void* args)
{
    cout << "Hello Runoob!" << endl;
    return 0;
}
 
void delay(){
    for(int i= 0 ;i<50000;i++){
        for(int j=0;j<30000;j++);
    }
}

int main()
{
    // 定义线程的 id 变量,多个变量使用数组
    for(int i = 0;i<2;i++){
    pthread_t tids[NUM_THREADS];
    for(int i = 0; i < NUM_THREADS; ++i)
    {
        //参数依次是:创建的线程id,线程参数,调用的函数,传入的函数参数
        int ret = pthread_create(&tids[i], NULL, say_hello, NULL);
        if (ret != 0)
        {
           cout << "pthread_create error: error_code=" << ret << endl;
        }
    }
    delay();
    }
    //等各个线程退出后,进程才结束,否则进程强制结束了,线程可能还没反应过来;
    pthread_exit(NULL);
}

看这个例子的话,就很明显,是一下子打印出来5行,然后的话说一下这个代码,是最基本的了,首先记住我们建立的函数是指针类型的,然后一个延时函数,先定义线程的id,然后的话就是对每个线程id建立线程,最后退出。

然后我们结合工业相机试一下:然后这里有个细节,就是我们的建立的那个指针函数括号里一定要写那些东西,否则就会报错。

然后也行了,太简单我就先不写了,然后后期的话加上处理再说!

那么现在要做的就是在我们的那个最终程序中实现一下 :就是先改写程序。

然后的话我拍了一些棋盘格,但是标定出来的和吉大的咋差那么多呢,但是我感觉我的应该是对的。先放上看看。

现在的话已将将原来的获取视频换成了我们刚才的用工业相机获取了,然后下一步看看什么个方法去和处理图像相连,因为第一步的话就是必须先出图像才能处理嘛,就是要处理下这个地方的多线程编写。


串口学习

然后我发现我的帧率超高,感觉都不用加速了,然后呢就差最后一步了,串口,解决的话,我的2021RM就结束了呀!

然后的话,就是我借鉴了一个文章,其实网上的串口的程序已经非常多了,我可以直接拿来用,我试试看。在此之前我还是想先找到一下妙算2的串口是哪个!那我直接就照我那个rm的代码改吧,试试看!

我一定可以成功的!

我记得我以前说了一些,但是也没有说多少,重新开始一遍:

肯定的是我们这里有一个.c和一个.h文件,然后的话我们去建个文件夹学起:

那么按照我们一直的习惯,先从.hpp文件看起:

#ifndef  _USART_H
#define  _USART_H
 
//串口相关的头文件    
#include<stdio.h>      /*标准输入输出定义*/    
#include<stdlib.h>     /*标准函数库定义*/    
#include<unistd.h>     /*Unix 标准函数定义*/    
#include<sys/types.h>     
#include<sys/stat.h>       
#include<fcntl.h>      /*文件控制定义*/    
#include<termios.h>    /*PPSIX 终端控制定义*/    
#include<errno.h>      /*错误号定义*/    
#include<string.h>    
     
     
//宏定义    
#define FALSE  -1    
#define TRUE   0
extern int UART0_Open(int fd,char*port);
extern void UART0_Close(int fd) ;
extern int UART0_Set(int fd,int speed,int flow_ctrl,int databits,int stopbits,int parity);
extern int UART0_Init(int fd, int speed,int flow_ctrl,int databits,int stopbits,int parity) ;
extern int UART0_Recv(int fd, char *rcv_buf,int data_len);
extern int UART0_Send(int fd, char *send_buf,int data_len);
//串口主函数
int Serial(int yaw,int pitch,bool fire,bool find);
#endif

这里面的头文件啥的就不说了,然后就是有这些函数,不过话说为啥前面要加那个东西呀!extern是啥呀!感觉以前见过,但是记不得了。

参考:https://www.cnblogs.com/yc_sunniwell/archive/2010/07/14/1777431.html

学起来:(然后又来新任务了,就是还是)

extern可以置于变量或者函数前,以标示变量或者函数的定义在别的文件中,提示编译器遇到此变量和函数时在其他模块中寻找其定义。

然后的话就是定义了下面的几个函数:然后最后的那个是集成的主函数。

等下,我这里有个疑惑,就是妙算的串口会引出4跟线,哪个是tx和rx呀,然后刚才查了一下,反正中间那两肯定是,倒是不行就换一下。

然后的话就是看一下这个open的函数:

/*******************************************************************
*名称:             UART0_Open
*功能:             打开串口并返回串口设备文件描述
*入口参数:         fd      文件描述符
                    port    串口号(ttyTHS0,ttyTHS1,ttyTHS2)
*出口参数:正确返回为1,错误返回为0
*******************************************************************/
int UART0_Open(int fd,char*port)
{
    fd = open( port, O_RDWR|O_NOCTTY|O_NDELAY);
    if (fd<0)
    {
        perror("Can't Open Serial Port");
        return(FALSE);
    }
    //恢复串口为阻塞状态
    if(fcntl(fd, F_SETFL, 0) < 0)
    {
        printf("fcntl failed!\\n");
        return(FALSE);
    }
    else
    {
        printf("fcntl=%d\\n",fcntl(fd, F_SETFL,0));
    }
    //测试是否为终端设备
    if(0 == isatty(STDIN_FILENO))
    {
        printf("standard input is not a terminal device\\n");
        return(FALSE);
    }
    else
    {
        printf("isatty success!\\n");
    }
    printf("fd->open=%d\\n",fd);
    return fd;
}

就是返回一个文件描述符,然后根据这个fd来进行下一步的操作,这个没啥说的。

有开就有关,看下这个关的:

void UART0_Close(int fd)
{
    close(fd);
}

比开的简单多了,然后下面这个就非常重要了。

这里的话,先说一下传输数据的构成吧,反正我写的话,就是会用到两个校验位,首尾各一个,一会我写的时候肯定会对上面的做更改,这个一会再说先看看这个。

我去看了一圈也没弄懂那个set的文件,我吐了,太复杂了,我还是直接应用吧(主要是有点)

/*******************************************************************
*名称:             UART0_Set
*功能:             设置串口数据位,停止位和效验位
*入口参数:         fd          串口文件描述符
*                   speed       串口速度
*                   flow_ctrl   数据流控制
*                   databits    数据位   取值为 7 或者8
*                   stopbits    停止位   取值为 1 或者2
*                   parity      效验类型 取值为N,E,O,,S
*出口参数:正确返回为1,错误返回为0
*******************************************************************/
int UART0_Set(int fd,int speed,int flow_ctrl,int databits,int stopbits,int parity)

初始化一下:

/*******************************************************************
*名称:                UART0_Init()
*功能:                串口初始化
*入口参数:            fd         文件描述符
*                      speed      串口速度
*                      flow_ctrl  数据流控制
*                      databits   数据位   取值为 7 或者8
*                      stopbits   停止位   取值为 1 或者2
*                      parity     效验类型 取值为N,E,O,,S
*
*出口参数:正确返回为1,错误返回为0
*******************************************************************/
int UART0_Init(int fd, int speed,int flow_ctrl,int databits,int stopbits,int parity)
{
    int err=0;
    //设置串口数据帧格式
    if (UART0_Set(fd,115200,0,8,1,'N') == FALSE)
    {
        return FALSE;
    }
    else
    {
        return  TRUE;
    }
}

然后看下发送的函数:

int UART0_Send(int fd, char *send_buf,int data_len)
{
    int len = 0;

    len = write(fd,send_buf,data_len);
    if (len == data_len )
    {
        printf("send data is %s\\n",send_buf);
        return len;
    }
    else
    {

        tcflush(fd,TCOFLUSH);
        return FALSE;
    }

}

就这样了吧,其实在最后的几天也是才得知这次我们的队伍用不上视觉了,然后呢,后面的也是不想在优化了,然后回顾一下吧!

我是从寒假才开始准备的,可以说是0基础了,几乎所有的东西都是现学的,期间也是有各种各样的问题,但是也是感谢自己一路走了过来,现在也是对其有了大体上的了解了,很感谢一直分享的大家,然后感谢吉大的开源代码,我的2021rm也就结束了,然后比赛我也是帮不上什么了,因为呢我们队伍没有用视觉,因为时间来不及联调了,然后的话,其实就是到现在我还说无法将所有的代码看明白,只能说是能实现出来,其实大多数还是借鉴,这么长时间过去了,自己真的也是成长了不少,只能说,明年再来了,明年的话就得实现对装甲板的自瞄了,到时估计肯定还有新的东西,其实想回顾也很简单,就从第一个博客看起嘛,看到这个就行了,这也就是最好的结果了,可能现在还不是很理想,但是我也要成长下去呀。去挑战下一个去吧,智能车!只要我在学习,我就在成长,我会变的更强的!

 

 

 

 

 

 

 

 

 

 

 

以上是关于rm记录第三阶段(完):多线程学习,及其调用相机及其处理,串口学习-------及其最后总结:RM2021 see you!的主要内容,如果未能解决你的问题,请参考以下文章

rm记录第三阶段:海康威视工业相机的使用,cmake的复习

Java第三阶段学习(多线程)

多线程高并发之Synchronized锁及其膨胀

第三章--Win32程序的执行单元(部分概念及代码讲解)(上 -- 多线程)

java面试题,15个java多线程面试题及答案

15个java多线程面试题及回答