文章目录

  • 前言
    • 关键词:无线通信;单片机;视频监控;android;WiFi
  • 一、材料
  • 二、模块的驱动(keil5写)
    • 代码1——onenet.c
  • 三、APP
    • 代码二——MainActivity
  • 总结

前言

关键词:无线通信;单片机;视频监控;android;WiFi

一、材料

1.1制作材料:

硬件系统主要由单片机主控模块、电源模块、电机驱动模块、WiFi通信模块和无线视频监控模块组成。
1.2主控模块
主控模块采用STM32F103为主控制器,STM32F103属于中低端的32位ARM微控制器,该系列芯片是意法半导体(ST)公司出品,其内核是Cortex-M3。该系列芯片按片内Flash的大小可分为三大类:小容量(16K和32K)、中容量(64K和128K)、大容量(256K、384K和512K)。芯片集成定时器,CAN,ADC,SPI,I2C,USB,UART,等多种功能。STM32F103可使用keilC语言编译,支持STLink-SWD在线调试,主要用于收集信息、处理数据、协调系统中的每个功能模块预计要完成的任务。(图3)
图3单片机

1.3 WiFi模块ESP8266
WIFI通信模块作为STM32和云平台通信的中介,两端都通过WIFI模块进行数据交互,该模块选用ESP8266芯片,其特点就是如果断开连接,再次连接,模块会连接到最近一次连接过的热点。数据将通过ESP8266存放到云平台,并且stm32也能通过ESP8266获取云平台的数据。以下表格1是ESP8266与STM32的接线图。WiFi模块ESP8266如图4所示。

图4WiFi模块ESP8266

1.4L298N电机驱动模块
电机驱动原理:小车左轮右轮上分别配有两个电机,左轮电机A与右轮电机B的正转、反转和停止决定着小车的运动模式。而STM32单片机4根电机控制信号线连接着L298N的IN1~IN4,另外两根PWM调速信号线连着ENA和ENB。输入信号线IN1和IN2控制电机A的运动,直流电机A接OUT1和OUT2。同理,IN3和IN4合起来控制了电机B的运动,如图5电机模块L298N所示。

图5电机模块L298N

电机调速原理:L298N上还有ENA和ENB两个信号输入端口,这两个端口的作用是控制信号的使能,低电平有效。由于L298N有控制使能的信号线,则可以通过控制ENA和ENB的信号来进行PWM调速。原理是开关管在一个周期T的时间内导通的时间为t,那么电机两端的平均电压U=V*t()T=aV。其中,a=t/T(占空比),V是电源电压。电动机的转速与电动机两端的电压成正比,而电动机两端的电压与控制波形的占空比成正比,因此电动机的转动速度与PWM信号的占空比成比例,信号的占空比越大电动机转动得越快。在硬件电路上将STM32单片机的PA0~PA3端口分别接到L298N的IN1~IN4上,通过改变PA0~PA3口的高低电平控制小车的行驶方向,通过调节信号线ENA和ENB上的PWM占空比来控制小车运动速度。

1.5电源模块DC-DC
DC-DC是用开关电源的思想实现的。DC-DC有降压和升压两种,这里叫降压。DC-DC内部有振荡器和斩波器模块。输出端有电容器,对中间的脉冲波形进行微积分,输出5V的直流波形。该降压的过程相对于恒压模块,更大幅度地避免了降压模块上的电力消耗,内部振荡部通过控制其占空比,输出恒定。例如在本次设计中使用输入为12V电源的降压模块,其中输出11V引脚给电机供电,输出3.3V引脚给单片机供电。下面图6所示为电源模块DC-DC。

图6电源模块DC-DC

二、模块的驱动(keil5写)

2.1小车制作部分
2.1.1主控制器
主控制器STM32F103C8T6以ARM32位CortexM3作为CPU,其开发环境为常用的ARM开发环境,本系统采用KeilμVision5作为开发工具。ARM公司在2015年发布的集成开发环境RealViewMDK集成了最新版本的KeilμVision5,其编译器、调试工具实现与ARM器件的最完美匹配,用C语言完成编程。

2.1.2控制小车的软件设计

电机的GPIO口的初始化,通过调用库函数RCC_APB2PeriphClockCmd[1],使能RCC_APB2Periph_GPIOA/RCC_APB2Periph_GPIOB端口时钟,而由于需要重映射,所以使能AFIO时钟RCC_APB2Periph_AFIO,之后通过复用推挽输出GPIO_Mode_Out_PP来将GPIO进行输出,输出到L298N的IN1~IN4,这里有两个电机,所以初始化了8个引脚,分别为PB引脚的GPIO_Pin_11,GPIO_Pin_12,和PA引脚的GPIO_Pin_3~GPIO_Pin_8。之后通过GPIO_SetBits拉高使能和GPIO_ResetBits拉低使能来控制电机的正反转动。
TIM3定时器的初始化,通过调用RCC_APB1PeriphClockCmd使能RCC_APB1Periph_TIM3,用于设定定时器3中断服务程序。
TIM1定时器的初始化,通过调用RCC_APB1PeriphClockCmd使能RCC_APB2Periph_TIM1,开启了TIM1的时钟之后,设置ARR和PSC两个寄存器的值来控制输出PWM的周期。之后输出比较通道1到4的初始化,之后,就可以控制TIM1的CH1到CH4输出PWM了,这里我使用的是PA6和PA7来进行左轮的使能,PB0和PB1进行右轮的使能。通过调整输出PWM波的频率还可以对轮子的转速进行调速。
关于小车的前进后退,可以这样实现:前进:左轮和右轮以同样的速率向前转动,小车向正前方运动;后退:左轮和右轮以同样的速率向后转动,小车向正后方运动。右转:当左轮速率大于右轮的速率时,小车右转;左转:当右轮速率大于左轮的速率时,小车左转。原地打转:当两轮速率相同,方向相反时,小车原地打转。转弯半径与差值的关系:小车转弯半径由左右电机数值差决定,差值越小,半径越大;差值越大,半径越小。以下图7为MCU控制小车的流程图。

代码1——onenet.c

代码如下(示例):

//单片机头文件
#include "stm32f10x.h"//网络设备
#include "esp8266.h"//协议文件
#include "onenet.h"
#include "mqttkit.h"//硬件驱动
#include "usart.h"//C库
#include <string.h>
#include <stdio.h>#define PROID       "111111"   //产品ID#define AUTH_INFO    "111111"      //鉴权信息  #define DEVID       "1111111" //设备IDextern unsigned char esp8266_buf[128];//==========================================================
//  函数名称:    OneNet_DevLink
//
//  函数功能:    与onenet创建连接
//
//  入口参数:    无
//
//  返回参数:    1-成功    0-失败
//
//  说明:      与onenet平台建立连接
//==========================================================
_Bool OneNet_DevLink(void)
{MQTT_PACKET_STRUCTURE mqttPacket = {NULL, 0, 0, 0};                   //协议包unsigned char *dataPtr;_Bool status = 1;printf("OneNet_DevLink\r\nPROID: %s, AUIF: %s,   DEVID:%s\r\n", PROID, AUTH_INFO, DEVID);if(MQTT_PacketConnect(PROID, AUTH_INFO, DEVID, 256, 0, MQTT_QOS_LEVEL0, NULL, NULL, 0, &mqttPacket) == 0){ESP8266_SendData(mqttPacket._data, mqttPacket._len);           //上传平台dataPtr = ESP8266_GetIPD(250);                                   //等待平台响应if(dataPtr != NULL){if(MQTT_UnPacketRecv(dataPtr) == MQTT_PKT_CONNACK){switch(MQTT_UnPacketConnectAck(dataPtr)){case 0:printf("Tips:    连接成功\r\n");status = 0;break;case 1:printf("WARN: 连接失败:协议错误\r\n");break;case 2:printf("WARN: 连接失败:非法的clientid\r\n");break;case 3:printf("WARN:  连接失败:服务器失败\r\n");break;case 4:printf("WARN:    连接失败:用户名或密码错误\r\n");break;case 5:printf("WARN: 连接失败:非法链接(比如token非法)\r\n");break;default:printf("ERR:  连接失败:未知错误\r\n");break;}}}MQTT_DeleteBuffer(&mqttPacket);                                //删包}elseprintf("WARN: MQTT_PacketConnect Failed\r\n");return status;}
u8 velue0 ;
u8 velue1 ;
unsigned char OneNet_FillBuf(char *buf)
{   char text[32];memset(text, 0, sizeof(text));//strcpy(buf, ",;");strcpy(buf, ",;");memset(text, 0, sizeof(text));sprintf(text, "temperature,%d;", velue0);strcat(buf, text);memset(text, 0, sizeof(text));sprintf(text, "humidity,%d;", velue1);strcat(buf, text);//printf("buf: %s \r\n", buf);return strlen(buf);
}//==========================================================
//  函数名称:    OneNet_SendData
//
//  函数功能:    上传数据到平台
//
//  入口参数:    type:发送数据的格式
//
//  返回参数:    无
//
//  说明:
//==========================================================
void OneNet_SendData(void)
{MQTT_PACKET_STRUCTURE mqttPacket = {NULL, 0, 0, 0};           //协议包char buf[128];short body_len = 0, i = 0;//   printf("Tips:  OneNet_SendData-MQTT\r\n");memset(buf, 0, sizeof(buf));body_len = OneNet_FillBuf(buf);    //获取当前需要发送的数据流的总长度if(body_len){if(MQTT_PacketSaveData(DEVID, body_len, NULL, 5, &mqttPacket) == 0)                            //封包{for(; i < body_len; i++)mqttPacket._data[mqttPacket._len++] = buf[i];ESP8266_SendData(mqttPacket._data, mqttPacket._len);                                  //上传数据到平台//printf(" buf[%d]:%c \r\n",i, buf[i]);//printf("Send %d Bytes\r\n", mqttPacket._len);MQTT_DeleteBuffer(&mqttPacket);                                                          //删包}elseprintf("WARN: EDP_NewBuffer Failed\r\n");}}//==========================================================
//  函数名称:    OneNet_RevPro
//
//  函数功能:    平台返回数据检测
//
//  入口参数:    dataPtr:平台返回的数据
//
//  返回参数:    无
//
//  说明:
//==========================================================
void OneNet_RevPro(unsigned char *cmd)
{MQTT_PACKET_STRUCTURE mqttPacket = {NULL, 0, 0, 0};                               //协议包char *req_payload = NULL;char *cmdid_topic = NULL;unsigned short req_len = 0;unsigned char type = 0;short result = 0;char *dataPtr = NULL;char numBuf[10];int num = 0;type = MQTT_UnPacketRecv(cmd);switch(type){case MQTT_PKT_CMD:                                                            //命令下发result = MQTT_UnPacketCmd(cmd, &cmdid_topic, &req_payload, &req_len);    //解出topic和消息体if(result == 0){printf("cmdid: %s, req: %s, req_len: %d\r\n", cmdid_topic, req_payload, req_len);if(MQTT_PacketCmdResp(cmdid_topic, req_payload, &mqttPacket) == 0)  //命令回复组包{printf("Tips: Send CmdResp\r\n");ESP8266_SendData(mqttPacket._data, mqttPacket._len);            //回复命令MQTT_DeleteBuffer(&mqttPacket);                                   //删包}}break;case MQTT_PKT_PUBACK:                       //发送Publish消息,平台回复的Ackif(MQTT_UnPacketPublishAck(cmd) == 0)
//              printf("Tips:  MQTT Publish Send OK\r\n");break;default:result = -1;break;}ESP8266_Clear();                                  //清空缓存//    if(result == -1)
//      return;dataPtr = strchr(req_payload, ':');                   //搜索':'if(dataPtr != NULL && result != -1)                  //如果找到了{dataPtr++;while(*dataPtr >= '0' && *dataPtr <= '9')       //判断是否是下发的命令控制数据{numBuf[num++] = *dataPtr++;}numBuf[num] = 0;num = atoi((const char *)numBuf);               //转为数值形式if(strstr((char *)req_payload, "onoff"))      //搜索"onoff"{printf("onoff = %d", num);velue0 = num;}else if(strstr((char *)req_payload, "switch"))      //搜索"switch"{printf("switch = %d", num);velue1 = num;}}if(type == MQTT_PKT_CMD || type == MQTT_PKT_PUBLISH){MQTT_FreeBuffer(cmdid_topic);MQTT_FreeBuffer(req_payload);}}
//定义一个数据交换函数
void Shujujiaohuan(unsigned char wendu,unsigned char shidu)
{velue0=wendu;velue1=shidu;
}

三、APP

2.1.3ONENet云平台软件设计

OneNET[3]是中国移动推出的物联网开放平台,该平台屏蔽了复杂的技术细节,提供多种协议类型,支持多种智能硬件的接入和大数据服务。用户按照OneNET云平台的规范接入平台,上传数据,实现数据传输与存储管理功能,同时平台还支持MQTT、EDP、HTTP等接入协议。用户在官网注册账号后即可进入云平台创建项目。数据上传完成后,用户可以在网页和手机APP端查看数据和对应的变化曲线,也可以下发控制指令,控制智能设备的运行。本系统采用OneNET云平台提供的网页应用控件、命令下发控件等实现了数据接收和远程指令下发等应用。通过网页端和手机APP端的同步应用,可快速方便地构建远程智能监控系统。系统运行时,智能小车在远程指令的控制下,实现前进、后退、转弯。
我们通过云平台产品的多协议接入中的MQTT协议创建一个产品,还需要创建一个设备,之后取出里面的产品ID,设备ID,还有鉴权信息,用于上传数据、查看数据、下发命令。
在keil5中通过RCC_APB2PeriphClockCmd库使能RCC_APB2Periph_GPIOB端口时钟,对ESP8266的使能引脚和复位引脚初始化,之后通过AT指令如:AT+CWMODE=1、AT+CWDHCP=1等等进行模式设置,连接手机热点,开启单连接,连接TCP服务器。
之后通过MQTT协议与云平台创建连接,如果8266成功连接到onenet云平台会打印Tips:连接成功的信息提示语,如果连接失败会打印出连接失败的原因。
连接成功后通过OneNet_SendData和OneNet_RevPro函数来进行发送和接收数据,在接收数据的方法中使用字符串匹配函数来进行在云端下发命令。

2.2APP制作部分

本设计釆用Android Studio作为系统开发软件。Android Studio提供了用于开发和调试的集成Android开发工具,功能比Eclipse更强大。虽然安卓手机或者平板具有很多种尺寸的屏幕与分辨率,但开发人员应用集成Android开发工具都能够比较轻松的调整每个分辨率设备上的应用程序.开发人员能够一边写和调试程序并能够看到这个程序在不同屏幕里的外观。以下图8 为Android Studio开发界面。

图8 Android Studio 开发界面

2.2.1视频监控
本次开发使用声网(Agora)[2]的视频通话和信令的SDK进行二次开发。集成了Agora视频SDK并调用API。
创建项目后我们将Agora视频SDK集成到项目中,添加mavenCentral依赖,之后添加网络和设备权限(INTERNET、CAMERA、RECORD_AUDIO、MODIFY_AUDIO_SETTINGS、ACCESS_WIFI_STATE、ACCESS_NETWORK_STATE、BLUETOOTH)
之后我们创建界面布局,在用户界面中,需要设置两个帧布局(FrameLayout),分别展示本地视图和远端视图。
处理Android系统逻辑,导入必要的Android类,如Manifest、FrameLayout等等。添加必要权限的授权逻辑,启动应用程序时,检查是否已在app中授予了实现视频通话所需的权限。如果未授权,使用内置的Android功能申请权限;如果已授权,则返回true。
实现视频通话逻辑,应用开启时,需要依次创建RtcEngine实例,开启视频模块,让本地用户加入频道,将本地视图与处于较低图层的帧布局(FrameLayout)绑定。当其他用户加入频道时,应用捕捉到远端用户加入频道的事件,并将远端视图与处于较高图层的帧布局(FrameLayout)绑定。首先导入必要的Agora类(io.agora.rtc.RtcEngine;io.agora.rtc.video.VideoCanvas;io.agora.rtc.IRtcEngineEventHandler;)
创建变量用以创建并加入视频通话频道。如AppID、频道名称。通过IRtcEngineEventHandler函数监听频道内的远端用户,获取用户的uid信息。从onUserJoined回调获取uid后,调用setupRemoteVideo,设置远端视频视图。由于视频默认禁用,需要调用enableVideo开始视频流,调用CreateRendererView创建一个SurfaceView对象,并将其作为FrameLayout的子对象,将SurfaceView对象传入Agora,以渲染本地视频。
当远端用户加入频道时,通过setupRemoteVideo函数更新远端用户界面。以下图9为视频监控驱动流程图。

图9视频监控驱动流程图

2.2.2APP控制端

Onenet云平台提供开放的API接口,用户可以通过HTTP/HTTPS调用,进行设备管理,数据查询,设备命令交互等操作,在API的基础上,根据自己的个性化需求搭建上层应用。
Android端控制小车,主要是给OneNet服务器发送一个post请求。通过调用平台API-http://api.heclouds.com/devices/868917927来下发命令,下发的格式为onoff:%d(自己设定),当命令下发成功,平台会作出回应。而单片机那边通过订阅的方式接收到APP下发的指令,之后则会执行相应的程序来驱动小车的前进后退调速等。
APP的按钮通过单击监听事件setOnTouchListener来完成,当按钮按下发送驱动小车命令,当按钮松开执行小车停止命令,按钮颜色的变换,通过调用setImageResource方法进行更换图片来完成。布局界面通过RelativeLayout布局嵌套LinearLayout布局来完成,保证按钮在不同的安卓设备端不会乱跑,也保证了美观。以下图10为OneNet数据收流程图。

图10OneNet数据收流程图

代码二——MainActivity

package com.example.mobile_monitoring;import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;import android.Manifest;
import android.content.pm.PackageManager;
import android.graphics.Color;
import android.os.Bundle;
import android.os.Handler;
import android.text.TextUtils;
import android.util.Log;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.SurfaceView;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewParent;
import android.widget.Button;
import android.widget.FrameLayout;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.TextView;
import android.widget.Toast;import org.json.JSONException;
import org.json.JSONObject;import java.io.IOException;
import java.util.Timer;
import java.util.TimerTask;import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.Headers;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import android.view.MotionEvent;import io.agora.rtc.IRtcEngineEventHandler;
import io.agora.rtc.RtcEngine;
import io.agora.rtc.video.VideoCanvas;import io.agora.rtc.video.VideoEncoderConfiguration;public class MainActivity extends AppCompatActivity {private ImageButton btn_Lock_advance,btn_Lockback,btn_Lockleft,btn_Lockright;private TextView show_DeviceName,show_online,show_DeviceID,show_CreateTime,show_Monitor;private String mip = "183.230.40.39";//服务器地址private String apikey = "111111111111111111111=";//private String device_id = "11111111111111";//设备idprivate int a=0,b=1,port = 6002;//private static final String TAG = MainActivity.class.getSimpleName();// 创建 SurfaceView 对象。private FrameLayout mLocalContainer;private SurfaceView mLocalView;private VideoCanvas mLocalVideo;private VideoCanvas mRemoteVideo;// 创建一个 SurfaceView 对象。private RelativeLayout mRemoteContainer;private SurfaceView mRemoteView;private boolean mCallEnd;private boolean mMuted;private ImageView mCallBtn;private ImageView mMuteBtn;private ImageView mSwitchCameraBtn;// Javaprivate static final int PERMISSION_REQ_ID = 22;// App 运行时确认麦克风和摄像头设备的使用权限。private static final String[] REQUESTED_PERMISSIONS = {Manifest.permission.RECORD_AUDIO,Manifest.permission.CAMERA};@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);if(getSupportActionBar() !=null){ getSupportActionBar().hide(); }//去掉标题栏setContentView(R.layout.activity_main);//setTitle("智能锁V1.0");//标题initUI();// 获取权限后,初始化 RtcEngine,并加入频道。if (checkSelfPermission(REQUESTED_PERMISSIONS[0], PERMISSION_REQ_ID) &&checkSelfPermission(REQUESTED_PERMISSIONS[1], PERMISSION_REQ_ID)) {initEngineAndJoinChannel();}show_online = findViewById(R.id.txtNetwork);//设备联网情况
/*        show_DeviceName = findViewById(R.id.txtDeviceName);//设备名称*//*        show_DeviceID = findViewById(R.id.txtDeviceID);//设备IDshow_CreateTime = findViewById(R.id.txtCreateTime);//设备创建时间*//*show_Monitor = findViewById(R.id.txtMonitor);//监控信息*/btn_Lock_advance = findViewById(R.id.btnLock_advance);//前指令btn_Lockback = findViewById(R.id.btnLock_back);//后btn_Lockleft = findViewById(R.id.btnLock_left);//左btn_Lockright = findViewById(R.id.btnLock_right);//右//ButtonFunction();//按键功能new Handler().postDelayed(task,2000);btn_Lock_advance.setOnTouchListener(new View.OnTouchListener() {@Overridepublic boolean onTouch(View v, MotionEvent event) {if(event.getAction() == MotionEvent.ACTION_DOWN){a=1;Control(a);btn_Lock_advance.setImageResource(R.drawable.ic_btn_forward_on);//btn_Lock_advance.setBackgroundColor(Color.#EAEAEA);}else if(event.getAction() == MotionEvent.ACTION_UP){a=5;Control(a);btn_Lock_advance.setImageResource(R.drawable.ic_btn_forward_off);}return false;}});btn_Lockback.setOnTouchListener(new View.OnTouchListener() {@Overridepublic boolean onTouch(View v, MotionEvent event) {if(event.getAction() == MotionEvent.ACTION_DOWN){a=2;Control(a);btn_Lockback.setImageResource(R.drawable.ic_btn_backward_on);}else if(event.getAction() == MotionEvent.ACTION_UP){a=5;Control(a);btn_Lockback.setImageResource(R.drawable.ic_btn_backward_off);}return false;}});btn_Lockleft.setOnTouchListener(new View.OnTouchListener() {@Overridepublic boolean onTouch(View v, MotionEvent event) {if(event.getAction() == MotionEvent.ACTION_DOWN){a=4;Control(a);btn_Lockleft.setImageResource(R.drawable.ic_btn_left_on);}else if(event.getAction() == MotionEvent.ACTION_UP){a=5;Control(a);btn_Lockleft.setImageResource(R.drawable.ic_btn_left_off);}return false;}});btn_Lockright.setOnTouchListener(new View.OnTouchListener() {@Overridepublic boolean onTouch(View v, MotionEvent event) {if(event.getAction() == MotionEvent.ACTION_DOWN){a=3;Control(a);btn_Lockright.setImageResource(R.drawable.ic_btn_right_on);}else if(event.getAction() == MotionEvent.ACTION_UP){a=5;Control(a);btn_Lockright.setImageResource(R.drawable.ic_btn_right_off);}return false;}});}private Handler handler = new Handler();private Runnable task = new Runnable() {@Overridepublic void run() {handler.postDelayed(this,3000);new Thread(new Runnable() {@Overridepublic void run() {try{OkHttpClient client = new OkHttpClient();String url1 = String.format("http://api.heclouds.com/devices/%s",device_id);Request request = new Request.Builder().url(url1).addHeader("api-key", apikey).build();Response response = client.newCall(request).execute();String responseData = response.body().string();Log.w("test", responseData);//json提取数据JSONObject jsonObject = new JSONObject(responseData);JSONObject jsonObjectData = jsonObject.getJSONObject("data");//Log.e("e", String.valueOf(jsonObjectData));final String device_title = jsonObjectData.getString("title");//提取设备名称final String device_id = jsonObjectData.getString("id");//提取设备idfinal String create_time = jsonObjectData.getString("create_time");//提取设备创建时间final String device_online = jsonObjectData.getString("online");//提取设备是否在线//设备监控信息OkHttpClient client2 = new OkHttpClient();String url2 = String.format("http://api.heclouds.com/devices/%s/datastreams/test2",device_id);Request request2 = new Request.Builder().url(url2).addHeader("api-key", apikey).build();Response response2 = client2.newCall(request2).execute();String responseData2 = response2.body().string();//json提取数据JSONObject jsonObject2 = new JSONObject(responseData2);JSONObject jsonObjectData2 = jsonObject2.getJSONObject("data");final String current_value = jsonObjectData2.getString("current_value");//提取最新数据final String update_at = jsonObjectData2.getString("update_at");//提取最新数据的时间handler.post(new Runnable() {@Overridepublic void run() {//show_DeviceName.setText(device_title);// show_DeviceID.setText("设备ID:"+device_id);// show_CreateTime.setText("创建时间:"+create_time);if(device_online.equals("true")) {show_online.setText("在 线");show_online.setTextColor(Color.GREEN);}if(device_online.equals("false")){show_online.setText("离 线");show_online.setTextColor(Color.RED);}}});} catch (Exception e) {e.printStackTrace();handler.post(new Runnable() {@Overridepublic void run() {Toast.makeText(MainActivity.this, "请检查手机是否连接网络", Toast.LENGTH_SHORT).show(); //显示提示}});}}}).start();}};//获取数据public void GetData(){new Thread(new Runnable() {@Overridepublic void run() {try{OkHttpClient client = new OkHttpClient();String url = String.format("http://api.heclouds.com/devices/%s/datastreams/test1",device_id);Request request = new Request.Builder().url(url).addHeader("api-key", apikey).build();Response response = client.newCall(request).execute();String responseData = response.body().string();Log.w("test", responseData);//json提取数据JSONObject jsonObject = new JSONObject(responseData);JSONObject jsonObjectData = jsonObject.getJSONObject("data");Log.e("e", String.valueOf(jsonObjectData));final String current_value = jsonObjectData.getString("current_value");//提取最新数据final String update_at = jsonObjectData.getString("update_at");//提取最新数据的时间}catch (IOException | JSONException e) {e.printStackTrace();}}}).start();}//下发命令public void Control(final int val) {new Thread(new Runnable() {@Overridepublic void run() {try{OkHttpClient client=new OkHttpClient();String url = String.format("http://api.heclouds.com/cmds?device_id=%s",device_id);String body = String.format("onoff:%d", val);RequestBody body1=RequestBody.create(MediaType.parse("application/json; charset=utf-8"), body);Request request = new Request.Builder().url(url).headers(new Headers.Builder().add("api-key", apikey).build())//表头.post(body1).build();Call call=client.newCall(request);call.enqueue(new Callback() {@Overridepublic void onFailure(Call call, IOException e) {//请求失败Log.e("e", "post请求失败");}@Overridepublic void onResponse(Call call, Response response) throws IOException {//请求成功}});//平台回应Response response = client.newCall(request).execute();String jsonStr = response.body().string();Log.e(" onenet回应数据",jsonStr);JSONObject jsonObject = new JSONObject(jsonStr);String jsonObjectRes = jsonObject.getString("errno");final String jsonObjectError = jsonObject.getString("error");Log.e("a", jsonObjectRes);if (jsonObjectRes == "10"){handler.post(new Runnable() {@Overridepublic void run() {AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);builder.setTitle("请求错误");builder.setMessage("设备不在线");//builder.setIcon(R.mipmap.ic_launcher);//图标显示builder.setCancelable(true);builder.show();
//                                AlertDialog dialog=builder.create();
//                                dialog.show();}});}else if (jsonObjectRes == "0"){handler.post(new Runnable() {@Overridepublic void run() {Toast.makeText(MainActivity.this, "远程控制成功", Toast.LENGTH_SHORT).show(); //显示提示}});}else {handler.post(new Runnable() {@Overridepublic void run() {AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);builder.setTitle("请求错误");builder.setMessage(jsonObjectError);builder.setCancelable(true);// builder.show();}});}} catch (Exception e) {// toastStr = "连接失败,请检测手机或设备的网络状态";e.printStackTrace();}}}).start();}
/*    @Overrideprotected void onDestroy(){super.onDestroy();handler.removeCallbacks(task);}*/@Overridepublic boolean onKeyDown(int keyCode, KeyEvent event){if(keyCode == KeyEvent.KEYCODE_BACK){exitBy2Click();}return false;}private static Boolean isExit = false;private void exitBy2Click() {Timer tExit = null;if(!isExit){isExit = true;Toast.makeText(this,"再按一次退出程序",Toast.LENGTH_SHORT).show();tExit = new Timer();tExit.schedule(new TimerTask() {@Overridepublic void run() {isExit = false;}},2000);}else {android.os.Process.killProcess(android.os.Process.myPid());System.exit(0);}}//shengwangprivate void initUI() {mLocalContainer = findViewById(R.id.local_video_view_container);mRemoteContainer = findViewById(R.id.remote_video_view_container);mCallBtn = findViewById(R.id.btn_call);mMuteBtn = findViewById(R.id.btn_mute);mSwitchCameraBtn = findViewById(R.id.btn_switch_camera);// Sample logs are optional.}private void initEngineAndJoinChannel() {initializeEngine();setupLocalVideo();joinChannel();}private boolean checkSelfPermission(String permission, int requestCode) {if (ContextCompat.checkSelfPermission(this, permission) !=PackageManager.PERMISSION_GRANTED) {ActivityCompat.requestPermissions(this, REQUESTED_PERMISSIONS, requestCode);return false;}return true;}// Javaprivate RtcEngine mRtcEngine;private final IRtcEngineEventHandler mRtcEventHandler = new IRtcEngineEventHandler() {@Override// 注册 onJoinChannelSuccess 回调。// 本地用户成功加入频道时,会触发该回调。public void onJoinChannelSuccess(String channel, final int uid, int elapsed) {runOnUiThread(new Runnable() {@Overridepublic void run() {Log.i("agora","Join channel success, uid: " + (uid & 0xFFFFFFFFL));}});}@Override// 注册 onUserJoined 回调。// 远端用户成功加入频道时,会触发该回调。// 可以在该回调中调用 setupRemoteVideo 方法设置远端视图。public void onUserJoined(final int uid, int elapsed) {runOnUiThread(new Runnable() {@Overridepublic void run() {Log.i("agora","Remote user joined, uid: " + (uid & 0xFFFFFFFFL));setupRemoteVideo(uid);}});}private void onRemoteUserLeft(int uid) {if (mRemoteVideo != null && mRemoteVideo.uid == uid) {removeFromParent(mRemoteVideo);// Destroys remote viewmRemoteVideo = null;}}@Override// 注册 onUserOffline 回调。// 远端用户离开频道或掉线时,会触发该回调。public void onUserOffline(final int uid, int reason) {runOnUiThread(new Runnable() {@Overridepublic void run() {Log.i("agora","User offline, uid: " + (uid & 0xFFFFFFFFL));onRemoteUserLeft(uid);}});}};// 初始化 RtcEngine 对象。private void initializeEngine() {try {mRtcEngine = RtcEngine.create(getBaseContext(), getString(R.string.agora_app_id), mRtcEventHandler);} catch (Exception e) {Log.e(TAG, Log.getStackTraceString(e));throw new RuntimeException("NEED TO check rtc sdk init fatal error\n" + Log.getStackTraceString(e));}}// Javaprivate void setupLocalVideo() {// 启用视频模块。mRtcEngine.enableVideo();mLocalView = RtcEngine.CreateRendererView(getBaseContext());mLocalView.setZOrderMediaOverlay(true);mLocalContainer.addView(mLocalView);// 设置本地视图。VideoCanvas localVideoCanvas = new VideoCanvas(mLocalView, VideoCanvas.RENDER_MODE_HIDDEN, 0);mRtcEngine.setupLocalVideo(localVideoCanvas);}// Javaprivate void joinChannel() {String token = getString(R.string.agora_access_token);if (TextUtils.isEmpty(token) || TextUtils.equals(token, "#YOUR ACCESS TOKEN#")) {token = null; // default, no token}// 调用 joinChannel 方法 加入频道。mRtcEngine.joinChannel(token, "demoChannel1", "Extra Optional Data", 0);}// Javaprivate void setupRemoteVideo(int uid) {mRemoteView = RtcEngine.CreateRendererView(getBaseContext());mRemoteContainer.addView(mRemoteView);// 设置远端视图。mRtcEngine.setupRemoteVideo(new VideoCanvas(mRemoteView, VideoCanvas.RENDER_MODE_HIDDEN, uid));}// Java停止发送音频流public void onLocalAudioMuteClicked(View view) {mMuted = !mMuted;mRtcEngine.muteLocalAudioStream(mMuted);mRtcEngine.muteLocalAudioStream(mMuted);int res = mMuted ? R.drawable.btn_mute : R.drawable.btn_unmute;mMuteBtn.setImageResource(res);}// Javapublic void onSwitchCameraClicked(View view) {mRtcEngine.switchCamera();}public void onCallClicked(View view) {if (mCallEnd) {startCall();mCallEnd = false;mCallBtn.setImageResource(R.drawable.btn_endcall);} else {endCall();mCallEnd = true;mCallBtn.setImageResource(R.drawable.btn_startcall);}showButtons(!mCallEnd);}private void startCall() {setupLocalVideo();joinChannel();}private void endCall() {removeFromParent(mLocalVideo);mLocalVideo = null;removeFromParent(mRemoteVideo);mRemoteVideo = null;leaveChannel();}private void showButtons(boolean show) {int visibility = show ? View.VISIBLE : View.GONE;mMuteBtn.setVisibility(visibility);mSwitchCameraBtn.setVisibility(visibility);}private ViewGroup removeFromParent(VideoCanvas canvas) {if (canvas != null) {ViewParent parent = canvas.view.getParent();if (parent != null) {ViewGroup group = (ViewGroup) parent;group.removeView(canvas.view);return group;}}return null;}// Java@Overrideprotected void onDestroy() {super.onDestroy();if (!mCallEnd) {leaveChannel();}RtcEngine.destroy();handler.removeCallbacks(task);}private void leaveChannel() {// 离开当前频道。mRtcEngine.leaveChannel();}}

git代码
https://github.com/lianghuajunone/Mobile_monitoring

设计实物图


PP界面截图

总结

本项目设计了一个以STM32为核心的智能视频小车,通过Android Studio开发实现手机端监控且控制设备移动。通过测试,基本实现了用手机通过WIFI控制小车前进、后退、左转、右转等转向运动,可以实时视频监控,整体效果达到预期,小车成本低,稳定性好,在人们的生产、生活中具有非常好的应用前景。虽然设计出的移动监控系统达到了预期的设计要求,但是系统本身还是有一些缺陷。随着自动化和智能化的普及,工业生产对于智能小车的要求也越来越高。本文的视频监控系统只是智能化系统的一个分支,设计的系统硬件比较简单并且只能实现一些简单的功能,但为以后更加智能化地设计打下了一个基础。

基于STM32的移动视频监控系统相关推荐

  1. linux 车载视频监控,基于Linux平台车载视频监控系统研发-计算机科学与技术专业论文.docx...

    基于Linux平台车载视频监控系统研发-计算机科学与技术专业论文 目录 HYPERLINK \l "_bookmark0" 第一章 绪论1 HYPERLINK \l "_ ...

  2. 基于ARM的移动视频监控系统

    http://www.eeworld.com.cn/qrs/2010/0409/article_2439_1.html 0 引 言 传统的视频监控系统一般采用PC服务器的C/S(Client/Serv ...

  3. 介绍基于ARM的移动视频监控系统

    摘要:将嵌入式Linux和无线网络引入到视频监控系统,阐述了系统的硬件组成:介绍了USB无线网卡驱动实现的过程:从嵌入式Linux开发环境的搭建.嵌入式流媒体服务器的设计和动态网页的设计等方面介绍了软 ...

  4. 基于ARM的远程视频监控系统的设计

    http://www.21ic.com/app/mcu/201208/135975.htm 摘要:在ARM 微处理器平台上移植嵌入式Linux 操作系统,完成视频采集任务,并以服务器方式将图像发送到网 ...

  5. b s架构监控java,基于B/S的视频监控系统的设计与实现

    基于B/S的视频监控系统的设计与实现 本文分析了基于C/S架构的视频监控系统的缺点和B/S结构的诸多优点,通过需求分析,设计实现了一种以B/S为架构的视频监控系统,并针对现存视频监控系统在权限控制方面 ...

  6. 无线视频监控系统 PHP,基于ARM的无线视频监控系统的解决方案

    随着通信技术.计算机技术.数字视频技术.网络技术等高科技的发展,视频监控领域也快速进步.近年嵌入式计算机技术和网络技术的开发推动了视频监控的再次进步,出现了基于嵌入式技术的无线网络视频监控系统.无线网 ...

  7. 基于ARM11的无线视频监控系统

    摘 要:设计了一种基于ARM11+Linux 系统组成的无线视频监控系统.为提高运算速度,系统采用ARM11 微处理器S3C6410 作为主处理器,采用OV9650 摄像头作为图像采集设备,用硬编码方 ...

  8. 远程视频监控php,基于 CentOS 搭建远程视频监控系统

    妹子说想看一下没人在家的时候小狗在干嘛,于是我就开始寻找开源的远程视频监控系统.经常一翻查找.对比,最后选定了 Zoneminder. A full-featured, open source, st ...

  9. 基于云端的智能视频监控系统的设计与实现

    目 录 引言 1 总体设计 2 2.1 系统设计需求 2 2.2 系统设计思路 2 2.3 系统设计方案 3 云监控系统硬件设计 5 3.1 系统控制模块 5 3.2 无线接收模块 5 3.3 内存存 ...

最新文章

  1. 迭代和瀑布的最大的差别就在于风险的暴露时间上
  2. module 'cv2' has no attribute 'CV_LOAD_IMAGE_GRAYSCALE'
  3. (C#)设计模式之装饰模式
  4. apache2.2配置php,PHP5+APACHE2.2配置_PHP教程
  5. 20款响应式的 HTML5 网页模板【免费下载】
  6. xposed框架在分机安装失败_免root用Xposed框架!安卓用户一定要学会
  7. Unity发布WebGl注意事项
  8. oracle set markup,oracle sql*plus set spool介绍(二)
  9. oracle复制数据库文件不动,复制数据库中需要注意的几点事项
  10. java秒杀时间与服务器时间_Javascript实现秒杀倒计时(时间与服务器时间同步)...
  11. Bailian4016 班级排名【稳定排序】
  12. 【NOIP2007】【Luogu1093】奖学金
  13. 互联网+商业 济宁苏宁生活广场打造智慧城市范本
  14. python代码怎么弄颜色_python的颜色显示
  15. 证据理论(1)—— DS证据理论基本理论
  16. cmd命令快速重启IIS服务
  17. MATLAB五子棋游戏(双人对战,可悔棋)
  18. 解决0x00000FD:Stack overflow(参数:0x00000000,0x002F2000)栈溢出问题
  19. java画图板可选颜色,java学习——画图板
  20. 慧荣SM2259XT主控贴镁光B27A测试分享

热门文章

  1. 伯克利双专业 经济学和计算机专业,美国加州伯克利大学世界排名第几2021
  2. Centos开机后ens33网卡失效连不上网
  3. 数据可视化分析教学课件——FineBI实验册节选====企业产品销售分析
  4. 慕课-初识 学习ts笔记
  5. 浏览器是指在用户计算机,2016年计算机二级office模拟试卷及答案
  6. Three.js实现剖切
  7. 相机与图像--小孔成像模型与坐标系--坐标系转换
  8. vc6 调试 附加到进程 列表空_今天,进程告诉我线程它它它它不想活了
  9. 相机与IMU标定教程
  10. 查询学生各科前三名的学生成绩