You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

widget.cpp 20 kB

5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556
  1. /*
  2. * Copyright (C) 2021 刘臣轩
  3. *
  4. * This program is free software: you can redistribute it and/or modify
  5. * it under the terms of the GNU General Public License as published by
  6. * the Free Software Foundation, either version 3 of the License, or
  7. * (at your option) any later version.
  8. *
  9. * This program is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  16. */
  17. #include "widget.h"
  18. #include "ui_widget.h"
  19. Widget::Widget(QWidget* parent)
  20. : QWidget(parent)
  21. , ui(new Ui::Widget)
  22. {
  23. ui->setupUi(this);
  24. connect(ui->pushButton, SIGNAL(clicked()), this, SLOT(close()));
  25. ui->frame->setStyleSheet("#frame {border-image: url(:/new/prefix1/image/主.png);}");
  26. ui->textEdit->append("开始初始化设备");
  27. // Time
  28. QTimer* timer = new QTimer(this);
  29. connect(timer, SIGNAL(timeout()), this, SLOT(timerUpdate()));
  30. timer->start(500);
  31. initSerial();
  32. #ifdef Q_OS_WIN
  33. initCamera();
  34. #else
  35. connect(this, SIGNAL(imageCaptured(int, QImage)), this, SLOT(onImageCaptured(int, QImage)));
  36. ui->textEdit->append("摄像头初始化成功");
  37. #endif
  38. // Network
  39. networkManager = new QNetworkAccessManager();
  40. networkRequest = new QNetworkRequest();
  41. networkRequest->setHeader(QNetworkRequest::ContentTypeHeader, " application/json;charset=UTF-8");
  42. url = new QUrl("https://aiapi.jd.com/jdai/garbageImageSearch");
  43. connect(networkManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(onRequestFinished(QNetworkReply*)));
  44. ui->label_3->setText("工训大赛");
  45. ui->label_4->setStyleSheet("border-image: url(:/new/prefix1/image/工训大赛.png);\nborder-radius: 10px;\n");
  46. ui->label_4->setVisible(true);
  47. ui->label_5->setVisible(false);
  48. ui->textEdit->append("设备初始化成功√");
  49. number = 0;
  50. // Video
  51. player = new QMediaPlayer;
  52. videoWidget = new QVideoWidget(this);
  53. playList = new QMediaPlaylist;
  54. #ifdef Q_OS_WIN
  55. playList->addMedia(QUrl::fromLocalFile("../WasteSorting/test.mp4"));
  56. #else
  57. playList->addMedia(QUrl::fromLocalFile("/home/pi/WasteSorting/test.mp4"));
  58. #endif
  59. playList->setPlaybackMode(QMediaPlaylist::CurrentItemInLoop);
  60. player->setPlaylist(playList);
  61. player->setVideoOutput(videoWidget);
  62. ui->verticalLayout->addWidget(videoWidget);
  63. videoWidget->setVisible(false);
  64. videoTimer = new QTimer(this);
  65. connect(videoTimer, SIGNAL(timeout()), this, SLOT(videoTimerUpdate()));
  66. videoTimer->setSingleShot(true);
  67. videoTimer->start(10000);
  68. #ifdef Q_OS_WIN
  69. #else
  70. // Tensorflow
  71. model = tflite::FlatBufferModel::BuildFromFile(model_file.c_str());
  72. tflite::InterpreterBuilder(*model, resolver)(&interpreter);
  73. interpreter->SetNumThreads(4);
  74. interpreter->AllocateTensors();
  75. input_tensor = interpreter->tensor(interpreter->inputs()[0]);
  76. TfLiteIntArray* output_dims = interpreter->tensor(interpreter->outputs()[0])->dims;
  77. output_size = output_dims->data[output_dims->size - 1];
  78. #endif
  79. //captureImage();
  80. }
  81. Widget::~Widget()
  82. {
  83. delete ui;
  84. }
  85. void Widget::timerUpdate()
  86. {
  87. QString str = QDateTime::currentDateTime().toString("yyyy年MM月dd日 hh:mm:ss");
  88. ui->label->setText(str);
  89. }
  90. void Widget::videoTimerUpdate()
  91. {
  92. ui->label_4->setVisible(false);
  93. player->play();
  94. videoWidget->setVisible(true);
  95. ui->label_3->setText("播放视频");
  96. ui->textEdit->append("播放视频");
  97. }
  98. void Widget::initSerial()
  99. {
  100. ui->textEdit->append("开始初始化串口");
  101. serialPort = new QSerialPort();
  102. connect(serialPort, SIGNAL(readyRead()), this, SLOT(serialRead()));
  103. if (QSerialPortInfo::availablePorts().length() == 0) {
  104. QMessageBox::critical(this, "错误", "无可用串口设备,请检查硬件连接后重试");
  105. exit(0);
  106. }
  107. #ifdef Q_OS_WIN
  108. QString portName = QSerialPortInfo::availablePorts()[1].portName();
  109. qDebug() << portName;
  110. ui->textEdit->append("尝试连接串口" + portName);
  111. serialPort->setPortName(portName);
  112. #else
  113. QString portName = "ttyUSB0";
  114. ui->textEdit->append("尝试连接串口ttyUSB0");
  115. serialPort->setPortName("ttyUSB0");
  116. #endif
  117. if (serialPort->open(QIODevice::ReadWrite)) {
  118. ui->textEdit->append("串口连接成功");
  119. serialPort->setBaudRate(115200);
  120. serialPort->setDataBits(QSerialPort::Data8);
  121. serialPort->setParity(QSerialPort::NoParity);
  122. serialPort->setStopBits(QSerialPort::OneStop);
  123. } else {
  124. QMessageBox::critical(this, "错误", "串口设备" + portName + "无法打开,请检查硬件连接后重试");
  125. exit(0);
  126. }
  127. ui->textEdit->append("串口初始化成功");
  128. serialWrite('\xCC');
  129. }
  130. void Widget::initCamera()
  131. {
  132. // for (QCameraInfo& info : QCameraInfo::availableCameras()) {
  133. // qDebug() << info.deviceName();
  134. // }
  135. int camNum = QCameraInfo::availableCameras().length();
  136. if (!camNum) {
  137. QMessageBox::critical(this, "错误", "无可用摄像头,请检查硬件连接后重试");
  138. exit(0);
  139. }
  140. ui->textEdit->append("开始初始化摄像头");
  141. camera = new QCamera(QCameraInfo::availableCameras()[0], this);
  142. imageCapture = new QCameraImageCapture(camera);
  143. connect(imageCapture, SIGNAL(imageCaptured(int, QImage)), this, SLOT(onImageCaptured(int, QImage)));
  144. camera->setCaptureMode(QCamera::CaptureStillImage);
  145. imageCapture->setCaptureDestination(QCameraImageCapture::CaptureToBuffer);
  146. camera->start();
  147. ui->textEdit->append("摄像头初始化成功");
  148. }
  149. void Widget::serialRead()
  150. {
  151. QByteArray buffer = serialPort->readAll();
  152. // qDebug() << buffer;
  153. if (buffer[0] == '\x03' && buffer[1] == '\xFC'
  154. && buffer[3] == '\xFC' && buffer[4] == '\x03') {
  155. switch (buffer[2]) {
  156. case '\x00':
  157. ui->textEdit->append("取消警报");
  158. ui->label_3->setText("取消警报");
  159. ui->label_4->setVisible(true);
  160. ui->label_5->setVisible(false);
  161. ui->frame->setStyleSheet("#frame {border-image: url(:/new/prefix1/image/主.png);}");
  162. videoTimer->start(10000);
  163. break;
  164. case '\x01':
  165. ui->textEdit->append("触发拍照信号");
  166. ui->label_3->setText("触发拍照");
  167. videoTimer->stop();
  168. videoWidget->setVisible(false);
  169. player->stop();
  170. #ifdef Q_OS_WIN
  171. imageCapture->capture();
  172. #else
  173. captureImage();
  174. #endif
  175. break;
  176. case '\x02':
  177. ui->textEdit->append("投递完毕");
  178. ui->label_3->setText("投递完毕");
  179. ui->label_4->setVisible(true);
  180. ui->label_5->setVisible(false);
  181. ui->frame->setStyleSheet("#frame {border-image: url(:/new/prefix1/image/主.png);}");
  182. videoTimer->start(10000);
  183. break;
  184. case '\x04':
  185. ui->textEdit->append("满载警报");
  186. ui->label_3->setText("满载警报");
  187. ui->label_4->setVisible(false);
  188. videoTimer->stop();
  189. videoWidget->setVisible(false);
  190. player->stop();
  191. ui->frame->setStyleSheet("#frame {border-image: url(:/new/prefix1/image/满载警报.png);}");
  192. break;
  193. case '\x08':
  194. // qDebug() << "倾倒警报";
  195. ui->textEdit->append("倾倒警报");
  196. ui->label_3->setText("倾倒警报");
  197. ui->label_4->setVisible(false);
  198. videoTimer->stop();
  199. videoWidget->setVisible(false);
  200. player->stop();
  201. ui->frame->setStyleSheet("#frame {border-image: url(:/new/prefix1/image/倾倒警报.png);}");
  202. break;
  203. case '\xFF':
  204. break;
  205. }
  206. }
  207. }
  208. void Widget::serialWrite(const char data)
  209. {
  210. QByteArray buffer("\x30\xCF\x0F\xCF\x30");
  211. buffer[2] = data;
  212. serialPort->write(buffer);
  213. }
  214. QImage Widget::cvMat2QImage(const cv::Mat& mat)
  215. {
  216. // 8-bits unsigned, NO. OF CHANNELS = 1
  217. if(mat.type() == CV_8UC1)
  218. {
  219. QImage image(mat.cols, mat.rows, QImage::Format_Indexed8);
  220. // Set the color table (used to translate colour indexes to qRgb values)
  221. image.setColorCount(256);
  222. for(int i = 0; i < 256; i++)
  223. {
  224. image.setColor(i, qRgb(i, i, i));
  225. }
  226. // Copy input Mat
  227. uchar *pSrc = mat.data;
  228. for(int row = 0; row < mat.rows; row ++)
  229. {
  230. uchar *pDest = image.scanLine(row);
  231. memcpy(pDest, pSrc, mat.cols);
  232. pSrc += mat.step;
  233. }
  234. return image;
  235. }
  236. // 8-bits unsigned, NO. OF CHANNELS = 3
  237. else if(mat.type() == CV_8UC3)
  238. {
  239. // Copy input Mat
  240. const uchar *pSrc = (const uchar*)mat.data;
  241. // Create QImage with same dimensions as input Mat
  242. QImage image(pSrc, mat.cols, mat.rows, mat.step, QImage::Format_RGB888);
  243. return image.rgbSwapped();
  244. }
  245. else if(mat.type() == CV_8UC4)
  246. {
  247. qDebug() << "CV_8UC4";
  248. // Copy input Mat
  249. const uchar *pSrc = (const uchar*)mat.data;
  250. // Create QImage with same dimensions as input Mat
  251. QImage image(pSrc, mat.cols, mat.rows, mat.step, QImage::Format_ARGB32);
  252. return image.copy();
  253. }
  254. else
  255. {
  256. qDebug() << "ERROR: Mat could not be converted to QImage.";
  257. return QImage();
  258. }
  259. }
  260. void Widget::captureImage()
  261. {
  262. // system("raspistill -o ../WasteSorting/WasteSorting.jpg -t 1 -br 60 -hf -awb sun");
  263. // system("python3 ../WasteSorting/capture.py");
  264. //system("rm -rf /home/pi/WasteSorting/WasteSorting.jpg");
  265. capture = cv::VideoCapture(0);
  266. cv::Mat frame;
  267. capture >> frame;
  268. QImage image = cvMat2QImage(frame);
  269. capture.release();
  270. //cv::imwrite("/home/pi/WasteSorting/WasteSorting.jpg", frame);
  271. //QImage image("../WasteSorting/WasteSorting.jpg");
  272. emit(imageCaptured(0, image));
  273. }
  274. void Widget::onImageCaptured(int, QImage image)
  275. {
  276. // 显示图片
  277. ui->label_4->setVisible(false);
  278. ui->label_5->setPixmap(QPixmap::fromImage(image).scaled(405, 306));
  279. ui->label_5->setVisible(true);
  280. ui->label_3->setText("识别中");
  281. ui->frame->setStyleSheet("#frame {border-image: url(:/new/prefix1/image/识别中.png);}");
  282. /* 使用京东垃圾识别 API
  283. // Base64编码
  284. QByteArray ba;
  285. QBuffer buf(&ba);
  286. image.save(&buf, "JPG", -1);
  287. QByteArray imageBase64 = ba.toBase64();
  288. // qDebug() << "data:image/jpg;base64," + imageBase64;
  289. // Request
  290. sendRequest(imageBase64);
  291. */
  292. /* TensorFlow Lite Python
  293. #ifdef Q_OS_WIN
  294. image.save("../WasteSorting/WasteSorting.jpg");
  295. FILE* fp = _popen("python ../WasteSorting/tensorflow/label_image.py", "rt");
  296. char buf[255] = { 0 };
  297. fscanf(fp, "%s", buf);
  298. _pclose(fp);
  299. #else
  300. FILE* fp = popen("python3 ../WasteSorting/tensorflow/label_image.py", "r");
  301. char buf[255] = { 0 };
  302. printf("%s", buf);
  303. fscanf(fp, "%s", buf);
  304. pclose(fp);
  305. #endif
  306. QString cate_name = QString::fromLocal8Bit(buf);
  307. qDebug() << cate_name;
  308. classifyFinished(cate_name);
  309. */
  310. /* Tensorflow Lite C++ */
  311. image.save("../WasteSorting/WasteSorting.jpg");
  312. image = image.convertToFormat(QImage::Format_RGB888).mirrored(true, false);
  313. formatImageTFLite<uint8_t>(interpreter->typed_tensor<uint8_t>(interpreter->inputs()[0]), image.bits(),
  314. image.height(), image.width(), 3, 224, 224, 3, false);
  315. interpreter->Invoke();
  316. std::vector<std::pair<float, int>> top_results;
  317. get_top_n<uint8_t>(interpreter->typed_output_tensor<uint8_t>(0),
  318. output_size, 1, 0.01f, &top_results, kTfLiteUInt8);
  319. int index = top_results[0].second;
  320. QString cate_name;
  321. switch(index) {
  322. case 0:
  323. cate_name = "识别失败";
  324. break;
  325. case 1:case 2:case 10:
  326. cate_name = "有害垃圾";
  327. break;
  328. case 3:case 4:case 5:case 11:
  329. cate_name = "可回收垃圾";
  330. break;
  331. case 6:case 7:case 12:case 13:
  332. cate_name = "厨余垃圾";
  333. break;
  334. case 8:case 9:
  335. cate_name = "其他垃圾";
  336. break;
  337. }
  338. qDebug() << cate_name;
  339. classifyFinished(cate_name);
  340. }
  341. template <class T>
  342. void Widget::formatImageTFLite(T* out, const uint8_t* in, int image_height, int image_width, int image_channels, int wanted_height, int wanted_width, int wanted_channels, bool input_floating)
  343. {
  344. const float input_mean = 127.5f;
  345. const float input_std = 127.5f;
  346. int number_of_pixels = image_height * image_width * image_channels;
  347. std::unique_ptr<tflite::Interpreter> interpreter(new tflite::Interpreter);
  348. int base_index = 0;
  349. // two inputs: input and new_sizes
  350. interpreter->AddTensors(2, &base_index);
  351. // one output
  352. interpreter->AddTensors(1, &base_index);
  353. // set input and output tensors
  354. interpreter->SetInputs({0, 1});
  355. interpreter->SetOutputs({2});
  356. // set parameters of tensors
  357. TfLiteQuantizationParams quant;
  358. interpreter->SetTensorParametersReadWrite(0, kTfLiteFloat32, "input", {1, image_height, image_width, image_channels}, quant);
  359. interpreter->SetTensorParametersReadWrite(1, kTfLiteInt32, "new_size", {2},quant);
  360. interpreter->SetTensorParametersReadWrite(2, kTfLiteFloat32, "output", {1, wanted_height, wanted_width, wanted_channels}, quant);
  361. tflite::ops::builtin::BuiltinOpResolver resolver;
  362. const TfLiteRegistration *resize_op = resolver.FindOp(tflite::BuiltinOperator_RESIZE_BILINEAR,1);
  363. auto* params = reinterpret_cast<TfLiteResizeBilinearParams*>(malloc(sizeof(TfLiteResizeBilinearParams)));
  364. params->align_corners = false;
  365. interpreter->AddNodeWithParameters({0, 1}, {2}, nullptr, 0, params, resize_op, nullptr);
  366. interpreter->AllocateTensors();
  367. // fill input image
  368. // in[] are integers, cannot do memcpy() directly
  369. auto input = interpreter->typed_tensor<float>(0);
  370. for (int i = 0; i < number_of_pixels; i++)
  371. input[i] = in[i];
  372. // fill new_sizes
  373. interpreter->typed_tensor<int>(1)[0] = wanted_height;
  374. interpreter->typed_tensor<int>(1)[1] = wanted_width;
  375. interpreter->Invoke();
  376. auto output = interpreter->typed_tensor<float>(2);
  377. auto output_number_of_pixels = wanted_height * wanted_height * wanted_channels;
  378. for (int i = 0; i < output_number_of_pixels; i++)
  379. {
  380. if (input_floating)
  381. out[i] = (output[i] - input_mean) / input_std;
  382. else
  383. out[i] = (uint8_t)output[i];
  384. }
  385. }
  386. template <class T>
  387. void Widget::get_top_n(T* prediction, int prediction_size, size_t num_results,
  388. float threshold, std::vector<std::pair<float, int>>* top_results,
  389. TfLiteType input_type) {
  390. // Will contain top N results in ascending order.
  391. std::priority_queue<std::pair<float, int>, std::vector<std::pair<float, int>>,
  392. std::greater<std::pair<float, int>>>
  393. top_result_pq;
  394. const long count = prediction_size; // NOLINT(runtime/int)
  395. float value = 0.0;
  396. for (int i = 0; i < count; ++i) {
  397. switch (input_type) {
  398. case kTfLiteFloat32:
  399. value = prediction[i];
  400. break;
  401. case kTfLiteInt8:
  402. value = (prediction[i] + 128) / 256.0;
  403. break;
  404. case kTfLiteUInt8:
  405. value = prediction[i] / 255.0;
  406. break;
  407. default:
  408. break;
  409. }
  410. // Only add it if it beats the threshold and has a chance at being in
  411. // the top N.
  412. if (value < threshold) {
  413. continue;
  414. }
  415. top_result_pq.push(std::pair<float, int>(value, i));
  416. // If at capacity, kick the smallest value out.
  417. if (top_result_pq.size() > num_results) {
  418. top_result_pq.pop();
  419. }
  420. }
  421. // Copy to output vector and reverse into descending order.
  422. while (!top_result_pq.empty()) {
  423. top_results->push_back(top_result_pq.top());
  424. top_result_pq.pop();
  425. }
  426. std::reverse(top_results->begin(), top_results->end());
  427. }
  428. void Widget::sendRequest(QByteArray& imageBase64)
  429. {
  430. QUrlQuery query;
  431. query.addQueryItem("appkey", "3a24b33468565b633d25d426eb0c660c");
  432. qint64 timestamp = QDateTime::currentDateTime().toMSecsSinceEpoch();
  433. query.addQueryItem("timestamp", QString::number(timestamp));
  434. QString sign = "58125e5985e6ef2d385ebfaa646987ba" + QString::number(timestamp);
  435. QByteArray ba = QCryptographicHash::hash(sign.toUtf8(), QCryptographicHash::Md5);
  436. query.addQueryItem("sign", ba.toHex());
  437. url->setQuery(query);
  438. networkRequest->setUrl(*url);
  439. // qDebug() << query.toString();
  440. QJsonObject json;
  441. json.insert("imgBase64", QString(imageBase64));
  442. json.insert("cityId", "440300");
  443. QJsonDocument document;
  444. document.setObject(json);
  445. QByteArray data = document.toJson(QJsonDocument::Compact);
  446. // qDebug() << QString(data);
  447. networkManager->post(*networkRequest, data);
  448. }
  449. void Widget::onRequestFinished(QNetworkReply* reply)
  450. {
  451. QVariant statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute);
  452. if (!statusCode.isValid()) {
  453. QMessageBox::critical(this, "错误", "网络连接不可用,请检查后重试");
  454. exit(0);
  455. }
  456. QByteArray replyData = reply->readAll();
  457. QJsonParseError jsonError;
  458. QJsonDocument document = QJsonDocument::fromJson(replyData, &jsonError);
  459. if (!document.isNull() && (jsonError.error == QJsonParseError::NoError)) {
  460. QJsonObject object = document.object().value("result").toObject();
  461. QJsonArray array = object.value("garbage_info").toArray();
  462. QJsonObject max = std::max_element(array.begin(), array.end(),
  463. [](QJsonValue const& a, QJsonValue const& b) { return a.toObject().value("confidence").toDouble()
  464. < b.toObject().value("confidence").toDouble(); })
  465. ->toObject();
  466. QString cate_name = max.value("cate_name").toString();
  467. QString garbage_name = max.value("garbage_name").toString();
  468. double confidence = max.value("confidence").toDouble();
  469. // qDebug() << "cate_name:" << cate_name;
  470. // qDebug() << "garbage_name:" << garbage_name;
  471. // qDebug() << "confidence:" << confidence;
  472. // ui->textEdit->append("cate_name: " + cate_name);
  473. // ui->textEdit->append("garbage_name: " + garbage_name);
  474. // ui->textEdit->append("confidence: " + QString::number(confidence));
  475. classifyFinished(cate_name);
  476. } else {
  477. serialWrite('\xFD');
  478. //ui->textEdit->append("识别失败,请重试");
  479. //ui->label_3->setText("识别失败");
  480. ui->label_4->setVisible(true);
  481. ui->label_5->setVisible(false);
  482. ui->frame->setStyleSheet("#frame {border-image: url(:/new/prefix1/image/主.png);}");
  483. }
  484. }
  485. void Widget::classifyFinished(QString cate_name)
  486. {
  487. ui->frame->setStyleSheet("#frame {border-image: url(:/new/prefix1/image/" + cate_name + ".PNG);}");
  488. ui->label_3->setText("投递中");
  489. if (cate_name == "识别失败") {
  490. serialWrite('\xFD');
  491. //ui->textEdit->append("识别失败,请重试");
  492. //ui->label_3->setText("识别失败");
  493. ui->label_4->setVisible(true);
  494. ui->label_5->setVisible(false);
  495. ui->frame->setStyleSheet("#frame {border-image: url(:/new/prefix1/image/主.png);}");
  496. }else {
  497. number += 1;
  498. ui->textEdit->append(QString::number(number) + " " + cate_name + " 1 OK!");
  499. if (cate_name == "可回收垃圾")
  500. serialWrite('\x01');
  501. else if (cate_name == "厨余垃圾")
  502. serialWrite('\x02');
  503. else if (cate_name == "有害垃圾")
  504. serialWrite('\x04');
  505. else
  506. serialWrite('\x08');
  507. }
  508. }

No Description