1. 程式人生 > 程式設計 >微信小程式實現樹莓派(raspberry pi)小車控制

微信小程式實現樹莓派(raspberry pi)小車控制

本文是基於上一篇“網頁版樹莓派小車控制程式”改造而成。主要也練習了一下微信小程式的開發。這裡簡單記錄一下主要程式碼片段。也是趟過了許多的坑,例如:微信小程式不支援完全全屏,微信小程式不能橫屏展示。所以開發過程中也用了一些非常手段。可以說這只是一個很基本的demo,所以裡面很多東西,比如攝像頭監控ip、頁面元素定位我都使用了寫死的值。特別是介面,我只是在iPhone 6上面做的實驗,所以換到其他手機上時,介面就會變型了。

1. 基本思路

  • 進入小程式時展示index頁,可以讓使用者輸入服務端url(模擬上一篇中在瀏覽器獲取get請求)
  • 然後跳轉到實際的小車控制介面,並可以通過點選按鈕實現小車控制
  • 控制小車的移動,主要是在control.js中定義了介面按鈕事件的響應,在響應事件的過程中實現http請求的傳送

index頁面如下:

微信小程式實現樹莓派(raspberry pi)小車控制

進去之後的頁面如下(其中中間空白處會展示攝像頭監控,不過我並沒有啟動,所以看不見):

微信小程式實現樹莓派(raspberry pi)小車控制

2. 程式碼結構如下:

其中,index下面是首頁,control是控制頁面,res目錄下存放的是圖片資源

微信小程式實現樹莓派(raspberry pi)小車控制

3. index目錄

index.js

//index.js
//獲取應用例項
const app = getApp()
 
Page({
 data: {
 logo: "/res/rasp-logo.png",welcome: "歡迎使用樹莓小車",enterBtn: "進入",PromoteMsg: "Please enter the server address (eg: http://x.x.x.x:8080)",reqURL: ""
 },// 從輸入框中獲取使用者輸入的伺服器地址資訊
 getURL: function (e) {
 this.setData({
 reqURL: e.detail.value
 })
 },enterClicked: function (e) {
 /*
 * 當按下進入按鈕,需要做以下事情:
 * 1. 首先判斷使用者是否已經在輸入框中輸入完整的伺服器地址
 * 2. 發起一個到伺服器的GET請求,並分析伺服器的響應結果
 * 3. 跳轉到小車控制介面
 */
 console.log(this.data.reqURL)
 
 if (this.data.reqURL == '') {
 wx.showModal({
 title: '提示',content: '請先輸入正確的伺服器地址!',})
 return
 }
 
 // 發起到伺服器的GET請求
 wx.request({
 url: this.data.reqURL,success: function (res) {
 // 在這裡獲取POST請求地址,以及視訊流地址,然後賦值給全域性變數,供control頁面呼叫
 console.log(res.data.match(/url = \"(\S*)\"/)[1])
 console.log(res.data.match(/src=\"(\S*)\"/)[1])
 app.globalData.postURL = res.data.match(/url = \"(\S*)\"/)[1]
 app.globalData.cameraURL = res.data.match(/src=\"(\S*)\"/)[1]
 
 // 跳轉到control頁面
 wx.navigateTo({
  url: '/pages/control/control',})
 },fail: function(res) {
 wx.showModal({
  title: '提示',content: '請檢查輸入的伺服器地址!',})
 }
 })
 }
})

index.json:無資料,只有一對打括號

index.wxml

<!--index.wxml-->
<view>
 <view class="welcome">
 <view class="logo">
 <image style="width: 250rpx; height: 250rpx" src="{{logo}}"></image>
 </view>
 <view>
 <text class="words">{{welcome}}</text>
 </view>
 </view>
 
 <input class="requestURL" type="text" placeholder="{{PromoteMsg}}" focus='1' cursor='10' confirm-type="done" bindinput='getURL'></input>
 <button class='enter' bindtap='enterClicked'>{{enterBtn}}</button>
</view>

index.wxss

/**index.wxss**/
.welcome{
 display: flex;
 margin-top: 50rpx;
 flex-direction: column;
 align-items: center;
 justify-content: space-between;
}
 
.requestURL{
 margin: 50rpx 10rpx 30rpx 10rpx;
 border: 1px solid gray;
 font-style: italic;
 font-size: small
}
 
.enter{
 margin-right: 10rpx;
 width: 150rpx;
 height: 60rpx;
 font-size: small
}

4. control目錄

control.js

// pages/control/control.js
const app = getApp()
 
Page({
 
 /**
 * 頁面的初始資料
 */
 data: {
 // Car control images
 "forwardBtn": "/res/forward.png","leftBtn": "/res/left.png","rightBtn": "/res/right.png","backLeftBtn": "/res/back-left.png","backRightBtn": "/res/back-right.png","backBtn": "/res/backward.png",// Camera control images
 "upBtn": "/res/forward.png","camLeftBtn": "/res/camLeft.png","camRightBtn": "/res/camRight.png","downBtn": "/res/backward.png","resetBtn": "/res/reset.png"
 },carMove: function(event) {
 wx.request({
 url: this.data.postURL,data: event.currentTarget.dataset.direction,method: "POST",success: function(res){
 
 },fail: function(res){
 
 }
 })
 },carStop: function(event) {
 wx.request({
 url: this.data.postURL,data: "S",success: function (res) {
 
 },fail: function (res) {
 
 }
 })
 },camMove: function(event) {
 wx.request({
 url: this.data.postURL,/**
 * 生命週期函式--監聽頁面載入
 */
 onLoad: function (options) {
 //this.data.cameraURL = app.globalData.cameraURL
 this.setData({
 cameraURL: app.globalData.cameraURL,postURL: app.globalData.postURL
 })
 console.log(this.data.cameraURL)
 console.log("post url in control page: " + app.globalData.postURL)
 },/**
 * 生命週期函式--監聽頁面初次渲染完成
 */
 onReady: function () {
 
 },/**
 * 生命週期函式--監聽頁面顯示
 */
 onShow: function () {
 //console.log(wx.getSystemInfoSync().windowWidth)
 //console.log(wx.getSystemInfoSync().windowHeight)
 },/**
 * 生命週期函式--監聽頁面隱藏
 */
 onHide: function () {
 
 },/**
 * 生命週期函式--監聽頁面解除安裝
 */
 onUnload: function () {
 
 },/**
 * 頁面相關事件處理函式--監聽使用者下拉動作
 */
 onPullDownRefresh: function () {
 
 },/**
 * 頁面上拉觸底事件的處理函式
 */
 onReachBottom: function () {
 
 },/**
 * 使用者點選右上角分享
 */
 onShareAppMessage: function () {
 
 }
})

control.json

{
 "navigationBarBackgroundColor": "#ffffff","navigationBarTextStyle": "black","navigationBarTitleText": "樹莓小車","backgroundColor": "#eeeeee","backgroundTextStyle": "light","enablePullDownRefresh": false,"navigationStyle": "custom","disableScroll": true
}

control.wxml

<!--pages/control/control.wxml-->
<view class='control'>
 <!-- This image shows the camera view -->
 <image class='cameraView' src='http://192.168.1.104:8080/?action=stream' style="z-index:1"></image>
 
 <!-- The following six images control the car move -->
 <image class='button' id='forward' src='{{forwardBtn}}' style="position:absolute;z-index:2" bindtouchstart='carMove' data-direction='F' bindtouchend='carStop'></image>
 <image class='button' id='left' src='{{leftBtn}}' style="position:absolute;z-index:2" bindtouchstart='carMove' data-direction='L' bindtouchend='carStop'></image>
 <image class='button' id='right' src='{{rightBtn}}' style="position:absolute;z-index:2" bindtouchstart='carMove' data-direction='R' bindtouchend='carStop'></image>
 <image class='button' id='backLeft' src='{{backLeftBtn}}' style="position:absolute;z-index:2" bindtouchstart='carMove' data-direction='BL' bindtouchend='carStop'></image>
 <image class='button' id='backRight' src='{{backRightBtn}}' style="position:absolute;z-index:2" bindtouchstart='carMove' data-direction='BR' bindtouchend='carStop'></image>
 <image class='button' id='back' src='{{backBtn}}' style="position:absolute;z-index:2" bindtouchstart='carMove' data-direction='B' bindtouchend='carStop'></image>
 
 <!-- The following images control the camera move -->
 <image class='button' id='up' src='{{upBtn}}' style="position:absolute;z-index:2" bindtouchstart='camMove' data-direction='VU'></image>
 <image class='button' id='camLeft' src='{{camLeftBtn}}' style="position:absolute;z-index:2" bindtouchstart='camMove' data-direction='HL'></image>
 <image class='button' id='camRight' src='{{camRightBtn}}' style="position:absolute;z-index:2" bindtouchstart='camMove' data-direction='HR'></image>
 <image class='button' id='down' src='{{downBtn}}' style="position:absolute;z-index:2" bindtouchstart='camMove' data-direction='VD'></image>
 <image class='button' id='reset' src='{{resetBtn}}' style="position:absolute;z-index:2" bindtouchstart='camMove' data-direction='RESET'></image>
</view>

control.wxss

/* pages/control/control.wxss */
 
.control {
 width: 100%;
 height: 100%;
 transform: rotate(90deg);
 background-color: #eee;
 justify-content: center;
}
 
.cameraView {
 margin-left: 0px;
 width: 603px;
 height: 375px;
 background-color: #eee;
 justify-content: center;
}
 
.button {
 height: 60px;
 width: 60px;
 opacity: 0.3;
}
 
#forward {
 left: 60px;
 top: 135px;
}
 
#left {
 left: 0px;
 top: 195px;
}
 
#right {
 left: 120px;
 top: 195px;
}
 
#backLeft {
 left: 0px;
 top: 255px;
}
 
#backRight {
 left: 120px;
 top: 255px;
}
 
#back {
 left: 60px;
 top: 315px;
}
 
#up {
 left: 480px;
 top: 195px;
}
 
#camLeft {
 left: 420px;
 top: 255px;
}
 
#camRight {
 left: 540px;
 top: 255px;
}
 
#down {
 left: 480px;
 top: 315px;
}
 
#reset{
 left: 480px;
 top: 135px
}

5. 工程全域性控制

app.js:實際似乎並沒有用到,裡面都是工程建立時的預設程式碼

//app.js
App({
 onLaunch: function () {
 // 展示本地儲存能力
 var logs = wx.getStorageSync('logs') || []
 logs.unshift(Date.now())
 wx.setStorageSync('logs',logs)
 
 // 登入
 wx.login({
 success: res => {
 // 傳送 res.code 到後臺換取 openId,sessionKey,unionId
 }
 })
 // 獲取使用者資訊
 wx.getSetting({
 success: res => {
 if (res.authSetting['scope.userInfo']) {
  // 已經授權,可以直接呼叫 getUserInfo 獲取頭像暱稱,不會彈框
  wx.getUserInfo({
  success: res => {
  // 可以將 res 傳送給後臺解碼出 unionId
  this.globalData.userInfo = res.userInfo
 
  // 由於 getUserInfo 是網路請求,可能會在 Page.onLoad 之後才返回
  // 所以此處加入 callback 以防止這種情況
  if (this.userInfoReadyCallback) {
  this.userInfoReadyCallback(res)
  }
  }
  })
 }
 }
 })
 },globalData: {
 userInfo: null,postURL: null,cameraURL: null
 }
})

app.json:

{
 "pages": [
 "pages/index/index","pages/control/control"
 ],"window": {
 "backgroundTextStyle": "light","navigationBarBackgroundColor": "#fff","showStatusBar": false
 }
}

app.wxss:

/**app.wxss**/
.container {
 height: 100%;
 display: flex;
 flex-direction: column;
 align-items: center;
 justify-content: space-between;
 padding: 200rpx 0;
 box-sizing: border-box;
} 
project.control.json:
{
 "description": "專案配置檔案。","packOptions": {
 "ignore": []
 },"setting": {
 "urlCheck": false,"es6": true,"postcss": true,"minified": true,"newFeature": true
 },"compileType": "miniprogram","libVersion": "2.0.4","appid": "wx18414b9f85bfc895","projectname": "wechat-control","isGameTourist": false,"condition": {
 "search": {
 "current": -1,"list": []
 },"conversation": {
 "current": -1,"game": {
 "currentL": -1,"miniprogram": {
 "current": -1,"list": []
 }
 }
}

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支援我們。