ROS-Vicon-Crazypony通信

ROS-Serial-Crazypony通信

从第二次开始学ros到成功进行串口通信,读取vicon数据,再将高度信息发送给crazypony花了差不多十天的时间,最后的主控程序其实很短很短,但是终于能完成最基本的功能了,可喜可贺可喜可贺:)。

首先写出代码

#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     <iostream>
#include     <pthread.h>
#include     <cstdlib>
#include     <string.h>

#include     <ros/ros.h>
#include     <std_msgs/String.h>
#include     <sstream>
#include     <vicon_bridge/Marker.h>
#include     <geometry_msgs/TransformStamped.h>
#include     <geometry_msgs/Transform.h>
#include     <geometry_msgs/Vector3.h>
#include     <geometry_msgs/Quaternion.h>


using namespace std;

int fd=open( "/dev/ttyUSB0", O_RDWR|O_NOCTTY|O_NDELAY);
int nread;
char buff[512];
char tempbuff[512];
int buffnum=0;
char test;
char tempone;  //临时字符,用做通信协议
char temptwo;
int status;
int flag=0;


void *tx(void*)
{
    while(1)
    {
        if(fscanf(stdin,"%c",&test)>0)
            {   
            printf("write\n");
            if(test=='s')
            {
                flag=1;
                close(fd);
                printf("Exit Tx");
            }
            tempone='c';
            write(fd,&tempone,1);
                write(fd,&test,1);
            tempone='s';
            write(fd,&tempone,1);
            }
    }
    printf("Exit Tx");
}

void *rx(void*)
{
    int i=0;
     while(flag==0)
     {
         if((nread=read(fd,buff,512))>0)
             {
            printf("%s\n",buff);
            for(i=0;i<nread;i++)
            {
                tempbuff[buffnum]=buff[i];
        //      printf("%s\n",tempbuff);
                buffnum++;
                if(tempbuff[buffnum-1]=='!')
                {
        //          printf("%s\n",tempbuff);
                    tempbuff[0]='\0';
                    buffnum=0;
                }
            }
         }
          }
    
     printf("Exit Rx");
}

int height;
void callback(const geometry_msgs::TransformStamped& msg)
{
    //测试用,Z是高度,于实际同号
    //printf("translation.x %f  ",msg.transform.translation.x);
    //printf("translation.y %f  ",msg.transform.translation.y);
    //printf("translation.z %f\n",msg.transform.translation.z);
    height=(int)(msg.transform.translation.z*100.0);
    //printf("send %d,height %f\n",height,height/100.0);
    temptwo='h';
    write(fd,&temptwo,1);
    write(fd,&height,1);
    temptwo='s';
    write(fd,&temptwo,1);
}


void *spin(void*)
{
    ros::spin();
}

int main(int argc,char **argv)
{
    //打开串口
    int count;
    printf("begin\n");
    if (fcntl(fd,F_SETFL,0)<0)
    { 
        perror(" 提示错误!\n"); 
        return 1;
    }
    else
        printf("success open USB0\n");
    //设置串口,termios.h中定义了终端控制结构体和POSIX控制函数
    if(0==isatty(STDIN_FILENO))
    {
        printf("standard input is not terminal device\n");
        return 1;
    }
    
    struct termios options;
    tcgetattr(fd, &options);
    //set speed
    cfsetispeed(&options, B115200);
    cfsetospeed(&options, B115200);

    //保证程序不会成为端口所有者
    options.c_cflag |= (CLOCAL | CREAD);

    //无校验,8位
    options.c_cflag &= ~PARENB;  
    options.c_cflag &= ~CSTOPB;
    options.c_cflag &= ~CSIZE;
    options.c_cflag |= CS8;

    options.c_cflag &= ~CRTSCTS;  //不使用流控制

    options.c_iflag &= ~INPCK;  

    //原始模式通信
    options.c_lflag  &= ~(ICANON | ECHO | ECHOE | ISIG);  //原始数据输入
    options.c_oflag  &= ~OPOST;   //原始数据输出

    tcflush(fd,TCIFLUSH);  //数据溢出时接受数据但不读取

        tcsetattr(fd,TCSANOW,&options);
        status=tcsetattr(fd,TCSANOW,&options);
    if(status!=0)
    {
        perror("com set error");
        return 1;
    }
    
    pthread_t tids[3];  
    //ROS 订阅发布消息 
    ros::init(argc,argv,"CP_Posture");  
    ros::NodeHandle n;
    ros::Publisher chatter_pub=n.advertise<std_msgs::String>("posture",1000);
    ros::Subscriber sub=n.subscribe("vicon/CP1_1/CP1_1",1000,callback);
    ros::Rate loop_rate(1);
        

    
    int retRx=pthread_create(&tids[0],NULL,rx,NULL);
    int retTx=pthread_create(&tids[1],NULL,tx,NULL);    
    int retSub=pthread_create(&tids[2],NULL,spin,NULL); 
        
    while(1)
    {
        if(ros::ok)
        {
            //printf("hello\n");
            count++;
            std_msgs::String msg;
            std::stringstream ss;
            ss << "hello" << count;
            msg.data = ss.str();
                        
            chatter_pub.publish(msg);
            loop_rate.sleep();
            ros::spinOnce();
        }
    }

    
    //异常检测
    if(retRx!=0)
    {
        printf("retRX error\n");
    }
    if(retTx!=0)
    {
        printf("retTX error\n");
    }
    
    pthread_exit(NULL); 

    close(fd);
return 0;
}   

代码流程

mian函数:

初始化串口设置:115200B,8位数据位,无控制流,无校验,这个程序在很多人的博客已经写到了,我 仅仅写出了与我的无人机匹配的设置模式,没有其他设置模式的代码。

打开了三个线程:RX用于读取串口,TX用于写串口,Sub用于订阅vicon节点并且通过无线发送,之所于 要使用者三个线程,我的想法是因为read函数、write函数、ROSmsg函数都要写到循环里,但是如果写到一个函数里就会陷入等待中,所以我开了一个线程专门用来读缓冲区,一个线程等待输入,第三个线程是因为ros::spins会一直自循环,所以额外开了一个线程并把功能都写入了回调函数。

关于是开多线程还是利用ROS的优势使用topic通信进行控制,我的考虑是因为fd这个文件指针会被占用,所以应该把write和read写进一个程序,这样控制程序也自然应写在同一个函数,但是因为我完全没有学习过C++,也对串口的API细节不了解,所以也并不确定。

有一个要注意的点是要记得及时销毁文件指针,在*rx和*tx里我使用test和flag就是想要控制销毁该指针(但是最后的结果很奇怪,在我输入s后tx确实不再写串口也打印了Tx Exit,但是但我输入时仍然会打印write),如果不及时销毁,直接关闭终端会使ttyUSB0被占用(我也不确定是不是被占用,因为我在/dev/里找不到ttyUSB0了,只有ttyUSB1,如果继续使用ttyUSB1,那么下一次dev里就只有ttyUSB2了)

最后,整个过程中最蛋疼的一点是,我使用crazypony做地面站时,怎么都无法串口通信,我检查程序检查驱动一切都似乎没有问题,然后我尝试把地面站程序移植到了一块开发板,就直接可以通信了。我猜想是因为cp2102驱动的问题(虽然我系统显示我驱动没问题),开发板是ch340的就直接可以用了。真的有毒。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,100评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,308评论 3 388
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,718评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,275评论 1 287
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,376评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,454评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,464评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,248评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,686评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,974评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,150评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,817评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,484评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,140评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,374评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,012评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,041评论 2 351

推荐阅读更多精彩内容

  • 姓名:莫益彰 学号:16030140019 【嵌牛导读】:串口通信是指外设和计算机间,通过数据信号线 、地线、控制...
    换个名字消消毒阅读 1,584评论 1 5
  • *面试心声:其实这些题本人都没怎么背,但是在上海 两周半 面了大约10家 收到差不多3个offer,总结起来就是把...
    Dove_iOS阅读 27,138评论 30 470
  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,944评论 25 707
  • 这里并不对串口的编程作讲解,主要是从应用的角度去讲一讲。因为更多的时候,都是产品做好了,比如触摸屏需要和控制器,P...
    我是嘻哈大哥阅读 4,035评论 1 9
  • 认识小玫的时候,我十五岁,她也十五岁。那年我住在外婆家,也在那边念中学,知道高考结束才回自己家。那期间,小玫就是我...
    蔓蔓幔青萝阅读 892评论 0 1