本帖最后由 jeffc_good 于 2017-7-18 20:18 编辑
想用NanoPi Neo2做个智能小车,用来远程监视。根据手上现有的器件、模块等,基本上实现了预期的效果。从搭建小车硬件,熟悉NanoPi Neo2,实现功能等,友善之臂提供了丰富的资源,所以开发起来非常迅速,可以省很多时间,非常喜欢这种尺寸小,性能高,开发方便的设定。搭建小车硬件费了点时间,但是效果自己还是挺满意的。当然可以直接买现成的,自己做硬件一是想将手上的东西用起来,再就是想自己折腾一下,享受这个过程。有了智能小车这个平台,就可以熟悉板子、验证功能等等。我感觉,实现一个智能小车等同于嵌入式的hello world。
系统硬件的基本结构如下图所示。
NanoPi Neo2上面没有无线模块,我感觉这是对我而言比较遗憾的,可能NanoPi Neo Plus2更适合我预期的效果,不过,幸亏手上有无线模块HLK-RM04,这个模块主要是实现串口与无线之间的转换,在默认模式下,无线是AP模式,LAN作为其一个IP点,因此,我的思路是,将模块设置为默认模式,将NanoPi Neo2通过网口连接到HLK-RM04的LAN上,将其接在HLK-RM04的局域网下,设置NanoPi Neo2为静态IP,就可以在将笔记本电脑连上HLK-RM04创建的无线,来实现控制PC和NanoPi Neo2的通讯。USB摄像头通过板子上唯一的USB口连接,因为板子上有 mjpg-streamer网络视频流服务器,因此,如果想直接看视频,可以非常方便的实现。超声波测距传感器通过GPIO口连接,用来测小车前后障碍物的距离,距离过近,直接停止,保证小车的安全,模块型号是HC-SR04,使用起来很方便,可以参考我前面的帖子。TB6560驱动器驱动步进电机,接口NanoPi Neo2给的脉冲和方向控制信号。声音传感器和人体红外传感器作为搭载传感器,判断小车周围是否有声音动静,是否有人。 这些模块用到的电压是24V以及5V,TB6560驱动模块的驱动电压是24V,NanoPi NEO2和HLK-RM04模块都用的是5V电压。因此主电源用一个24V锂电池,然后通过DC-DC转换模块转换为5V,24V电压给TB6560使用,5V给NanoPi NEO2和HLK-RM04模块使用。实现结构如下图所示。
最终做出来的小车照片如下所示。
这是小车底盘,亚克力板是在淘宝上加工的。
板子内软件实现采用C语言,上位机采用Qt编程。先说小车里面的实现。
传感器模块、驱动模块都是用GPIO实现的,直接用系统自带的wiringPi编程,可以很容易实现GPIO的控制。也用到了TCP通讯,所以包含socket编程,各个模块的工作相对独立,除了主线程外,又创建了7个线程。7个线程分别如下所示。
主线程除了创建各个线程外,还需要建立起socket通讯,当有客户端连接后才建立的发送数据线程以及传感器线程。因为这两个线程需要用到通讯的功能。主线程代码如下所示。
- int main(int argc, char *argv[])
- {
- int sockfd;
- struct sockaddr_in server_addr;
- struct sockaddr_in client_addr;
- int sin_size;
- char buf[100];
-
- pthread_t thread_left;
- pthread_t thread_right;
-
- pthread_t thread_hcsr04_forward;
- pthread_t thread_hcsr04_backward;
-
- pthread_t thread_safety;
-
- int temp;
- memset(&thread_left, 0, sizeof(pthread_t));
- memset(&thread_right, 0, sizeof(pthread_t));
- memset(&thread_hcsr04_forward, 0, sizeof(pthread_t));
- memset(&thread_hcsr04_backward, 0, sizeof(pthread_t));
- memset(&thread_safety, 0, sizeof(pthread_t));
-
- wiringPiSetup();
- /*创建线程*/
-
- if((temp = pthread_create(&thread_left, NULL, motor_thread_left, NULL)) != 0) //comment2
- printf("left motor线程创建失败!n");
- else
- printf("left motor线程被创建n");
- if((temp = pthread_create(&thread_right, NULL, motor_thread_right, NULL)) != 0) //comment2
- printf("right motor线程创建失败!n");
- else
- printf("right motor线程被创建n");
-
- if((temp = pthread_create(&thread_hcsr04_forward, NULL, hcsr04_forward_thread, NULL)) != 0)
- printf("hcsr04_forward_thread线程创建失败!n");
- else
- printf("hcsr04_forward_thread线程被创建n");
-
- if((temp = pthread_create(&thread_hcsr04_backward, NULL, hcsr04_backward_thread, NULL)) != 0)
- printf("hcsr04_backward_thread线程创建失败!n");
- else
- printf("hcsr04_backward_thread线程被创建n");
-
- if((temp = pthread_create(&thread_safety, NULL, safety_thread, NULL)) != 0)
- printf("safety_thread线程创建失败!n");
- else
- printf("safety_thread线程被创建n");
-
- /*用默认属性初始化互斥锁*/
- pthread_mutex_init(&mut,NULL);
- sockfd = socket(AF_INET,SOCK_STREAM,0);
- if(sockfd == -1)
- {
- fprintf(stderr,"Socket error:%sn",strerror(errno));
- exit(1);
- }
-
- bzero(&server_addr,sizeof(struct sockaddr_in));
- server_addr.sin_family = AF_INET;
- server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
- server_addr.sin_port = htons(PORT);
- int on=1;
- setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on)); //上次(1)篇没解释,其实这个就是阻止服务端一关掉,再启动,运行不了的情况发生
- if(bind(sockfd,(struct sockaddr *)(&server_addr),sizeof(struct sockaddr_in))==-1)
- {
- fprintf(stderr,"Bind error:%sn",strerror(errno));
- exit(1);
- }
-
- if(listen(sockfd,20)==-1)
- {
- fprintf(stderr,"listen error:%sn",strerror(errno));
- exit(1);
- }
- int new_fd,res2;
- int r_size;
-
- pthread_t thread_write; //线程id,即线程标识符
- pthread_t thread_sensor; //传感器上传线程
- while(1)
- {
- printf("wait for connection!!!!!n");
- memset(buf,0,100);
- sin_size = sizeof(struct sockaddr_in);
- if((new_fd=accept(sockfd,(struct sockaddr *)(&client_addr),&sin_size))==-1)
- {
- fprintf(stderr,"Accept error:%sn",strerror(errno));
- exit(1);
- }
- else
- {
- fprintf(stderr,"Server get connection from %sn",inet_ntoa(client_addr.sin_addr));
- res2=pthread_create(&thread_write,NULL,thrd_write,new_fd); //创建线程
- if(res2!=0)
- {
- perror("Pthread2 create failn");
- exit(res2);
- }else{
- printf("Pthread2线程被创建n");
- }
-
- res2=pthread_create(&thread_sensor,NULL,sensor_thread,new_fd); //创建线程
- if(res2!=0)
- {
- perror("sensor_thread create failn");
- exit(res2);
- }else{
- printf("sensor_thread线程被创建n");
- }
-
- while(1) //读取客户端信息
- {
- char buf[100];
- if((r_size=read(new_fd,buf,100))==-1)
- {
- fprintf(stderr,"Read error:%sn",strerror(errno));
- exit(1);
- }
- printf("Server Received%d::%sn",r_size,buf);
- pthread_mutex_lock(&mut);
- motor_control(buf);
- pthread_mutex_unlock(&mut);
- memset(buf,0,100);
- }
- }
- }
- close(sockfd);
- exit(0);
- }
复制代码
发送数据线程没有用,只是预留一下,用来从板子发送数据到上位机。
- void *thrd_write(void *arg) //写线程
- {
- int sockfd=(int)arg; //传进来的客户端端口
- char buf[100];
- while(1)
- {
- fgets(buf,100,stdin); //从屏幕得到你输入的字符
- if(write(sockfd,buf,sizeof(buf))<0) //写功能
- {
- fprintf(stderr,"write Error:%san",strerror(errno));
- exit(1);
- }
- }
- pthread_exit(NULL); //线程退出
- }
复制代码
传感器线程根据传感器采集的信息更新给上位机。
- void *sensor_thread(void *arg)
- {
- int sockfd=(int)arg; //传进来的客户端端口
- char buf[100];
- pinMode(HC_SR501,INPUT);
- pinMode(SOUND_SENS,INPUT);
- delayMicroseconds(1000000);
- while(1)
- {
- if(digitalRead(HC_SR501))
- {
- strcpy(buf,"PEOPLE");
- }
- else{
- strcpy(buf,"NONP");
- }
- if(write(sockfd,buf,sizeof(buf))<0) //写功能
- {
- fprintf(stderr,"write Error:%san",strerror(errno));
- exit(1);
- }
- delayMicroseconds(15000);
-
- if(digitalRead(SOUND_SENS))
- {
- strcpy(buf,"NONS");
- }
- else{
- strcpy(buf,"SOUND");
- }
- if(write(sockfd,buf,sizeof(buf))<0) //写功能
- {
- fprintf(stderr,"write Error:%san",strerror(errno));
- exit(1);
- }
- delayMicroseconds(15000);
- }
- pthread_exit(NULL); //线程退出
- }
复制代码
安全保障线程确保超声传感器测得的距离是安全距离,否则直接停止。
- void *safety_thread()
- {
- while(1)
- {
- if((distance_forward<10)||(distance_backward<10))
- {
- if(power_flag)
- {
- pthread_mutex_lock(&mut);
- motor_control("SPEED0");
- pthread_mutex_unlock(&mut);
- }
- }
- delayMicroseconds(10000);
- }
- pthread_exit(NULL); //线程退出
- }
复制代码
电机控制线程根据当前电机状态以及需要电机状态,控制电机转向、脉冲速率,生成脉冲控制电机。
- void *motor_thread_left()
- {
- printf ("motor_thread_leftn");
- motor_set(CW_LEFT,CLK_LEFT);
- motor_direction(CW_LEFT,LEFT_FORWARD);
- for(;;){
- if(Direction_left_changed!=Direction_left)
- {
- printf("Direction_left:%dn",Direction_left_changed);
- motor_direction(CW_LEFT,Direction_left_changed);
- Direction_left = Direction_left_changed;
- }
- if(Speed_left_changed!=Speed_left)
- {
- printf("Speed_left:%dn",Speed_left_changed);
- if(Speed_left_changed==0)
- Time_left = 0;
- else
- Time_left = 18750/Speed_left_changed;
- Speed_left = Speed_left_changed;
- }
- if(Time_left!=0)
- {
- digitalWrite(CLK_LEFT,HIGH);
- delayMicroseconds(Time_left);
- digitalWrite(CLK_LEFT,LOW);
- delayMicroseconds(Time_left);
- }else{
- delayMicroseconds(100);
- }
-
- }
- pthread_exit(NULL);
- }
复制代码
超声测距两个线程得到前后两个超声测距传感器的所得距离。
- void *hcsr04_backward_thread()
- {
- struct timeval tv1;
- struct timeval tv2;
- struct timezone tz;
- int i,pin_flag=0,get_flag=0;
- long long x,y;
- float distanse;
- //wiringPiSetup();
- pinMode(TRIG_B,OUTPUT);
- pinMode(ECHO_B,INPUT);
- digitalWrite(TRIG_B,LOW);
- for(;;)
- {
- distanse = 0;
- pin_flag = 0;
- digitalWrite(TRIG_B,HIGH);
- delayMicroseconds(30);//15us的触发
- digitalWrite(TRIG_B,LOW);//重新置低
- //等待100ms
- for(i=0;i<100000;i++)
- {
- if(digitalRead(ECHO_B))
- {
- if(!pin_flag)
- {
- pin_flag=1;
- gettimeofday(&tv1,&tz);
- }
- }else{
- if(pin_flag)
- {
- pin_flag=0;
- gettimeofday(&tv2,&tz);
- get_flag = 1;
-
- }
- }
- delayMicroseconds(1);
- }
- if(get_flag)
- {
- get_flag = 0;
- x=tv1.tv_sec*1000*1000+tv1.tv_usec;
- y=tv2.tv_sec*1000*1000+tv2.tv_usec;
- distanse = (float)(y-x)/58;//得到距离
- //printf("back distanse:%fn",distanse);
- delayMicroseconds(10000); //过10ms再检测
- distance_backward = distanse;
- }
-
- }
- pthread_exit(NULL);
- }
复制代码
上位机软件在qt中编写。主要是和NanoPi NEO2通讯,以及下发控制指令。包含两个界面,一个是小车控制界面,如下所示。小车Ip设置,速度设置,运动控制按钮,摄像头连接现实,传感器状态显示等等。
另一个界面是调试界面,就是个TCP调试窗口,用来调试通讯内容。用Qt实现TCP通讯还是很简单的。
主要代码如下。
- #include "carcontrol.h"
- /*
- * carcontrol的构造函数
- * @author jeff
- * @返回值:NULL
- */
- carcontrol::carcontrol(QWidget *parent, Qt::WFlags flags)
- : QWidget(parent, flags)
- {
- ui.setupUi(this);
- Init_Control_Window();
- Init_Debug_Window();
- }
- carcontrol::~carcontrol()
- {
- }
- /*
- * 初始化界面上的信息
- * @author jeff
- * @返回值:NULL
- */
- void carcontrol::Init_Control_Window()
- {
- Init_Connectstate_Control(); //连接状态初始化
- ui.lineEdit_IP_C_1->setText("192");
- ui.lineEdit_IP_C_2->setText("168");
- ui.lineEdit_IP_C_3->setText("16");
- ui.lineEdit_IP_C_4->setText("10");
- ui.lineEdit_speed->setText("10");
-
- QRegExp regExp1_c("[0-9]{1,3}");
- ui.lineEdit_IP_C_1->setValidator(new QRegExpValidator(regExp1_c, this));
-
- QRegExp regExp2_c("[0-9]{1,3}");
- ui.lineEdit_IP_C_2->setValidator(new QRegExpValidator(regExp2_c, this));
-
- QRegExp regExp3_c("[0-9]{1,3}");
- ui.lineEdit_IP_C_3->setValidator(new QRegExpValidator(regExp3_c, this));
-
- QRegExp regExp4_c("[0-9]{1,3}");
- ui.lineEdit_IP_C_4->setValidator(new QRegExpValidator(regExp4_c, this));
- ui.lineEdit_speed->setValidator(new QIntValidator(0, 200, this));
- control_tcpsocket = new QTcpSocket;
- html = new QWebView;
- connectstate_control = 0;
- connectstate_camera = 0;
- runstate_control = 0;
- //QWebSettings* defaultSettings = QWebSettings::globalSettings();
- //// We use JavaScript, so set it to be enabled.
- //defaultSettings->setAttribute(QWebSettings::JavascriptEnabled, true);
- //// Plug-ins must be set to be enabled to use plug-ins.
- //defaultSettings->setAttribute(QWebSettings::PluginsEnabled,true);
- //defaultSettings->setAttribute(QWebSettings::LocalContentCanAccessRemoteUrls,true);
- //defaultSettings->setObjectCacheCapacities(0, 0, 0);
- QGridLayout *layout = new QGridLayout;
- layout->addWidget(html, 0, 0, 1, 10);
- ui.widget_web->setLayout(layout);
- ui.horizontalLayout_27->setStretchFactor(ui.verticalLayout_5,1);
- ui.horizontalLayout_27->setStretchFactor(ui.verticalLayout_15,10);
- connect(ui.pushButton_conncect_car, SIGNAL(clicked()), this, SLOT(Connect_Car_Pushbutton_Clicked()));
- connect(ui.pushButton_conncect_camera,SIGNAL(clicked()),this,SLOT(Connect_Camera_Pushbutton_Clicked()));
- connect(ui.pushButton_start, SIGNAL(clicked()), this, SLOT(pushButton_start_clicked()));
- connect(ui.pushButton_start_forward, SIGNAL(clicked()), this, SLOT(pushButton_start_forward_clicked()));
- connect(ui.pushButton_start_backward, SIGNAL(clicked()), this, SLOT(pushButton_start_backward_clicked()));
- connect(ui.pushButton_start_left, SIGNAL(clicked()), this, SLOT(pushButton_start_left_clicked()));
- connect(ui.pushButton_start_right, SIGNAL(clicked()), this, SLOT(pushButton_start_right_clicked()));
- connect(control_tcpsocket, SIGNAL(error(QAbstractSocket::SocketError)), this,
- SLOT(control_Error_Robot(QAbstractSocket::SocketError)));
- connect(control_tcpsocket, SIGNAL(connected()), this, SLOT(control_connected_Socket())); //进行连接
- connect(control_tcpsocket, SIGNAL(disconnected()), this, SLOT(control_disConnected_Socket())); //断开连接
- connect(control_tcpsocket, SIGNAL(readyRead()), this, SLOT(control_ReadyRead_Socket())); //接收数据
- webtimer = new QTimer;
- webtimer->stop();
- connect(webtimer,SIGNAL(timeout()),this,SLOT(Connect_Camera()));
- }
- /*
- * 初始化界面上的信息(IP信息)
- * @author jeff
- * @返回值:NULL
- */
- void carcontrol::Init_Debug_Window()
- {
- Init_Connectstate(); //连接状态初始化
- ui.lineEdit_IP_1->setText("192");
- ui.lineEdit_IP_3->setText("168");
- ui.lineEdit_IP_4->setText("16");
- ui.lineEdit_IP_5->setText("10");
- ui.lineEdit_Port->setText("3333");
- ui.lineEdit_Robot_name->setText("NanoPi NEO2");
-
- QRegExp regExp("[0-9]{1,4}");
- ui.lineEdit_Port->setValidator(new QRegExpValidator(regExp, this));
-
- QRegExp regExp1("[0-9]{1,3}");
- ui.lineEdit_IP_1->setValidator(new QRegExpValidator(regExp1, this));
-
- QRegExp regExp2("[0-9]{1,3}");
- ui.lineEdit_IP_3->setValidator(new QRegExpValidator(regExp2, this));
-
- QRegExp regExp3("[0-9]{1,3}");
- ui.lineEdit_IP_4->setValidator(new QRegExpValidator(regExp3, this));
-
- QRegExp regExp4("[0-9]{1,3}");
- ui.lineEdit_IP_5->setValidator(new QRegExpValidator(regExp4, this));
- tcpsocket = new QTcpSocket;
- connectstate = 0;
- count_send = 0;
- count_receive = 0;
- flag_file_receive = 0;
- flag_suspend = 0;
- timerflag =0;
- autosend =0;
- connect(ui.pushButton_Connect, SIGNAL(clicked()), this, SLOT(Connect_Pushbutton_Clicked()));
- connect(ui.pushButton_Send,SIGNAL(clicked()),this,SLOT(pushButton_Send_clicked()));
- connect(ui.pushButton_Clear_send, SIGNAL(clicked()), this, SLOT(pushButton_Clear_Send_clicked()));
- connect(ui.pushButton_Clear, SIGNAL(clicked()), this, SLOT(Count_Clear()));
- connect(ui.pushButton_Clear_receive, SIGNAL(clicked()), this, SLOT(pushButton_Clear_Receive_clicked()));
- connect(ui.pushButton_Suspend,SIGNAL(clicked()),this, SLOT(pushButton_Suspend_clicked()));
- connect(ui.checkBox_Auto_Send, SIGNAL(clicked()), this, SLOT(Send_Message_Auto()));
- connect(ui.checkBox_Send_file, SIGNAL(clicked()), this, SLOT(Send_File()));
- connect(ui.checkBox_Receive_file, SIGNAL(clicked()), this, SLOT(Receive_File()));
- connect(tcpsocket, SIGNAL(error(QAbstractSocket::SocketError)), this,
- SLOT(Error_Robot(QAbstractSocket::SocketError)));
- connect(tcpsocket, SIGNAL(connected()), this, SLOT(connected_Socket())); //进行连接
- connect(tcpsocket, SIGNAL(disconnected()), this, SLOT(disConnected_Socket())); //断开连接
- connect(tcpsocket, SIGNAL(readyRead()), this, SLOT(ReadyRead_Socket())); //接收数据
- }
- /*
- * 更新一下现在的连接状态
- * @author jeff
- * @返回值:NULL
- */
- void carcontrol::Init_Connectstate_Control()
- {
- switch(connectstate_control){
- case 0:
- {
- ui.pushButton_conncect_car->setText("连接小车");
- }break;
- case 1:
- {
- ui.pushButton_conncect_car->setText("断开小车");
- }break;
- default:{
- ui.pushButton_conncect_car->setText("连接小车");
- }break;
- }
- }
- /*
- * 更新一下现在的连接状态
- * @author jeff
- * @返回值:NULL
- */
- void carcontrol::Init_Connectstate()
- {
- switch(connectstate){
- case 0:
- {
- ui.pushButton_Connect->setText("Connect");
- ui.pushButton_Send->setDisabled(true);
- }break;
- case 1:
- {
- ui.pushButton_Connect->setText("Disconnect");
- ui.pushButton_Send->setEnabled(true);
- }break;
- default:{
- ui.pushButton_Connect->setText("Connect");
- ui.pushButton_Send->setDisabled(true);
- }break;
- }
- }
- void carcontrol::Connect_Car_Pushbutton_Clicked()
- {
- if(ui.lineEdit_IP_C_1->text().isEmpty()||ui.lineEdit_IP_C_2->text().isEmpty()||ui.lineEdit_IP_C_3->text().isEmpty()||ui.lineEdit_IP_C_4->text().isEmpty())
- {
- QMessageBox::information(this,
- tr("Please enter the ipaddress"),
- tr("open failed!"));
- return;
- }
- QString Ipadress = ui.lineEdit_IP_C_1->text()+'.'+ui.lineEdit_IP_C_2->text()+'.'+ui.lineEdit_IP_C_3->text()+'.'+ui.lineEdit_IP_C_4->text();
- switch(connectstate_control){
- case 0:
- {
- control_tcpsocket->connectToHost(Ipadress,3333);
- control_tcpsocket->waitForConnected();
- }break;
- case 1:
- {
- control_tcpsocket->close();
- }break;
- default:{
- control_tcpsocket->close();
- }break;
- }
- Init_Connectstate_Control(); //连接状态初始化
- }
- void carcontrol::Connect_Camera_Pushbutton_Clicked()
- {
- if(connectstate_camera==0)
- {
- connectstate_camera = 1;
- webtimer->start(1000);
- }else
- {
- connectstate_camera = 0;
- webtimer->stop();
- }
- switch(connectstate_camera){
- case 0:
- {
- ui.pushButton_conncect_camera->setText("连接摄像头");
- }break;
- case 1:
- {
- ui.pushButton_conncect_camera->setText("断开摄像头");
- }break;
- default:{
- ui.pushButton_conncect_camera->setText("连接摄像头");
- }break;
- }
- Connect_Camera();
- }
- void carcontrol::Connect_Camera()
- {
- QString url = "http://"+ui.lineEdit_IP_C_1->text()+'.'+ui.lineEdit_IP_C_2->text()+'.'+ui.lineEdit_IP_C_3->text()+'.'+ui.lineEdit_IP_C_4->text()+":8080/static_simple.html";
- html->load(url);
- }
- void carcontrol::pushButton_start_clicked()
- {
- if(connectstate_control<1)
- return;
- QString data;
- runstate_control=0;
- data = "SPEED0";
- control_sendMeassage(data);
- }
- void carcontrol::pushButton_start_forward_clicked()
- {
- if(connectstate_control<1)
- return;
- control_sendMeassage("FORWARD");
- MyTools::MySleep(10);
- QString speed = ui.lineEdit_speed->text();
- qDebug()<<"speed:"<
- QString data = "SPEED"+speed;
- control_sendMeassage(data);
- }
- void carcontrol::pushButton_start_backward_clicked()
- {
- if(connectstate_control<1)
- return;
- control_sendMeassage("BACKWARD");
- MyTools::MySleep(10);
- QString speed = ui.lineEdit_speed->text();
- qDebug()<<"speed:"<
- QString data = "SPEED"+speed;
- control_sendMeassage(data);
- }
- void carcontrol::pushButton_start_left_clicked()
- {
- if(connectstate_control<1)
- return;
- control_sendMeassage("LEFT");
- MyTools::MySleep(10);
- QString speed = ui.lineEdit_speed->text();
- qDebug()<<"speed:"<
- QString data = "SPEED"+speed;
- control_sendMeassage(data);
- }
- void carcontrol::pushButton_start_right_clicked()
- {
- if(connectstate_control<1)
- return;
- control_sendMeassage("RIGHT");
- MyTools::MySleep(10);
- QString speed = ui.lineEdit_speed->text();
- qDebug()<<"speed:"<
- QString data = "SPEED"+speed;
- control_sendMeassage(data);
- }
- void carcontrol::control_Error_Robot(QAbstractSocket::SocketError)
- {
- QMessageBox::information(this, "show", control_tcpsocket->errorString());
- }
- void carcontrol::control_connected_Socket()
- {
- connectstate_control = 1;
- Init_Connectstate_Control(); //连接状态初始化
- }
- void carcontrol::control_disConnected_Socket()
- {
- connectstate_control = 0;
- Init_Connectstate_Control(); //连接状态初始化
- }
- void carcontrol::control_ReadyRead_Socket()
- {
- if(connectstate_control<1) //未连接直接返回
- return;
- char *c_data;
- int i = 0;
- int Bytenum = 0;
- QByteArray message = control_tcpsocket->readAll();
-
- c_data = message.data();
- Bytenum = message.length();
- qDebug()<
- if(strstr(c_data,"PEOPLE"))
- {
- ui.pushButton_people->setText("有人");
- }
- if(strstr(c_data,"NONP"))
- {
- ui.pushButton_people->setText("没人");
- }
- if(strstr(c_data,"SOUND"))
- {
- ui.pushButton_sound->setText("有声响");
- }
- if(strstr(c_data,"NONS"))
- {
- ui.pushButton_sound->setText("没声响");
- }
- }
- /*
- * control_tcpsocket发送信息
- * @author jeff
- * @返回值:NULL
- */
- void carcontrol::control_sendMeassage(QString data)
- {
- if(connectstate_control==1)
- control_tcpsocket->write((data).toAscii());
- }
- /*
- * connect_pushbutton按下后的槽slots
- * @author jeff
- * @返回值:NULL
- */
- void carcontrol::Connect_Pushbutton_Clicked()
- {
- if(ui.lineEdit_Port->text().isEmpty()||ui.lineEdit_IP_1->text().isEmpty()||ui.lineEdit_IP_5->text().isEmpty()||ui.lineEdit_IP_3->text().isEmpty()||ui.lineEdit_IP_4->text().isEmpty())
- {
- QMessageBox::information(this,
- tr("Please enter the ipaddress and the port"),
- tr("open failed!"));
- return;
- }
- quint16 port = ui.lineEdit_Port->text().toInt();
- QString Ipadress = ui.lineEdit_IP_1->text()+'.'+ui.lineEdit_IP_3->text()+'.'+ui.lineEdit_IP_4->text()+'.'+ui.lineEdit_IP_5->text();
- switch(connectstate){
- case 0:
- {
- tcpsocket->connectToHost(Ipadress,port);
- tcpsocket->waitForConnected();
- }break;
- case 1:
- {
- tcpsocket->close();
- }break;
- default:{
- tcpsocket->close();
- }break;
- }
- Init_Connectstate(); //连接状态初始化
- }
- /*
- * 按下send按钮后的槽slots
- * @author jeff
- * @返回值:NULL
- */
- void carcontrol::pushButton_Send_clicked()
- {
- QString data=ui.lineEdit_Send_input->text();
- count_send += data.length();
- QString strings = QString::number(count_send,10);
- ui.lineEdit_Tx_count -> setText(strings);
- if (data!="")
- {
- if (ui.checkBox_Send_16->isChecked())
- {
- sendMeassage(MyTools::HexStrToByteArray(data));
- ui.textBrowser_send->append(MyTools::HexStrToByteArray(data));
- }
- else
- {
- sendMeassage((data).toAscii());//+'n'
- ui.textBrowser_send->append(data);
- }
- }
-
- }
- /*
- * 按下send的clear按钮后的槽slots
- * @author jeff
- * @返回值:NULL
- */
- void carcontrol::pushButton_Clear_Send_clicked()
- {
- ui.textBrowser_send->clear();
- }
- /*
- * 按下receive的clear按钮后的槽slots
- * @author jeff
- * @返回值:NULL
- */
- void carcontrol::pushButton_Clear_Receive_clicked()
- {
- ui.textBrowser_receive->clear();
- }
- /*
- * 机器人控制class给接收到的信号后的槽
- * @author jeff
- * @返回值:NULL
- */
- void carcontrol::ReadyRead_Robot(const QByteArray & bytearray)
- {
- count_receive += bytearray.length();
- QString strings = QString::number(count_receive,10);
- ui.lineEdit_Rx_count -> setText(strings);
- if(flag_file_receive==1)
- Save_To_File(bytearray);
- else{
- if(flag_suspend == 0)
- {
- if(!bytearray.isEmpty())
- {
- if (ui.checkBox_receive_16->isChecked())
- {
- ui.textBrowser_receive->append(MyTools::ByteArrayToHexStr(bytearray));
- }
- else
- {
- ui.textBrowser_receive->append(bytearray);
- }
- }
- }
- }
- }
- /*
- * 按下count的clear按钮后的槽slots
- * @author jeff
- * @返回值:NULL
- */
- void carcontrol::Count_Clear()
- {
- ui.lineEdit_Tx_count->clear();
- ui.lineEdit_Rx_count->clear();
- count_send = 0;
- count_receive = 0;
- }
- /*
- * 按下suspend后的槽slots
- * @author jeff
- * @返回值:NULL
- */
- void carcontrol::pushButton_Suspend_clicked()
- {
- if(flag_suspend==0)
- {
- flag_suspend = 1;
- ui.pushButton_Suspend->setText("Start");}
- else
- {
- flag_suspend = 0;
- ui.pushButton_Suspend->setText("Suspend");
- }
- }
- /*
- * 勾上Auto Send后的槽slots
- * 主要是打开一个定时器
- * @author jeff
- * @返回值:NULL
- */
- void carcontrol::Send_Message_Auto()
- {
- if(connectstate == 1)
- {
- if(ui.checkBox_Auto_Send->isChecked())
- {
- QString ms = ui.lineEdit_Auto_send->text();
- QString data = ui.lineEdit_Send_input->text();
- if((!ms.isEmpty())&&(!data.isEmpty()))
- {
- autosend = startTimer(ms.toInt());
- timerflag = 1;
- //this->timerEvent(autosend);
- }else
- {
- QMessageBox::about(this, tr("Warrning !"),
- tr("
Warrning !"
- "
Please input a time and a data."
- ));
- ui.checkBox_Auto_Send->setCheckState(Qt::Unchecked);
- }
- }else
- if(timerflag ==1)
- {
- timerflag = 0;
- killTimer(autosend);
- }
- }else
- if(timerflag ==1)
- {
- timerflag = 0;
- killTimer(autosend);
- }
- }
- /*
- * 定时器处理函数
- * @author jeff
- * @返回值:NULL
- */
- void carcontrol::timerEvent(QTimerEvent *event)
- {
- pushButton_Send_clicked();
- }
- /*
- * 发送文件处理函数
- * @author jeff
- * @返回值:成功返回0,失败返回-1
- */
- int carcontrol::Send_File()
- {
- if(ui.checkBox_Send_file->isChecked())
- {
- QString filename = QFileDialog::getSaveFileName(this,
- tr("Send data"),
- "",
- tr("*.txt;; *.png;; *.jpg;; *.tif;; *.GIF")); //选择路径
- if(filename.isEmpty())
- {
- return -1;
- }
-
- ui.lineEdit_Send_input->setText(filename);
- QFile file(filename);
- if(!file.open(QIODevice::ReadOnly | QIODevice::Text))
- {
- QMessageBox::about(this, tr("Warrning !"),
- tr("
Warrning1 !"
- "
Can't open the file!."
- ));
- }
- while(!file.atEnd())
- {
- QByteArray line = file.readLine();
- QString str(line);
- //tcpsocket->write((str+'n').toAscii());
-
- count_send += str.length();
- QString strings = QString::number(count_send,10);
- ui.lineEdit_Tx_count -> setText(strings);
- if (str!="")
- {
- if (ui.checkBox_Send_16->isChecked())
- {
- sendMeassage(MyTools::HexStrToByteArray(str));
- ui.textBrowser_send->append(MyTools::HexStrToByteArray(str));
- }
- else
- {
- sendMeassage((str+'n').toAscii());
- ui.textBrowser_send->append(str);
- }
- }
- }
- }else{
- //lineEdit_Send_path
- QMessageBox::about(this, tr("Warrning !"),
- tr("
Warrning1 !"
- "
Stop send a file."
- ));
- }
- return 0;
- }
- /*
- * 保存至文件内处理函数
- * @author jeff
- * @返回值:成功与否,成功返回1,失败返回0
- */
- int carcontrol::Receive_File()
- {
- if(ui.checkBox_Receive_file->isChecked()){
- QString filename = QFileDialog::getSaveFileName(this,
- tr("Send data"),
- "",
- tr("*.txt;; *.dat;; *.jpg;; *.tif;; *.GIF")); //选择路径
- if(filename.isEmpty())
- {
- return -1;
- }
- ui.lineEdit_Receive_path->setText(filename);
- flag_file_receive =1;
- filepath = filename;
- }
- else{
- flag_file_receive = 0;
- QMessageBox::about(this, tr("Warrning !"),
- tr("
Warrning 2!"
- "
Stop save to a file."
- ));
- }
- return 0;
- }
- /*
- * 保存至文件内
- * @author jeff
- * @返回值:成功与否,1:成功,0:失败
- */
- int carcontrol::Save_To_File(QByteArray x)
- {
-
- QFile file(filepath);
- if(!file.open(QIODevice::WriteOnly | QIODevice::Text| QIODevice::Append ))//
- return 1;
- QTextStream out(&file);
- qDebug()<
- out << x <
- return 0;
- }
- /*
- * socket错误报错
- * @author jeff
- * @返回值:NULL
- */
- void carcontrol::Error_Robot(QAbstractSocket::SocketError)
- {
- QMessageBox::information(this, "show", tcpsocket->errorString());
- }
- /*
- * socket连接上之后的槽
- * @author jeff
- * @返回值:NULL
- */
- void carcontrol::connected_Socket()
- {
- connectstate = 1;
- Init_Connectstate();
- }
- /*
- * socket断开之后的槽
- * @author jeff
- * @返回值:NULL
- */
- void carcontrol::disConnected_Socket()
- {
- connectstate = 0;
- Init_Connectstate();
- }
- /*
- * socket收到信息之后的槽
- * @author jeff
- * @返回值:NULL
- */
- void carcontrol::ReadyRead_Socket()
- {
- if(connectstate<1) //未连接直接返回
- return;
- char *c_data;
- int i = 0;
- int Bytenum = 0;
- QByteArray message = tcpsocket->readAll();
- ReadyRead_Robot(message);
-
- c_data = message.data();
- Bytenum = message.length();
- qDebug()<
- }
- /*
- * socket发送信息
- * @author jeff
- * @返回值:NULL
- */
- void carcontrol::sendMeassage(const QByteArray & byteArray)
- {
- if(connectstate==1)
- tcpsocket->write(byteArray);
- }
复制代码
最终小车通过上位机控制效果如下所示。
前进。
后退。
右转。
左转。
遇障碍停止。
到此小车基本搭建完成。因为NanoPi Neo2自带的资源很丰富,因此开发起来非常的方便。板子的性能没得说,A53的内核不是盖的。当然作为这么小巧的板子,所带的其他外设资源有限,但对我这种小规模的玩玩而言已经绰绰有余。在NanoPi Neo2上开发,完全就是Linux开发,这样的价位基本跟 单片机一样,同时性能比单片机强很多。这是一款高性价比的 开发板,有机会试用真的很开心。
|