前言
本篇源于 “ 2022 湖南省大學(xué)生物聯(lián)網(wǎng)應(yīng)用創(chuàng)新設(shè)計競賽技能賽參考樣題 ”
——應(yīng)用物聯(lián)網(wǎng)的共享電動自行車
針對共享電動自行車應(yīng)用場景,設(shè)計實現(xiàn)共享電動自行車、用戶、管理等相關(guān)人、物互聯(lián)的物聯(lián)網(wǎng)系統(tǒng)。假設(shè)系統(tǒng)由電動自行車、后端服務(wù)器、前端應(yīng)用終端、以及電動自行車專用巡檢裝置組成,各部分功能作用如下:
一、電動自行車:
1)每臺電動自行車有一個唯一的 ID 號,以及由 GPS 采集的位置信息(比賽中,GPS 及地圖信息可用人工輸入固定位置編號代替);
2)電動自行車電池可換,每個電池上有唯一 RFID 信息,可被電動自行車讀取;
3)電動自行車驅(qū)動部分有一個總開關(guān),能夠被遠(yuǎn)程控制其開關(guān),以允許電動自行車被合法租用人駕駛;
4)電動自行車由直流電機驅(qū)動,能被控制不同速度轉(zhuǎn)動(競賽條件下可用任何小型直流電機代替),設(shè)有控制直流電機轉(zhuǎn)速的操控開關(guān)、以及測量直流電機實際轉(zhuǎn)速的裝置;
5)電動自行車駕駛時設(shè)有左、右轉(zhuǎn)向指示,當(dāng)轉(zhuǎn)向時對應(yīng)轉(zhuǎn)向指示燈開始閃爍(亮 0.7 秒、滅 0.3 秒,循環(huán));
6)電動自行車設(shè)有一個夜間自動照明燈,當(dāng)環(huán)境亮度低于所設(shè)定閾值時,照明燈自動打開;
7)電動自行車設(shè)有 1 個喇叭(可蜂鳴器代),行車需要時可提示路上行人、或當(dāng)檢測到故障時報警;
8)電動自行車的電池狀態(tài)可被檢測(比賽場景簡化為檢測以下數(shù)據(jù):電壓 V1、電壓 V2、溫度T1、溫度 T2),設(shè)電池主要數(shù)據(jù)為:電池電壓 V1、充放電電流 I = | V1 -V2| / R (R 為固定的電流測量采樣電阻阻值)、電池工作溫升 T=T2-T1;
9)電動自行車上能夠顯示其重要相關(guān)信息和數(shù)據(jù);
10)電動自行車具備與遠(yuǎn)程服務(wù)器通信,將數(shù)據(jù)傳輸?shù)胶笈_服務(wù)器、或被查詢、或被控制;
11)挑戰(zhàn)性功能 1:當(dāng)斷電(如更換電池)時,一些設(shè)置的與電動車相關(guān)個性信息應(yīng)該保留,復(fù)電后仍然有效。
12)挑戰(zhàn)性功能 2:斷網(wǎng)(如騎行到無網(wǎng)絡(luò)場地)期間,電動自行車記錄的信息在網(wǎng)絡(luò)連通后,能夠不丟失地將全部數(shù)據(jù)傳送至后端服務(wù)器。
二、后端服務(wù)器:
1)構(gòu)建網(wǎng)絡(luò)后端服務(wù)器,收發(fā)、管理、控制多個電動自行車數(shù)據(jù)(競賽場景管理不少于 2 臺電動自行車);
2)按應(yīng)用場景和題目要求,對后臺數(shù)據(jù)計算、處理、運用;
3)按應(yīng)用場景和題目要求,為應(yīng)用前端(移動用戶和計算機網(wǎng)絡(luò)用戶)提供服務(wù)。
三、前端應(yīng)用:
網(wǎng)絡(luò)終端(如計算機)或移動終端(如智能手機 App)針對應(yīng)用場景和題目要求的相關(guān)應(yīng)用功能,如信息顯示、或遠(yuǎn)程控制、或預(yù)警、或統(tǒng)計等。
四、巡檢裝置:
電動自行車維護(hù)維修的專用移動裝置。當(dāng)巡檢人員攜帶該巡檢裝置到達(dá)電動自行車附近時,可無線方式與電動自行車交互,方便維護(hù)維修人員快速了解電動自行車狀況。搭建、設(shè)計、完成該物聯(lián)網(wǎng)系統(tǒng),實現(xiàn)共享電動自行車、用戶、管理人員之間的互聯(lián)互通,實現(xiàn)電動自行車數(shù)據(jù)采集、控制、傳輸、存儲、查詢和顯示的全過程,用戶能夠更加方便地使用共享電動自行車,管理人員也能更加清晰透明地了解電動自行車實時和歷史狀態(tài)。
一、實現(xiàn)效果
1. 模式選擇
2. 普通用戶
3. 巡檢人員
…
…
視頻演示
物聯(lián)網(wǎng)共享電單車管理系統(tǒng)
二、程序設(shè)計
本篇中信號與槽用之最多,且大多控件都是直接在ui界面設(shè)置的,這樣方便在比賽中修改,所以我在這只對主要部分進(jìn)行簡述,如需詳情請留言評論區(qū)。
1. 界面背景圖設(shè)計
界面背景圖一般放置構(gòu)造函數(shù)中,且在ui->setupUi(this);之后
QPixmap pixmap = QPixmap(":/picture/pc10.png").scaled(this->size()); //設(shè)置背景圖片
QPalette palette (this->palette());
palette .setBrush(QPalette::Background, QBrush(pixmap));
this-> setPalette( palette );
2. 信號槽設(shè)計
這里我介紹倆種常見的信號槽設(shè)計:
(1) 在ui界面中對要設(shè)置的信號控件右擊
這樣,系統(tǒng)就會自動給你創(chuàng)建出信號槽,你只用在該槽內(nèi)設(shè)置操作數(shù)即可。
(2) 用connect函數(shù)中進(jìn)行編寫信號槽 如:
connect(ui->pushButton,&QPushButton::clicked,[=](){
this->hide();
Widget *w=new Widget;
w->show();
});
上述操作為,在該文件的ui界面 點擊名為pushButton的控件(&QPushButton::clicked為文件QPushbutton自帶的點擊函數(shù)),如何觸發(fā)信號執(zhí)行={ };里面的操作。
3. 定時器設(shè)計
定時器的概念就不用我多說了把,畢竟都是學(xué)這行的,顧名思義,定時器就是用來定時的,直接上操作代碼,簡單粗暴且易懂。
timerDrawLine = new QTimer();
timerDrawLine->start(500);
connect(timerDrawLine,&QTimer::timeout,[=](){
DrawLine();
});
}
用計時器之前記得定義頭文件#include 哦,簡單來說 這幾句代碼的意思是創(chuàng)建一個名為timerDrawLine 的定時器,設(shè)置定時時間位500ms(注意單位是ms <1s=1000ms>),connect函數(shù)上面剛介紹完,&QTimer::timeout的意思是到設(shè)置時間了,就立即執(zhí)行={ }里面些操作代碼。
4. 動態(tài)曲/折線圖的設(shè)計
在這里我引入隨機數(shù),通過不斷產(chǎn)生的隨機數(shù)再結(jié)合定時器動態(tài)畫出曲/折線圖,定時器中操作為:
timerDrawLine = new QTimer();
timerDrawLine->start(500);
connect(timerDrawLine,&QTimer::timeout,[=](){
DrawLine();
});
在pro文件中記得加上 QT += charts
不廢話,曲/折線程序設(shè)計為:
#include <QtCharts/QChartView>
#include <QtCharts/QSplineSeries>
#include <QtCharts/QLineSeries>
#include <QValueAxis>
#include <QTimer>
QT_CHARTS_USE_NAMESPACE
#define MAX_X 10
#define MAX_Y 100
void lineseries::Chart_Init()
{
//初始化QChart的實例
chart = new QChart();
//初始化QSplineSeries的實例
lineSeries = new QSplineSeries();
//lineSeries = new QLineSeries();
//設(shè)置曲線的名稱
lineSeries->setName("隨機數(shù)測試曲線");
//把曲線添加到QChart的實例chart中
chart->addSeries(lineSeries);
//聲明并初始化X軸、兩個Y軸
QValueAxis *axisX = new QValueAxis();
QValueAxis *axisY = new QValueAxis();
//設(shè)置坐標(biāo)軸顯示的范圍
axisX->setMin(0);
axisX->setMax(MAX_X);
axisY->setMin(0);
axisY->setMax(MAX_Y);
//設(shè)置坐標(biāo)軸上的格點
axisX->setTickCount(11);
axisY->setTickCount(11);
//設(shè)置坐標(biāo)軸顯示的名稱
QFont font("Microsoft YaHei",8,QFont::Normal);//微軟雅黑。字體大小8
axisX->setTitleFont(font);
axisY->setTitleFont(font);
axisX->setTitleText("X-Test");
axisY->setTitleText("Y-Test");
//設(shè)置網(wǎng)格不顯示
axisY->setGridLineVisible(false);
//下方:Qt::AlignBottom,左邊:Qt::AlignLeft
//右邊:Qt::AlignRight,上方:Qt::AlignTop
chart->addAxis(axisX, Qt::AlignBottom);
chart->addAxis(axisY, Qt::AlignLeft);
//把曲線關(guān)聯(lián)到坐標(biāo)軸
lineSeries->attachAxis(axisX);
lineSeries->attachAxis(axisY);
//把chart顯示到窗口上
ui->graphicsView1->setChart(chart);
ui->graphicsView1->setRenderHint(QPainter::Antialiasing); // 設(shè)置渲染:抗鋸齒,如果不設(shè)置那么曲線就顯得不平滑
}
void lineseries::DrawLine()
{
static int count = 0;
if(count > MAX_X)
{
//當(dāng)曲線上最早的點超出X軸的范圍時,剔除最早的點,
lineSeries->removePoints(0,lineSeries->count() - MAX_X);
// 更新X軸的范圍
chart->axisX()->setMin(count - MAX_X);
chart->axisX()->setMax(count);
//當(dāng)折線上最早的點超出X軸的范圍時,剔除最早的點,
lineSeries1->removePoints(0,lineSeries1->count() - MAX_X);
// 更新X軸的范圍
chart1->axisX()->setMin(count - MAX_X);
chart1->axisX()->setMax(count);
}
//增加新的點到曲線末端
int ht=rand()%94+2;
lineSeries->append(count, ht);//隨機生成2到95的隨機數(shù)
lineSeries1->append(count, ht);
count ++;
}
void lineseries::Chart_Init1()
{
//初始化QChart的實例
chart1 = new QChart();
//初始化QSplineSeries的實例
lineSeries1 = new QLineSeries();
//設(shè)置曲線的名稱
lineSeries1->setName("隨機數(shù)測試折線");
//把折線添加到QChart的實例chart中
chart1->addSeries(lineSeries1);
//聲明并初始化X軸、兩個Y軸
QValueAxis *axisX = new QValueAxis();
QValueAxis *axisY = new QValueAxis();
//設(shè)置坐標(biāo)軸顯示的范圍
axisX->setMin(0);
axisX->setMax(MAX_X);
axisY->setMin(0);
axisY->setMax(MAX_Y);
//設(shè)置坐標(biāo)軸上的格點
axisX->setTickCount(11);
axisY->setTickCount(11);
//設(shè)置坐標(biāo)軸顯示的名稱
QFont font("Microsoft YaHei",8,QFont::Normal);//微軟雅黑。字體大小8
axisX->setTitleFont(font);
axisY->setTitleFont(font);
axisX->setTitleText("X-Test");
axisY->setTitleText("Y-Test");
//設(shè)置網(wǎng)格不顯示
axisY->setGridLineVisible(false);
//下方:Qt::AlignBottom,左邊:Qt::AlignLeft
//右邊:Qt::AlignRight,上方:Qt::AlignTop
chart1->addAxis(axisX, Qt::AlignBottom);
chart1->addAxis(axisY, Qt::AlignLeft);
//把折線關(guān)聯(lián)到坐標(biāo)軸
lineSeries1->attachAxis(axisX);
lineSeries1->attachAxis(axisY);
//把chart顯示到窗口上
ui->graphicsView2->setChart(chart1);
ui->graphicsView2->setRenderHint(QPainter::Antialiasing); // 設(shè)置渲染:抗鋸齒,如果不設(shè)置那么折線就顯得不平滑
}
5. 攝像頭掃碼
此功能用于開發(fā)的app在移動端模擬掃描自行車上的二維碼,將捕獲到的數(shù)據(jù)發(fā)送到服務(wù)器,服務(wù)器獲取該自行車的相關(guān)信息,進(jìn)行判斷自行車是否滿足解鎖條件,再將數(shù)據(jù)返回到移動端。
開啟攝像須在pro文件中添加
QT += multimedia multimediawidgets
其中Multimedia模塊提供了豐富的接口,可以輕松地使用平臺的多媒體功能。例如進(jìn)行媒體播放、使用相機和收音機等;multimediawidgets可以實現(xiàn)點擊播放按鈕,可以播放視頻;點擊暫停按鈕,可以停止播放視頻;拉動進(jìn)度條,可以定位視頻播放位置。
首先,定義相關(guān)類名,這里為考慮讀者通俗易懂,我起類名為“saoma”進(jìn)行演示,在頭文件里定義好相關(guān)對象 如下:
QCamera *camera;
QCameraViewfinder *viewfinder;
QCameraImageCapture *imageCapture;
QImage image;
然后在構(gòu)造函數(shù)中操作攝像頭,攝像頭會自動獲取設(shè)備資源,若無攝像頭功能,會自動報錯 具體操作如下:
//攝像頭信息獲取
QList<QCameraInfo> cameras = QCameraInfo::availableCameras();
foreach (const QCameraInfo &cameraInfo, cameras) {
camera = new QCamera(cameraInfo);
qDebug()<<cameraInfo.deviceName();
}
//設(shè)置攝像頭捕獲模式
camera->setCaptureMode(QCamera::CaptureStillImage);
//圖像回顯
viewfinder = new QCameraViewfinder(this);
camera->setViewfinder(viewfinder);
this->setCentralWidget(viewfinder);
//QCameraImageCapture 是獲取攝像頭捕捉的圖片 相關(guān)類
imageCapture = new QCameraImageCapture(camera);
//啟動攝像頭
this->camera->start();
運行如下:
6. 注冊設(shè)計
在登錄、注冊操作中,較難設(shè)計的是判斷這個用戶的是否達(dá)到注冊要求的標(biāo)準(zhǔn),如用戶名不得含有“@#*&”類似的特殊字符,倆次密碼需要輸入相同,手機號需要11位;登陸時檢測這個用戶是否已注冊,賬號密碼是否存在,忘記密碼時需要點擊找回密碼且在找回密碼的界面里手機號不得輸入錯誤等等。
(1) 創(chuàng)建用戶類user,引入vector容器用于存儲和判斷
#include "user.h"
#include <QString>
#include <QDebug>
User::User()
{
}
QList<User *> User::userlist;
User::User(QString userName,QString userPwd,QString userNumber)
{
this->userName = userName;
this->userPwd = userPwd;
this->userNumber = userNumber;
this->userState =0;//0為不在線
}
User::User(QString userName, QString userPwd, QString userNumber, int userState)
{
this->userName = userName;
this->userPwd = userPwd;
this->userNumber = userNumber;
this->userState =userState;//1為在線
}
//用戶名
QString User::GetUserName()
{
return userName;
}
void User::SetUserName(QString userName)
{
this->userName = userName;
}
//密碼
QString User::GetUserPwd()
{
return userPwd;
}
void User::SetUserPwd(QString userPwd)
{
this->userPwd = userPwd;
}
//手機號
QString User::GetUserNumber()
{
return userNumber;
}
void User::SetUserNumber(QString userNumber)
{
this->userNumber = userNumber;
}
//用戶狀態(tài)
int User::GetUserState()
{
return userState;
}
void User::SetUserState(int userState)
{
this->userState = userState;
}
void User::print()
{
for (int i=0;i<userlist.size();i++) {
qDebug()<<userlist.at(i);
}
}
(2) 輸入判斷
if(ui->userEdit->text()=="")//名字判斷
{
//彈窗(是否指定窗口,標(biāo)題,內(nèi)容)
QMessageBox::information(NULL,"錯誤","用戶名為空");
}
else if(ui->pwdEdit->text()=="")//密碼判斷
{
QMessageBox::information(NULL,"錯誤","密碼為空");
}
else if(ui->pwdEdit->text().length()<6)//密碼長度判斷
{
QMessageBox::information(NULL,"錯誤","密碼長度有誤");
}
else if(ui->nextpwdEdit->text()=="")
{
QMessageBox::information(NULL,"錯誤","重新輸入密碼為空");
}
else if(ui->nextpwdEdit->text().length()<6)//重新輸入密碼長度判斷
{
QMessageBox::information(NULL,"錯誤","重新輸入密碼長度有誤");
}
else if(ui->numberEdit->text()=="")
{
QMessageBox::information(NULL,"錯誤","密碼為空");
}
else if(ui->numberEdit->text().length()<11)//判斷電話號碼長度
{
QMessageBox::information(NULL,"錯誤","電話號碼長度有誤");
}
else if(ui->nextpwdEdit->text()!=ui->pwdEdit->text())
{
QMessageBox::information(NULL,"錯誤","密碼和重新輸入密碼不一致");
}
else
{
int i=0;//判斷次數(shù)
for(i=0;i<User::userlist.size();i++)
{
if(ui->userEdit->text()==User::userlist.at(i)->GetUserName())//名字是否已被注冊判斷
{
QMessageBox::information(NULL,"錯誤","名字已被注冊");
break;
}
else if(ui->numberEdit->text()==User::userlist.at(i)->GetUserNumber())//電話號碼是否已被注冊判斷
{
QMessageBox::information(NULL,"錯誤","電話號碼已被注冊");
break;
}
}
if(i>=User::userlist.size())
{
User *newuser = new User(ui->userEdit->text(),ui->pwdEdit->text(),ui->numberEdit->text());
User::userlist.push_back(newuser);
QMessageBox::information(NULL,"成功","注冊成功");
this->hide(); //關(guān)閉注冊界面窗口
}
}
void Widget::regSlot(QString name,QString pwd,QString number)
{
User *newuser = new User(name,pwd,number);
User::userlist.push_back(newuser);
}
7. 登錄設(shè)計
在登錄界面需要輸入已注冊好的賬號與密碼,若忘記密碼需要點擊界面下方的”找回密碼“,按照設(shè)計要求一步步操作,輸入正確的手機號,獲取驗證碼,輸入新密碼等。
在界面登錄上方我設(shè)計了一個“輸出已存儲的用戶”按鈕,實則是給程序員設(shè)計的,這樣方便查看已注冊的用戶信息;其次 界面還添加了“自動登錄”和“記住密碼”功能,因為我其實是根據(jù)“騰訊QQ”的樣式進(jìn)行設(shè)計的(haha)。
(1) 判斷用戶輸入是否有誤
void Widget::on_btn_denglu_clicked()
{
int flag=0;
for (int i=0;i<User::userlist.size();i++) {
if(ui->yonghuming->text()==User::userlist.at(i)->GetUserName()){
flag=1;
if(ui->mima->text()==User::userlist.at(i)->GetUserPwd()){
QMessageBox::information(NULL,"success","登錄成功");
}
else {
QMessageBox::information(NULL,"error","密碼錯誤");
}
}
}
if(flag==0) QMessageBox::information(NULL,"error","用戶不存在");
}
(2) 二維碼設(shè)計
點擊右下方的二維碼可彈出一個二維碼對話框,支持掃碼登錄。
8. 巡檢人員設(shè)計
巡檢人員相當(dāng)于管理員,權(quán)限自然大些,所以在這里我就沒設(shè)計巡檢人員的注冊功能,直接在程序中給定了巡檢人員的賬號密碼,正確輸入即可成功登錄,登錄成功后可查看硬件“自行車”的相關(guān)信息,即自行車電壓、電流、溫濕度、氣壓、速度等等,詳情可在上方界面中查看,這些每個控件我都有給其設(shè)置專有的信號槽,這樣方便與服務(wù)器那邊交接(按提要求可知,最終開發(fā)出來的app是要和服務(wù)器交互的,不可能自己跟自己玩是吧)。
在這里我用的是上方介紹的第一種信號槽方式設(shè)計:
void root_set::on_ton1_clicked()
{
qDebug()<<"點擊了藍(lán)牙選擇框";
}
void root_set::on_ton2_clicked()
{
qDebug()<<"點擊了掃描";
}
void root_set::on_ton3_clicked()
{
qDebug()<<"點擊了斷開";
}
void root_set::on_ton4_clicked()
{
qDebug()<<"點擊了發(fā)送";
}
void root_set::on_ton5_clicked()
{
qDebug()<<"點擊了獲取";
}
void root_set::on_ton6_clicked()
{
qDebug()<<"點擊了清空";
}
void root_set::on_ton7_clicked()
{
qDebug()<<"點擊了設(shè)定";
}
void root_set::on_ton8_clicked()
{
qDebug()<<"點擊了開控制";
}
void root_set::on_ton9_clicked()
{
qDebug()<<"點擊了關(guān)控制";
}
void root_set::on_ton10_clicked()
{
qDebug()<<"點擊了圖表";
lineseries *line=new lineseries;
line->show();
}
void root_set::on_ton11_clicked()
{
qDebug()<<"點擊了時間";
}
void root_set::on_ton12_clicked()
{
qDebug()<<"點擊了轉(zhuǎn)速";
}
void root_set::on_ton13_clicked()
{
qDebug()<<"點擊了電壓";
}
void root_set::on_ton14_clicked()
{
qDebug()<<"點擊了電流";
}
void root_set::on_ton15_clicked()
{
qDebug()<<"點擊了所有";
}
void root_set::on_ton16_clicked()
{
qDebug()<<"點擊了查詢";
}
void root_set::on_toolButton_clicked()
{
this->hide();
action * ac=new action;
ac->show();
}
三、綜合分析
在此項目中,我?guī)缀跛锌丶荚趗i界面中設(shè)計的,(在平時操作中 我不是不推薦在ui界面操作的),這樣確實省了不少事,但不利于實際的項目開發(fā),項目文件如下:文章來源:http://www.zghlxwxcb.cn/news/detail-676614.html
需要Qt相關(guān)資料或項目源碼的可以留言評論區(qū)或直接私信我 Respect!文章來源地址http://www.zghlxwxcb.cn/news/detail-676614.html
到了這里,關(guān)于Qt 物聯(lián)網(wǎng)系統(tǒng)界面開發(fā) “ 2022湖南省大學(xué)生物聯(lián)網(wǎng)應(yīng)用創(chuàng)新設(shè)計競賽技能賽 ——應(yīng)用物聯(lián)網(wǎng)的共享電動自行車 ”的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!