草庐IT

从零搭建树莓派远程监控小车,udp视频传输,qt上位机

Hello_Yangyi 2023-08-16 原文

目录

前言

一、材料准备

二、连线方式

三、软件编程

软件编程主要有一下几个方面

(1)树莓派视频传输

(2)esp8266代码

(3)上位机编程

 四、总结



前言

最近刚准备完期末机器人驱动的课设,本来是做远程监控无人机的,但是第一次玩无刷电机,烧坏了两个电调,所以就索性将无人机改成了无人车,接下来我将详细介绍一下我的准备以及设计过程。


一、材料准备

树莓派4b

esp8266模块(这个是用来驱动无刷电机,其实树莓派一个也能完成,但是最近树莓派价格太贵了,烧不起啊,所以单独选用esp8266来驱动电机接受指令)

树莓派官方摄像头

2个sg90舵机(这个舵机是真的不好用,强烈建议大家更换金属齿轮的舵机,由于在家中材料限制不得不使用sg90)

无刷电机两个

无刷电调两个

航模锂电池12v

部分3d打印件(云台以及地盘,轮子模型都是我自己通过solidwroks设计的,需要的我将链接放在最后)

二、连线方式

esp8266 5号引脚和4号引脚连接两个sg90舵机

0号和2号引脚连接两个无刷电调

无刷电调三根线分别连接无刷电机的三根线,顺序随便,后期调整方向即可


三、软件编程

软件编程主要有一下几个方面

1.树莓派的视频传输编程

2.接收端上位机的编程

3.esp8266接受上位机指令驱动舵机和无刷电机的编程

(1)树莓派视频传输

在视频传输上我考虑过很多个方法,tcp协议,udp协议,mjpg-streamer插件,最后选择的是udp协议,tcp由于需要三次握手三次挥手,传输精度高,但是效率低,我们做视频传输更在乎的是延迟,所以不需要握手的udp更加适合,mjpg-streamer由于我配置了opencv环境,所以起冲突了,不考虑,但是这个插件传输的延迟也很低,效率高,在GitHub上也获得了不少的star,大家也可以尝试一下

mjpg-steamer链接

以下是树莓派代码:

是用qt写的发送端,配置了opencv环境,编译了可能不会直接通过,可以先配置一下qt的opencv环境,代码量较多,仅展示cpp源代码,其他的放在文末资料内

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <opencv2/highgui.hpp>
#include <opencv2/imgcodecs.hpp>
#include <QHostAddress>
using namespace cv;
MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    udpSocket = new QUdpSocket(this);
    udpSocket->bind(QHostAddress::Any,8083);
    connect(&fps_timer,SIGNAL(timeout()),this,SLOT(VideoSend()));



}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::on_pushButton_clicked()
{
    camera.open(0);
    fps_timer.start(33);


}

void MainWindow::on_pushButton_2_clicked()
{
    fps_timer.stop();
    camera.release();
    this->close();

}


void MainWindow::VideoSend()
{
    QHostAddress ipp=(QHostAddress)(ui->lineEdit->text());
    quint16 portt=ui->lineEdit_2->text().toInt();
    Mat frame;
    camera.read(frame);
    cvtColor(frame,frame,COLOR_BGR2RGB);
    QImage image((unsigned char *)(frame.data),frame.cols,frame.rows,QImage::Format_RGB888);
    ui->label_video->setPixmap(QPixmap::fromImage(image));
    ui->label_video->resize(image.width(),image.height());
    QByteArray byte;
    QBuffer buff(&byte);
    buff.open(QIODevice::WriteOnly);
    image.save(&buff,"JPEG");
    QByteArray ss = qCompress(byte,5);
    udpSocket->writeDatagram(ss,ipp,portt);


}

(2)esp8266代码

这一部分使用的tcp协议进行传输,然后通过阿里云进行转发,具体请看我上一篇博文,代码如下:

#include "ESP8266WiFi.h"
#include "Servo.h"
const char* ssid="*******";//wifi账号
const char* password="******";//wifi密码


Servo wushua1;
Servo wushua2;
int Max=2000;      
int Min=1000;    
int pos=Min;       
int sign=0;       

Servo servo1;
Servo servo2;
int sor=50;
int sorr=50;
void setup()
{
  
servo1.attach(5);
servo1.write(sor);
  servo2.attach(4);
servo2.write(sorr);
wushua2.attach(2);
wushua1.attach(0); 
 
wushua2.write(Max);
wushua1.write(Max); 
     delay(5000); 
        
     wushua1.write(Min); 
     wushua2.write(Min); 
     delay(5000);      //模拟遥控器给无刷电机进行校准

Serial.begin(115200);
WiFi.mode(WIFI_STA);
WiFi.begin(ssid,password);
while(WiFi.status()!=WL_CONNECTED)
{
  delay(1000);
  Serial.println("waiting to connect...");

  
  }
Serial.println("connecting!!!");
Serial.print("ip address is :");
Serial.print(WiFi.localIP());




  
}

void loop() 
{
 WiFiClient tcpclient;
 if(!tcpclient.connect("8.130.51.57",8000))
{
  Serial.println("connect to aliyun is failed");
  delay(5000);
  
  
  }
Serial.println("Connect to aliyun is successful");
tcpclient.println("hello,i am esp8266");
while(1)
{

while(tcpclient.available()==0);

Serial.println("i recive:");
char ch=static_cast<char>(tcpclient.read());
Serial.println(ch);


if(ch=='1')
{sor=sor+20;
servo1.write(sor);
delay(500);
 }
  else if(ch=='2')
 {
  sor=sor-20;
  servo1.write(sor);
  delay(500);}
  else if(ch=='3')
  {sorr=sorr+20;
servo2.write(sorr);
delay(500);
    }
    else if(ch=='4')
    {
      sorr=sorr-20;
servo2.write(sorr);
delay(500);
      }
    else if(ch=='5')
    {
      wushua1.write(1500);
      wushua2.write(1500);
delay(500);
      }

      else if(ch=='6')
      {
              wushua1.write(800);
      wushua2.write(800);
delay(500);
        }
         else if(ch=='7')
      {
              wushua1.write(800);
      wushua2.write(1500);
delay(500);
        }
         else if(ch=='8')
      {
              wushua1.write(1500);
      wushua2.write(800);
delay(500);


}}}

(3)上位机编程

上位机也是通过qt写的,主要接受udp视频以及用tcp发送指令给esp8266 

cpp代码如下:

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include<QHostAddress>
#include<QPixmap>
#include<QImageReader>
#include<QBuffer>
#include<QHostAddress>
MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    receiver.bind(QHostAddress::Any,8083);
    connect(&receiver,SIGNAL(readyRead()),this,SLOT(video_receive_show()));
   //

    setWindowTitle("无人车远程监控平台");
    ui->connect->setEnabled(true);
    m_tcp=new QTcpSocket(this);
    connect(m_tcp,&QTcpSocket::readyRead,this,[=]()

    {

     QByteArray date=m_tcp->readAll();
     //
    }  );

    connect(m_tcp,&QTcpSocket::connected,this,[=]()
    {

      ui->jiaohu->append("已经成功连接到了无人车,可以进行控制");
    });


}

MainWindow::~MainWindow()
{
    delete ui;
}
void MainWindow::video_receive_show()
{
    quint64 size = receiver.pendingDatagramSize();    
    QByteArray buff;    
    buff.resize(size);
    QHostAddress adrr ;
    quint16 port;
    receiver.readDatagram(buff.data(),buff.size(),&adrr,&port);    
    buff = qUncompress(buff);
    QBuffer buffer(&buff);
    QImageReader reader(&buffer,"JPEG");//可读入磁盘文件、设备文件中的图像、以及其他图像数据如pixmap和image,相比较更加专业。
    //buffer属于设备文件一类,
    QImage image = reader.read();//read()方法用来读取设备图像,也可读取视频,读取成功返回QImage*,否则返回NULL    
    ui->label->setPixmap(QPixmap::fromImage(image));
    ui->label->resize(image.width(),image.height());
}

void MainWindow::on_connect_clicked()
{
    QString ip=ui->ip->text();
    unsigned short port=ui->port->text().toUShort();
    m_tcp->connectToHost(QHostAddress(ip),port);
    ui->jiaohu->append("客户端向无人车发起了连接请求");
}

void MainWindow::on_yunleft_clicked()
{
    m_tcp->write("1");
    ui->jiaohu->append("客户端发出了云台左转的命令");
}

void MainWindow::on_yunright_clicked()
{
    m_tcp->write("2");
    ui->jiaohu->append("客户端发出了云台右转的命令");
}

void MainWindow::on_yunup_clicked()
{
    m_tcp->write("3");
    ui->jiaohu->append("客户端发出了云台上调的命令");
}

void MainWindow::on_yundown_clicked()
{
    m_tcp->write("4");
    ui->jiaohu->append("客户端发出了云台下调的命令");
}

void MainWindow::on_go_clicked()
{
    m_tcp->write("5");
     ui->jiaohu->append("小车前进中");
}

void MainWindow::on_down_clicked()
{
        m_tcp->write("6");
     ui->jiaohu->append("小车暂停运行");
}

void MainWindow::on_left_clicked()
{
    m_tcp->write("7");
 ui->jiaohu->append("小车左转");
}

void MainWindow::on_right_clicked()
{
    m_tcp->write("8");
 ui->jiaohu->append("小车右转");
}

 四、总结

由于使用了tcp中转,所以小车不受距离的限制,只要接入了互联网,即可受到上位机的控制。后期可以加入人脸识别,变成人脸监控小车,然后写好代码让小车自动在家里巡航,当发现陌生人后可以通过app报警,这也是我接下来的研究方向。

资料下载:

链接:https://pan.baidu.com/s/1xNbzBkFHaO1DzDlhp44Tlw?pwd=w94s 
提取码:w94s 
--来自百度网盘超级会员V3的分享

有关从零搭建树莓派远程监控小车,udp视频传输,qt上位机的更多相关文章

  1. Observability:从零开始创建 Java 微服务并监控它 (二) - 2

    这篇文章是继上一篇文章“Observability:从零开始创建Java微服务并监控它(一)”的续篇。在上一篇文章中,我们讲述了如何创建一个Javaweb应用,并使用Filebeat来收集应用所生成的日志。在今天的文章中,我来详述如何收集应用的指标,使用APM来监控应用并监督web服务的在线情况。源码可以在地址 https://github.com/liu-xiao-guo/java_observability 进行下载。摄入指标指标被视为可以随时更改的时间点值。当前请求的数量可以改变任何毫秒。你可能有1000个请求的峰值,然后一切都回到一个请求。这也意味着这些指标可能不准确,你还想提取最小/

  2. Qt Designer的简单使用 - 2

    在前面两节的例子中,主界面窗口的尺寸和标签控件显示的矩形区域等,都是用C++代码编写的。窗口和控件的尺寸都是预估的,控件如果多起来,那就不好估计每个控件合适的位置和大小了。用C++代码编写图形界面的问题就是不直观,因此Qt项目开发了专门的可视化图形界面编辑器——QtDesigner(Qt设计师)。通过QtDesigner就可以很方便地创建图形界面文件*.ui,然后将ui文件应用到源代码里面,做到“所见即所得”,大大方便了图形界面的设计。本节就演示一下QtDesigner的简单使用,学习拖拽控件和设置控件属性,并将ui文件应用到Qt程序代码里。使用QtDesigner设计界面在开始菜单中找到「Q

  3. 关于Qt程序打包后运行库依赖的常见问题分析及解决方法 - 2

    目录一.大致如下常见问题:(1)找不到程序所依赖的Qt库version`Qt_5'notfound(requiredby(2)CouldnotLoadtheQtplatformplugin"xcb"in""eventhoughitwasfound(3)打包到在不同的linux系统下,或者打包到高版本的相同系统下,运行程序时,直接提示段错误即segmentationfault,或者Illegalinstruction(coredumped)非法指令(4)ldd应用程序或者库,查看运行所依赖的库时,直接报段错误二.问题逐个分析,得出解决方法:(1)找不到程序所依赖的Qt库version`Qt_5'

  4. 【Linux操作系统】——网络配置与SSH远程 - 2

    Linux操作系统——网络配置与SSH远程安装完VMware与系统后,需要进行网络配置。第一个目标为进行SSH连接,可以从本机到VMware进行文件传送,首先需要进行网络配置。1.下载远程软件首先需要先下载安装一款远程软件:FinalShell或者xhell7FinalShellxhell7FinalShell下载:Windows下载http://www.hostbuf.com/downloads/finalshell_install.exemacOS下载http://www.hostbuf.com/downloads/finalshell_install.pkg2.配置CentOS网络安装好

  5. ruby - 带有 grep 远程日志文件的 tail - 2

    我有这段代码来跟踪远程日志文件:defdo_tail(session,file)session.open_channeldo|channel|channel.on_datado|ch,data|puts"[#{file}]->#{data}"endchannel.exec"tail-f#{file}"endNet::SSH.start("host","user",:password=>"passwd")do|session|do_tailsession,"/path_to_log/file.log"session.loop我只想在file.log中检索带有ERROR字符串的行,我正在尝

  6. ruby - 如何使用远程 API 将 Confluence "Space"导出为 PDF - 2

    如何将Confluence的“空间”导出为pdf文件?看起来Confluence5.0可能仍然支持使用XML-RPCAPI。不过,我找不到调用什么的示例。https://developer.atlassian.com/display/CONFDEV/Remote+API+Specification+for+PDF+Export#RemoteAPISpecificationforPDFExport-XML-RPCInformation该链接表示调用应以pdfexport为前缀,但没有列出任何调用或给出示例。 最佳答案 这可以使用Bob

  7. ruby-on-rails - Rails 是否支持监听 UDP 套接字的简洁方式? - 2

    在Rails中,什么是集成更新模型某些元素的UDP监听过程的最佳方式(特别是它将向其中一个表添加行)。简单的答案似乎是在同一个进程中使用UDP套接字对象启动一个线程,但我什至不清楚我应该在哪里做适合Rails方式的事情。有没有一种巧妙的方法来开始收听UDP?具体来说,我希望能够编写一个UDPController并在每个数据报消息上调用一个特定的方法。理想情况下,我希望避免在UDP上使用HTTP(因为它会浪费一些在这种情况下非常宝贵的空间),但我完全控制消息格式,因此我可以为Rails提供它需要的任何信息。 最佳答案 Rails是一个

  8. ruby - AWS 上远程机器上的进程计数 - 2

    我正在为在AmazonEC2实例上运行的应用程序设计一个AutoScaling系统。应用程序从SQS读取消息并对其进行处理。AutoScaling系统将监控两件事:SQS中的消息数量,所有EC2机器上运行的进程总数。例如,如果SQS中的消息数量超过3000,我希望系统自动缩放,创建一个新的EC2实例,在其上部署代码,当消息数量低于2000时,我希望系统终止EC2实例.我正在用Ruby和Capistrano做这件事。我的问题是:我无法找到一种方法来确定在所有EC2机器上运行的进程数并将该数字保存在变量中。你能帮帮我吗? 最佳答案 您可

  9. ruby - 使用 Ruby 将 HTTP GET 的响应主体流式传输到 HTTP POST - 2

    我正在尝试下载一个大文件,然后使用Ruby将该文件发布到REST端点。该文件可能非常大,即超过可以存储在内存中甚至磁盘上的临时文件中的容量。我一直在用Net::HTTP尝试这个,但我愿意接受任何其他库(rest-client等)的解决方案,只要他们做我想做的事情。这是我尝试过的:require'net/http'source_uri=URI("https://example.org/very_large_file")source_request=Net::HTTP::Get.new(source_uri)source_http=Net::HTTP.start(source_uri.ho

  10. ruby-on-rails - 将 Heroku 环境变量传输到 Docker 实例 - 2

    我在Heroku上构建了一个必须在Docker容器内运行的RoR应用程序。为此,我使用officialDockerfile.因为它在Heroku中很常见,所以我需要一些附加组件才能使这个应用程序完全运行。在生产中,变量DATABASE_URL在我的应用程序中可用。但是,如果我尝试其他一些使用环境变量(在我的例子中是Mailtrap)的加载项,变量不会在运行时复制到实例中。所以我的问题很简单:如何让docker实例在Heroku上执行时知道环境变量?您可能会问,我已经知道我们可以在docker-compose.yml中指定一个environment指令。我想避免这种情况,以便能够通过项目

随机推荐