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


树莓派4b
esp8266模块(这个是用来驱动无刷电机,其实树莓派一个也能完成,但是最近树莓派价格太贵了,烧不起啊,所以单独选用esp8266来驱动电机接受指令)
树莓派官方摄像头
2个sg90舵机(这个舵机是真的不好用,强烈建议大家更换金属齿轮的舵机,由于在家中材料限制不得不使用sg90)
无刷电机两个
无刷电调两个
航模锂电池12v
部分3d打印件(云台以及地盘,轮子模型都是我自己通过solidwroks设计的,需要的我将链接放在最后)
esp8266 5号引脚和4号引脚连接两个sg90舵机
0号和2号引脚连接两个无刷电调
无刷电调三根线分别连接无刷电机的三根线,顺序随便,后期调整方向即可
1.树莓派的视频传输编程
2.接收端上位机的编程
3.esp8266接受上位机指令驱动舵机和无刷电机的编程
在视频传输上我考虑过很多个方法,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);
}
这一部分使用的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);
}}}
上位机也是通过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的分享
这篇文章是继上一篇文章“Observability:从零开始创建Java微服务并监控它(一)”的续篇。在上一篇文章中,我们讲述了如何创建一个Javaweb应用,并使用Filebeat来收集应用所生成的日志。在今天的文章中,我来详述如何收集应用的指标,使用APM来监控应用并监督web服务的在线情况。源码可以在地址 https://github.com/liu-xiao-guo/java_observability 进行下载。摄入指标指标被视为可以随时更改的时间点值。当前请求的数量可以改变任何毫秒。你可能有1000个请求的峰值,然后一切都回到一个请求。这也意味着这些指标可能不准确,你还想提取最小/
在前面两节的例子中,主界面窗口的尺寸和标签控件显示的矩形区域等,都是用C++代码编写的。窗口和控件的尺寸都是预估的,控件如果多起来,那就不好估计每个控件合适的位置和大小了。用C++代码编写图形界面的问题就是不直观,因此Qt项目开发了专门的可视化图形界面编辑器——QtDesigner(Qt设计师)。通过QtDesigner就可以很方便地创建图形界面文件*.ui,然后将ui文件应用到源代码里面,做到“所见即所得”,大大方便了图形界面的设计。本节就演示一下QtDesigner的简单使用,学习拖拽控件和设置控件属性,并将ui文件应用到Qt程序代码里。使用QtDesigner设计界面在开始菜单中找到「Q
目录一.大致如下常见问题:(1)找不到程序所依赖的Qt库version`Qt_5'notfound(requiredby(2)CouldnotLoadtheQtplatformplugin"xcb"in""eventhoughitwasfound(3)打包到在不同的linux系统下,或者打包到高版本的相同系统下,运行程序时,直接提示段错误即segmentationfault,或者Illegalinstruction(coredumped)非法指令(4)ldd应用程序或者库,查看运行所依赖的库时,直接报段错误二.问题逐个分析,得出解决方法:(1)找不到程序所依赖的Qt库version`Qt_5'
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网络安装好
我有这段代码来跟踪远程日志文件: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字符串的行,我正在尝
如何将Confluence的“空间”导出为pdf文件?看起来Confluence5.0可能仍然支持使用XML-RPCAPI。不过,我找不到调用什么的示例。https://developer.atlassian.com/display/CONFDEV/Remote+API+Specification+for+PDF+Export#RemoteAPISpecificationforPDFExport-XML-RPCInformation该链接表示调用应以pdfexport为前缀,但没有列出任何调用或给出示例。 最佳答案 这可以使用Bob
在Rails中,什么是集成更新模型某些元素的UDP监听过程的最佳方式(特别是它将向其中一个表添加行)。简单的答案似乎是在同一个进程中使用UDP套接字对象启动一个线程,但我什至不清楚我应该在哪里做适合Rails方式的事情。有没有一种巧妙的方法来开始收听UDP?具体来说,我希望能够编写一个UDPController并在每个数据报消息上调用一个特定的方法。理想情况下,我希望避免在UDP上使用HTTP(因为它会浪费一些在这种情况下非常宝贵的空间),但我完全控制消息格式,因此我可以为Rails提供它需要的任何信息。 最佳答案 Rails是一个
我正在为在AmazonEC2实例上运行的应用程序设计一个AutoScaling系统。应用程序从SQS读取消息并对其进行处理。AutoScaling系统将监控两件事:SQS中的消息数量,所有EC2机器上运行的进程总数。例如,如果SQS中的消息数量超过3000,我希望系统自动缩放,创建一个新的EC2实例,在其上部署代码,当消息数量低于2000时,我希望系统终止EC2实例.我正在用Ruby和Capistrano做这件事。我的问题是:我无法找到一种方法来确定在所有EC2机器上运行的进程数并将该数字保存在变量中。你能帮帮我吗? 最佳答案 您可
我正在尝试下载一个大文件,然后使用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
我在Heroku上构建了一个必须在Docker容器内运行的RoR应用程序。为此,我使用officialDockerfile.因为它在Heroku中很常见,所以我需要一些附加组件才能使这个应用程序完全运行。在生产中,变量DATABASE_URL在我的应用程序中可用。但是,如果我尝试其他一些使用环境变量(在我的例子中是Mailtrap)的加载项,变量不会在运行时复制到实例中。所以我的问题很简单:如何让docker实例在Heroku上执行时知道环境变量?您可能会问,我已经知道我们可以在docker-compose.yml中指定一个environment指令。我想避免这种情况,以便能够通过项目