MT7688双摄像头双电机驱动小车(6)应用软件

关于这篇主要是运行在MT7688上的应用程序的实现。

这部分程序很早之前写的,后来没想到要放出来,所以一开始也没什么设计可言,就是想到哪里写哪里。最后为了能拿的出手,代码改了一部分,还有一部分因为懒,就都没改了,所以算一个四不像体。如果要改很多地方要做重构,电脑配置和时间有限就跳过这一步。
多亏叽叽叽老司机提醒,终于不输出只输出到终端了,有的以日志形式输出。这样即使后台运行也可以看到状态了。但是转化太麻烦就省略了= =

主目录:

http://blog.csdn.net/DFSAE/article/details/78715815


本篇目录

一.设计

二.实现

1.线程实现
2.socket通信
3.通信协议的打包和解析
4.电机控制
5.摄像头控制
6.串口转发控制

三.makefile解析

四.编译,运行

五.设置为上电启动


一.设计

这里没有具体的设计,只有大概的设计思路。
整个软件分为5个部分,包括电机控制,摄像头控制,串口转发控制这三部分底层和socket网络通信,协议的打包及解析这里通信部分。
大概存在3个线程:socket通信线程,电机控制线程和连接超时线程(这个本来想用定时器的,但是没找到定时器的依赖库= =)。

1>.socket通信线程

程序主要在socket线程的监听上位机发送下来的数据中度过。当收到数据后进行解析。然后执行响应的动作。应用软件最核心的部分就在这里了。另外这里的电机操作正常情况是需要分开来的,后面解释为什么,如果做一起就说明比较懒了。

2>.电机控制线程

这个线程里面处理上位机发下来的电机控制信号,实现对电机的输出。这就是操作分离开来的部分,后面有详细解释。

3>.连接超时线程

其实就是一个定时器的功能,保证在一定时间没有接收上位机数据(连接断开)后,重新进行socket监听,以便进行新的连接。正常情况下,上位机应该隔一段时间就发下连接数据,以免断开连接。

*注:另外,这里IP地址暂时先定死,由前面的配置的ip为准:192.168.55.1,默认端口号为1234。两个摄像头的端口号分别为8090和8070。

二.实现

自顶向下开始分析实现。
注:这里要现在用命令行建一个car_server的文件夹,里面放个car_server.log的日志文件。

1.线程实现

在main函数里开启了3个线程:

err = pthread_create(&socket_th_id, NULL, socketListen_thread, NULL);   
err = pthread_create(&moter_th_id, NULL, moterControl_thread, NULL);
err = pthread_create(&timer_th_id, NULL, timer_thread, NULL);

socket监听线程中做的事情:判断是否掉线?如果掉线,开启socket监听,等待再次连接。其中car_recvAnalysisCmd函数在没有收到数据时其实是阻塞的。

/*************************************************
* 函数名: socketListen_thread
* 说明:scoket监听线程。
* 输入参数:
* 输出参数:
**************************************************/
void * socketListen_thread(void * arg)   
{  
    system("echo start socket listen thread! >> /car_server/car_server.log");
    printf("start socket listen thread!\n");  
    while (1)   
    {  
        //如果处于未连接状态,进行socket监听连接
        if (get_carLinkStatus(car) == Car_Link_Disconnet)
        {
   
            system("echo remote link! >> /car_server/car_server.log");
            car_waitRemoteLink(car);
        }

        car_recvAnalysisCmd(car);//接受数据

        usleep(2000);    
    }  
    return (void *)0;  
}  

电机控制线程,20ms执行一次控制。(目前采用直接控制的方式了)

/*************************************************
* 函数名: moterControl_thread
* 说明:电机控制线程。
* 输入参数:
* 输出参数:
**************************************************/
void * moterControl_thread(void * arg)   
{
    system("echo start moter control thread! >> /car_server/car_server.log");
    printf("start moter control thread!\n");  
    while (1)
    {
   
        //电机控制20ms一次
        usleep(20000);   
    }
}

该线程是用来判断连接超时的。

/*************************************************
* 函数名: timer_thread
* 说明:电机控制线程。
* 输入参数:
* 输出参数:
**************************************************/
void * timer_thread(void * arg)  
{
    system("echo start timer thread! >> /car_server/car_server.log");
    printf("start timer thread!\n");  
    while (1)
    {   
        car_linkTimeoutDece(car);
        //判断失去连接,清空电机参数列表,并停车
        sleep(1);   
    }
} 

2.socket通信

socket基础操作参考:http://c.biancheng.net/cpp/html/3030.html
socket.h里定义了一堆宏,来定义连接的IP和端口。默认数据端口为1234。

/*! 本机服务器IP及通信端口号  */
#define     SERVER_IP                "192.168.55.1"
#define     SERVER_DATA_PORT         1234
#define     SERVER_CAMERA_PORT1      8070
#define     SERVER_CAMERA_PORT2      8090    

socket部分封装了基础的socket通信,比如连接,断开,接收数据,发送数据等,具体代码如下:

/*************************************************
* 函数名:socket_send
* 说明:发送socket数据
* 输入参数:sInfo
*          dataBuff         发送缓冲
*          size             发送长度
* 输出参数:错误号
**************************************************/
SocketErrNo socket_send(const SocketInfo * const sInfo, 
                            const unsigned char *dataBuff, int size)
{
    if (write(sInfo->clnt_sock, dataBuff, size) == -1)
    {
   
        socket_err_deal(Send_Err);
        return Send_Err;
    }
    return No_Err;
}

/*************************************************
* 函数名:socket_recv
* 说明:接收socket数据
* 输入参数:sInfo
*          dataBuff     接收数据缓冲
*          size         接受长度
* 输出参数:错误号
**************************************************/
SocketErrNo socket_recv(const SocketInfo * const sInfo, 
                    unsigned char *dataBuff, int size, int *ret_size)
{   
    if ((*ret_size = read(sInfo->clnt_sock, dataBuff, size)) == -1)
    {
   
        socket_err_deal(Recv_Err);
        return Recv_Err;
    }
    return No_Err;
}

/*************************************************
* 函数名:socket_close
* 说明:关闭socket
* 输入参数:sInfo      
* 输出参数:错误号
**************************************************/
SocketErrNo socket_close(const SocketInfo * const sInfo)
{
    //关闭套接字
    close(sInfo->clnt_sock);
    close(sInfo->serv_sock);
    return No_Err;
}

/*************************************************
* 函数名:socket_listen
* 说明:关闭socket
* 输入参数:sInfo      
* 输出参数:错误号
**************************************************/
void socket_listen(SocketInfo * const sInfo)
{
    socklen_t clnt_addr_size;
    struct sockaddr_in clnt_addr;
#ifdef SOCKET_ERROR_PRINT
    static unsigned int link_t = 0; 
#endif  
    //进入监听状态,等待用户发起请求
    listen(sInfo->serv_sock, 20);

    //接收客户端请求
    clnt_addr_size = sizeof(clnt_addr);
    sInfo->clnt_sock = accept(sInfo->serv_sock, (struct sockaddr*)&clnt_addr, &clnt_addr_size);

#ifdef SOCKET_ERROR_PRINT
    link_t++;
    pri
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值