Browse Source

v0 python版本
Signed-off-by: caner <5658514@qq.com>

caner 3 years ago
parent
commit
2672fd15f6
13 changed files with 309 additions and 433 deletions
  1. 0 31
      .gitignore
  2. 125 0
      Contrl/index.js
  3. 0 8
      LICENSE
  4. 34 25
      README.md
  5. 0 103
      index.js
  6. 0 69
      install.sh
  7. 0 147
      lib/Pwm.js
  8. BIN
      lib/node
  9. 0 44
      lib/npm
  10. 44 0
      main.js
  11. 100 0
      package-lock.json
  12. 4 6
      package.json
  13. 2 0
      video.sh

+ 0 - 31
.gitignore

@@ -1,31 +0,0 @@
-# ---> Node
-# Logs
-logs
-*.log
-npm-debug.log*
-
-# Runtime data
-pids
-*.pid
-*.seed
-
-# Directory for instrumented libs generated by jscoverage/JSCover
-lib-cov
-
-# Coverage directory used by tools like istanbul
-coverage
-
-# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
-.grunt
-
-# node-waf configuration
-.lock-wscript
-
-# Compiled binary addons (http://nodejs.org/api/addons.html)
-build/Release
-
-# Dependency directory
-# https://docs.npmjs.com/misc/faq#should-i-check-my-node-modules-folder-into-git
-node_modules
-*.zip
-*.7z

+ 125 - 0
Contrl/index.js

@@ -0,0 +1,125 @@
+const i2cBus = require("i2c-bus")
+const { Pca9685Driver } = require("pca9685")
+const RPIO = require("rpio");
+
+class ContrlService {
+    constructor() {
+        // PWM 和 舵机配置
+        this.pwmOption = {
+            i2c: i2cBus.openSync(1), // 树莓派1:scl1
+            address: 0x40, //板子地址
+            frequency: 50, //频率
+            debug: false
+        }
+        //PCA 板子位置电调+舵机
+        this.MoAndSero = {
+            m1: 3,
+            m2: 2,
+            s1: 0,
+            s2: 1
+        }
+        // prio init
+        RPIO.init({ mapping: "gpio" });
+        // 继电器解锁
+        RPIO.open(22, RPIO.OUTPUT, RPIO.LOW);
+        RPIO.open(23, RPIO.OUTPUT, RPIO.LOW);
+        // 开灯
+        RPIO.open(22, RPIO.OUTPUT, RPIO.HIGH);
+        // init PWM
+        this.PWM = new Pca9685Driver(this.pwmOption, er => {
+            if (er) {
+                console.error("Error initializing PCA9685");
+            }
+        })
+        // 解锁计数器
+        this.Snum = 0
+        // 解锁状态
+        this.enable = false
+    }
+    // 设置pwm
+    async changPWM(params) {
+        const { v0, v1, v2, v3 } = params
+        if (typeof (v0) == 'number' || typeof (v3) == 'number') {
+            if (this.enable) {
+                // 解锁之后需要2秒给电调中立值
+                if (this.Snum >= 50 && this.Snum <= 61) this.Snum++
+                if (this.Snum >= 60) {
+                    if (Math.abs(+v2 - 128) < 20) {
+                        console.log('前后', v3)
+                        this.PWM.setPulseLength(this.MoAndSero.m1, this.Motor2pwm(Math.abs(+v3 - 256)));
+                        this.PWM.setPulseLength(this.MoAndSero.m2, this.Motor2pwm(Math.abs(+v3 - 256)));
+                    } else {
+                        // 分左右
+                        if ((+v2 - 128) > 20) {
+                            // 右
+                            console.log('右', +v2);
+                            const a = 128 - (+v2 - 128)
+                            const b = 128 + (+v2 - 128)
+                            this.PWM.setPulseLength(this.MoAndSero.m1, this.Motor2pwm(+a));
+                            this.PWM.setPulseLength(this.MoAndSero.m2, this.Motor2pwm(+b));
+                        } else if (+v2 - 128 < -20) {
+                            // 左
+                            console.log('左', +v2);
+                            const a = 128 - (+v2 - 128)
+                            const b = 128 + (+v2 - 128)
+                            this.PWM.setPulseLength(this.MoAndSero.m1, this.Motor2pwm(+a));
+                            this.PWM.setPulseLength(this.MoAndSero.m2, this.Motor2pwm(+b));
+                        }
+                    }
+
+                    //云台
+                    if (v0 || v1) {
+                        // console.log('云台', v1, v0)
+                        const a = +v0 < 60 ? 60 : +v0
+                        this.PWM.setPulseLength(this.MoAndSero.s1, this.Servo2pwm(+v1));
+                        this.PWM.setPulseLength(this.MoAndSero.s2, this.Servo2pwm(+a));
+                    }
+                }
+            } else {
+                this.unLOCK(v0, v1, v2, v3)
+            }
+        } else {
+            console.log('参数格式错误,自动略过');
+            return
+        }
+    }
+
+    /**
+     * 内八解锁
+     * @param {*} v0 
+     * @param {*} v1 
+     * @param {*} v2 
+     * @param {*} v3 
+     */
+    unLOCK(v0, v1, v2, v3) {
+        // 未解锁=>进行解锁:发送端的频率是0.04S,0.05*60 = 3S        
+        // 内八 :v0<50,v1>200,v2>200,v3<50
+        if (+v0 <= 60 && +v1 >= 190 && +v3 >= 190 && +v2 <= 60) {
+            if (this.Snum >= 0 && this.Snum <= 51) this.Snum++
+        } else {
+            this.Snum = 0
+        }
+        if (this.Snum == 50) {
+            RPIO.open(23, RPIO.OUTPUT, RPIO.HIGH);
+            this.enable = true
+        }
+        console.log('解锁中', v0, v1, v2, v3)
+    }
+    /**
+     * 电调换算比例:摇杆范围0-256,PWM范围500~1500~2500
+     * @param {number} v 
+     * @returns 
+     */
+    Motor2pwm(v) {
+        return parseInt(v / (256 / 2000)) + 500
+    }
+    /**
+     * 舵机换算比例:摇杆范围0-256,PWM范围1000~1500~2000
+     * @param {number} v 
+     * @returns 
+     */
+    Servo2pwm(v) {
+        return parseInt((Math.abs(v - 256)) / (256 / 1000)) + 1000
+    }
+}
+module.exports = new ContrlService()

+ 0 - 8
LICENSE

@@ -1,8 +0,0 @@
-MIT License
-Copyright (c) <year> <copyright holders>
-
-Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

+ 34 - 25
README.md

@@ -1,27 +1,36 @@
-# 车端
-```
-系统采用树莓派bullseye arm64 版本
-```
+# ------------------系统基于Raspi-linux armv7l-----------------
+# Raspi
+apt install ffmpeg
+down https://nodejs.org/dist/v12.22.5/node-v12.22.5-linux-armv7l.tar.gz
+ln -s /node/bin/node /us/local/node
+ln -s /node/bin/npm /us/local/npm
 
-## 一键安装
-```
-sudo sh install.sh
-```
+# 启动主程序.sh
+#!/usr/bin/sh
+node main.js
 
-## 源码安装
-```
-1. sudo apt-get install libx264-dev libjpeg-dev libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev libgstreamer-plugins-bad1.0-dev gstreamer1.0-plugins-ugly gstreamer1.0-tools gstreamer1.0-gl gstreamer1.0-gtk3 gstreamer1.0-pulseaudio -y
-2. sudo ./lib/npm install
-3. sudo ./lib/node index.js
-```
-## 注意
-```
-1. 电调需自行找中位可参考:[sensor] (https://git.caner.top/Caner/sensor)
-2. 注意摇杆间的中位误差
-3. yuyv 格式查询 gstream 根据最低分辨率填写
-    * sudo apt install v4l-utils
-    * v4l2-ctl --list-devices // 查看所有设备
-    * v4l2-ctl -d /dev/video0 --list-formats-ext --all // 查看图像格式
-    * sudo v4l2-ctl -d /dev/video0 --list-formats //查看当前摄像头支持的视频压缩格式
-    * sudo v4l2-ctl --list-framesizes=MJPG -d /dev/video0 //查看摄像头所支持的分辨率
-```
+<!-- 其它视频服务 -->
+# MJPG-Streamer 视频服务
+sudo apt install cmake libjpeg8-dev
+git clone https://e.coding.net/fivecc/mjpg-streamer/mjpg-streamer.git
+make && make install
+
+# 启动MJPG-Streamer.sh
+#!/bin/sh
+/usr/local/bin/mjpg_streamer -i "/usr/local/lib/mjpg-streamer/input_uvc.so -n -f 30 -r 1280x720" -o "/usr/local/lib/mjpg-streamer/output_http.so -p 8080 -w /usr/local/share/mjpg-streamer/www"
+
+# 树莓派桌面版,浏览器自动开启全屏在下面桌面路径增加
+#/etc/xdg/lxsession/LXDE-pi/autostart
+# kiosk模式
+@chromium-browser --kiosk www.raspberrypi.org
+# 全屏模式
+@chromium-browser --start-fullscreen www.raspberrypi.org
+# 最大化
+@chromium-browser --start-maximized www.raspberrypi.org
+
+# 注意 
+rpio-pwm 的库中位34
+<!-- 换算比例=>34电调中位,比例范围17~34~51 -->
+const ratio = Math.floor(256 / 34 * 10) / 10
+<!-- 换算比例:摇杆范围0-256 -->
+return Math.round(v / ratio + 17)

+ 0 - 103
index.js

@@ -1,103 +0,0 @@
-
-// wrt + socket + contrl
-const io = require("socket.io-client")
-const PWM = require('./lib/Pwm')
-const { PeerConnection, Video } = require('node-datachannel');
-const { createSocket } = require('dgram')
-const { spawn } = require('child_process')
-
-// const url = 'ws://10.10.3.196:7896'
-const url = process.argv.splice(2);
-class CarServer {
-    constructor() {
-        this.Peer = null
-        this.track = null
-        this.child = null
-        this.udp = null
-        this.socket = io(url, { auth: { roomID: "feiCar", name: 'car' } });
-        this.socket.on('connect', this.connected.bind(this))
-        this.socket.on('msg', this.onMsg.bind(this))
-        this.socket.on('leaved', this.onLeved.bind(this))
-        this.socket.on('joined', this.startVideo.bind(this))
-    }
-    // socket 连接
-    connected() {
-        console.log('connected');
-        this.Peer = new PeerConnection("Peer1", { iceServers: [] });
-        // 发送offer
-        this.Peer.onGatheringStateChange(state => {
-            console.log('GatheringState: ', state);
-            if (state === 'complete') {
-                const offer = this.Peer.localDescription();
-                this.socket.emit("msg", offer);
-            }
-        })
-    }
-
-    // 用户信息
-    onMsg(data) {
-        try {
-            if (data.type == 'answer') {
-                this.Peer.setRemoteDescription(data.sdp, data.type);
-            } else if (data.type === 'startRTC') {
-                this.startVideo()
-            } if (data.type === 'conctrl') {
-                PWM.changPWM(data.conctrl)
-            }
-        } catch (error) {
-            console.log('msg error:', error);
-        }
-    }
-
-    // 用户离开
-    onLeved() {
-        if (this.child) this.child.kill()
-        if (this.udp) this.udp.close()
-        this.child = null
-        this.udp = null
-        process.exit(1)
-    }
-
-    // 开始视频
-    startVideo() {
-        try {
-            if (this.child) this.child.kill()
-            if (this.udp) this.udp.close()
-
-            // test video
-            const video = new Video('video', 'SendOnly')
-            video.addH264Codec(96)
-            video.addSSRC(42, "video-send")
-            this.track = this.Peer.addTrack(video)
-            this.Peer.setLocalDescription()
-
-            // UDP server
-            const port = 7788
-            this.udp = createSocket("udp4")
-            this.udp.bind(port)
-
-            // video push
-            const args = [
-                "libcamerasrc",
-                "video/x-raw,width=640,height=480",
-                "videoconvert",
-                "queue",
-                "x264enc tune=zerolatency bitrate=1000 key-int-max=30",
-                "video/x-h264, profile=constrained-baseline",
-                "rtph264pay pt=96 mtu=1200 ssrc=42",
-                `udpsink host=127.0.0.1 port=${port}`,
-            ].join(" ! ").split(" ")
-            this.child = spawn("gst-launch-1.0", args)
-
-            // listen UDP
-            this.udp.on("message", (data) => {
-                if (!this.track.isOpen()) return
-                this.track.sendMessageBinary(data)
-            });
-
-        } catch (error) {
-            console.log('startvideo:', error)
-        }
-    }
-}
-new CarServer(url[0])

+ 0 - 69
install.sh

@@ -1,69 +0,0 @@
-sudo rm -rf /root/car/
-sudo systemctl stop car.service
-sudo rm /lib/systemd/system/car.service
-sudo mkdir /root/car/
-echo "下载安装包..."
-if sudo wget -O /root/car/car.zip https://cloud.caner.top/api/v3/file/get/4667/car.zip?sign=LHXY5OdRwtfqu7EaGYMC95DgKlPygn7S3VwScqG4vUs%3D%3A0; then
-    echo '开始解压...'
-else
-    echo '下载失败,请重试!'
-    exit 1
-fi
-
-if unzip -o /root/car/car.zip -d /root/car/;then
-    rm /root/car/car.zip
-    sudo chmod 744 /root/car/index.js
-    sudo chmod 744 /root/car/lib/node
-    echo ''
-else
-    echo '解压失败!'
-    exit 1
-fi
-  
-echo '开始安装gstreamer 依赖...'
-if sudo apt-get install libx264-dev libjpeg-dev libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev libgstreamer-plugins-bad1.0-dev gstreamer1.0-plugins-ugly gstreamer1.0-tools gstreamer1.0-gl gstreamer1.0-gtk3 gstreamer1.0-pulseaudio -y;then
-    echo 'gstreamer 安装成功'
-else
-    echo 'gstreamer 安装失败,请重试!'
-    exit 1
-fi
-
-read -p "输入车端socket地址(ws://ip:port):" URL
-URL=${URL:-URL}
-if  [ ! -n "$URL" ] ;then
-    echo "请输入车端socket地址"
-    exit 1
-else
-    echo "遥控端地址:$URL"
-fi
-
-echo "[Unit]
-Description=Car-server
-After=network.target
-
-[Service]
-Type=simple
-User=root
-ExecStart=/root/car/lib/node /root/car/index.js $URL &
-Restart=always
-RestartSec=3s
-
-[Install]
-WantedBy=multi-user.target" | sudo tee /lib/systemd/system/car.service
-echo 'systmctl 服务安装成功'
-echo ''
-sudo systemctl daemon-reload
-if sudo systemctl enable car.service;then
-    echo '开机添加成功'
-else
-    echo '开机添加失败,请重试!'
-    exit 1
-fi
-echo ''
-if sudo systemctl start car.service;then
-    echo '车端服务启动成功!'
-else
-    echo '车端服务启动失败,请重试!'
-    exit 1
-fi    
-exit

+ 0 - 147
lib/Pwm.js

@@ -1,147 +0,0 @@
-// PCA9685 PWM控制模块
-const i2cBus = require("i2c-bus")
-const { Pca9685Driver } = require("pca9685")
-const RPIO = require("rpio");
-
-class ContrlService {
-    constructor() {
-        // PWM 和 舵机配置
-        this.pwmOption = {
-            i2c: i2cBus.openSync(1), // 树莓派1:scl1
-            address: 0x40, //板子地址
-            frequency: 50, //频率
-            debug: false
-        }
-        //PCA 板子位置电调+舵机
-        this.MoAndSero = {
-            m1: 1,
-            m2: 0,
-            s1: 2,
-            s2: 3
-        }
-        // prio init
-        RPIO.init({ mapping: "gpio" });
-        // 继电器解锁
-        RPIO.open(6, RPIO.OUTPUT, RPIO.LOW);
-        //关闭继电器
-        RPIO.open(13, RPIO.OUTPUT, RPIO.LOW);
-        // 开灯
-        RPIO.open(19, RPIO.OUTPUT, RPIO.LOW);
-        // init PWM
-        this.PWM = new Pca9685Driver(this.pwmOption, er => {
-            if (er) {
-                console.error("Error initializing PCA9685");
-            }
-        })
-        // 解锁计数器
-        this.Snum = 0
-        // 解锁状态
-        this.enable = false
-        // 摇杆解锁
-        this.contrlEnable = false
-        // 摇杆中立值110-120
-        this.centerNum = 120
-    }
-    // 设置pwm
-    async changPWM(params) {
-        const { v0, v1, v2, v3 } = params
-        if (typeof (v0) == 'number' || typeof (v2) == 'number') {
-            // 内八解锁
-            if (this.enable) {
-                //中位值
-                if (!this.contrlEnable) {
-                    this.PWM.setPulseLength(this.MoAndSero.m1, this.Motor2pwm(Math.abs(this.centerNum)));
-                    this.PWM.setPulseLength(this.MoAndSero.m2, this.Motor2pwm(Math.abs(this.centerNum)));
-                }
-                //上推解锁
-                if (!this.contrlEnable && +v3 < 200) this.contrlEnable = true
-                // PWM操作
-                if (this.contrlEnable) {
-                    // 注意中位误差
-                    if (Math.abs(+v3 - this.centerNum) < 20) {
-                        this.PWM.setPulseLength(this.MoAndSero.m1, this.Motor2pwm(Math.abs(+v2 - 255)));
-                        this.PWM.setPulseLength(this.MoAndSero.m2, this.Motor2pwm(Math.abs(+v2 - 255)));
-                    } else {
-                        // 分左右 注意左右误差
-                        if ((+v3 - this.centerNum) > 20) {
-                            // 右
-                            const a = this.centerNum - (+v3 - this.centerNum)
-                            const b = this.centerNum + (+v3 - this.centerNum)
-                            this.PWM.setPulseLength(this.MoAndSero.m1, this.Motor2pwm(+a));
-                            this.PWM.setPulseLength(this.MoAndSero.m2, this.Motor2pwm(+b));
-                        } else if (+v3 - this.centerNum < -20) {
-                            // 左
-                            const a = this.centerNum - (+v3 - this.centerNum)
-                            const b = this.centerNum + (+v3 - this.centerNum)
-                            this.PWM.setPulseLength(this.MoAndSero.m1, this.Motor2pwm(+a));
-                            this.PWM.setPulseLength(this.MoAndSero.m2, this.Motor2pwm(+b));
-                        }
-                    }
-
-                }
-                //云台
-                if (v0 || v1) {
-                    const a = +v1 > 200 ? 200 : +v1
-                    this.PWM.setPulseLength(this.MoAndSero.s1, this.Servo2pwm(+v0));
-                    this.PWM.setPulseLength(this.MoAndSero.s2, this.Servo2pwm(+a));
-                }
-                console.log('前后', v3, '左右', v2, '云台', v0, v1)
-            } else {
-                this.unLOCK(v0, v1, v2, v3)
-            }
-        } else {
-            console.log('参数格式错误,自动略过');
-            return
-        }
-    }
-
-    /**
-     * 内八解锁
-     * @param {*} v0 
-     * @param {*} v1 
-     * @param {*} v2 
-     * @param {*} v3 
-     */
-    unLOCK(v0, v1, v2, v3) {
-        // 未解锁=>进行解锁:发送端的频率是0.05S,0.05*60 = 3S        
-        // 内八 :v0<50,v1>200,v2>200,v3<50
-        if (+v0 <= 60 && +v1 >= 190 && +v3 >= 190 && +v2 <= 60) {
-            if (this.Snum >= 0 && this.Snum <= 51) this.Snum++
-        } else {
-            this.Snum = 0
-        }
-        if (this.Snum == 50) {
-            //继电器
-            RPIO.open(19, RPIO.OUTPUT, RPIO.HIGH);
-            //空闲继电器
-            //RPIO.open(13, RPIO.OUTPUT, RPIO.HIGH);
-            //空闲继电器
-            //RPIO.open(6, RPIO.OUTPUT, RPIO.HIGH);
-            this.enable = true
-        }
-        console.log('解锁中', v0, v1, v2, v3)
-    }
-    /**
-     * 电调换算比例:摇杆范围0-255,PWM范围500~1500~2500
-     * @param {number} v 
-     * @returns 
-     */
-    Motor2pwm(v) {
-        if (v === 0) {
-            return parseInt(10 / (256 / 1000)) + 1000
-        } else if (v >= 200) {
-            return parseInt(200 / (256 / 1000)) + 1000
-        } else {
-            return parseInt((v - 5) / (256 / 1000)) + 1000
-        }
-    }
-    /**
-     * 舵机换算比例:摇杆范围0-256,PWM范围1000~1500~2000
-     * @param {number} v 
-     * @returns 
-     */
-    Servo2pwm(v) {
-        return parseInt(v / (256 / 1000)) + 1000
-    }
-}
-module.exports = new ContrlService()

BIN
lib/node


+ 0 - 44
lib/npm

@@ -1,44 +0,0 @@
-#!/usr/bin/env bash
-(set -o igncr) 2>/dev/null && set -o igncr; # cygwin encoding fix
-
-basedir=`dirname "$0"`
-
-case `uname` in
-  *CYGWIN*) basedir=`cygpath -w "$basedir"`;;
-esac
-
-NODE_EXE="$basedir/node.exe"
-if ! [ -x "$NODE_EXE" ]; then
-  NODE_EXE="$basedir/node"
-fi
-if ! [ -x "$NODE_EXE" ]; then
-  NODE_EXE=node
-fi
-
-# this path is passed to node.exe, so it needs to match whatever
-# kind of paths Node.js thinks it's using, typically win32 paths.
-CLI_BASEDIR="$("$NODE_EXE" -p 'require("path").dirname(process.execPath)')"
-NPM_CLI_JS="$CLI_BASEDIR/node_modules/npm/bin/npm-cli.js"
-
-NPM_PREFIX=`"$NODE_EXE" "$NPM_CLI_JS" prefix -g`
-if [ $? -ne 0 ]; then
-  # if this didn't work, then everything else below will fail
-  echo "Could not determine Node.js install directory" >&2
-  exit 1
-fi
-NPM_PREFIX_NPM_CLI_JS="$NPM_PREFIX/node_modules/npm/bin/npm-cli.js"
-
-# a path that will fail -f test on any posix bash
-NPM_WSL_PATH="/.."
-
-# WSL can run Windows binaries, so we have to give it the win32 path
-# however, WSL bash tests against posix paths, so we need to construct that
-# to know if npm is installed globally.
-if [ `uname` = 'Linux' ] && type wslpath &>/dev/null ; then
-  NPM_WSL_PATH=`wslpath "$NPM_PREFIX_NPM_CLI_JS"`
-fi
-if [ -f "$NPM_PREFIX_NPM_CLI_JS" ] || [ -f "$NPM_WSL_PATH" ]; then
-  NPM_CLI_JS="$NPM_PREFIX_NPM_CLI_JS"
-fi
-
-"$NODE_EXE" "$NPM_CLI_JS" "$@"

+ 44 - 0
main.js

@@ -0,0 +1,44 @@
+const net = require('net');
+const PWM = require('/home/pi/Node.server/Contrl/index.js')
+// socket Server
+class netServer {
+    constructor(HOST = '0.0.0.0', PORT = 6969) {
+        // ----------SOCKET 服务-----------
+        this.server = net.createServer((sock) => {
+            console.log('client connected:', sock.remoteAddress, ':', sock.remotePort)
+            sock.setEncoding('utf8')
+            // 监听数据
+            sock.on('data', (data) => {
+                try {
+                    const typeDb = JSON.parse(data)
+                    if (typeDb.type == 'conctrl') {
+                        PWM.changPWM(typeDb.data)
+                    }
+                } catch (error) {
+                    console.log('错误', error);
+                }
+            })
+            // 监听退出
+            sock.on('end', () => {
+                console.log('client disconnected')
+            })
+            // 监听错误
+            sock.on('error', (err) => {
+                let errcode = ''
+                switch (err.code) {
+                    case 'ECONNRESET':
+                        errcode = '客户端断开'
+                        break
+                    default:
+                        errcode = err.code
+                        break
+                }
+                console.log(errcode)
+            })
+        })
+        console.log('server listen: ' + HOST + ':' + PORT)
+        this.server.maxConnections = 1
+        this.server.listen(PORT, HOST)
+    }
+}
+new netServer()

+ 100 - 0
package-lock.json

@@ -0,0 +1,100 @@
+{
+  "name": "node.socket",
+  "version": "1.0.0",
+  "lockfileVersion": 1,
+  "requires": true,
+  "dependencies": {
+    "@types/debug": {
+      "version": "4.1.5",
+      "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.5.tgz",
+      "integrity": "sha512-Q1y515GcOdTHgagaVFhHnIFQ38ygs/kmxdNpvpou+raI9UO3YZcHDngBSYKQklcKlvA7iuQlmIKbzvmxcOE9CQ=="
+    },
+    "@types/i2c-bus": {
+      "version": "5.1.0",
+      "resolved": "https://registry.npmjs.org/@types/i2c-bus/-/i2c-bus-5.1.0.tgz",
+      "integrity": "sha512-zBwBpfaFzKtYaS2j/sh+m/zKRcbXuG26/wWlJq3F9+oWXQ9DSxuJXOU+t1PMorj3DBZzpLO8LqbVTGRE1PUb3g==",
+      "requires": {
+        "@types/node": "*"
+      }
+    },
+    "@types/node": {
+      "version": "16.11.11",
+      "resolved": "https://registry.npmjs.org/@types/node/-/node-16.11.11.tgz",
+      "integrity": "sha512-KB0sixD67CeecHC33MYn+eYARkqTheIRNuu97y2XMjR7Wu3XibO1vaY6VBV6O/a89SPI81cEUIYT87UqUWlZNw=="
+    },
+    "bindings": {
+      "version": "1.5.0",
+      "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz",
+      "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==",
+      "requires": {
+        "file-uri-to-path": "1.0.0"
+      }
+    },
+    "debug": {
+      "version": "4.3.3",
+      "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz",
+      "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==",
+      "requires": {
+        "ms": "2.1.2"
+      }
+    },
+    "file-uri-to-path": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz",
+      "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw=="
+    },
+    "i2c-bus": {
+      "version": "5.2.2",
+      "resolved": "https://registry.npmjs.org/i2c-bus/-/i2c-bus-5.2.2.tgz",
+      "integrity": "sha512-b2y/et08rqggEjqod6QxV0Ng+RlSkZXsdE+E1aZEQBahepZ9uFD9XfA77Y8O9SgyhwfGEn+CNxsw0gvXW1/m4g==",
+      "requires": {
+        "bindings": "^1.5.0",
+        "nan": "^2.14.2"
+      }
+    },
+    "ms": {
+      "version": "2.1.2",
+      "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
+      "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
+    },
+    "nan": {
+      "version": "2.15.0",
+      "resolved": "https://registry.npmjs.org/nan/-/nan-2.15.0.tgz",
+      "integrity": "sha512-8ZtvEnA2c5aYCZYd1cvgdnU6cqwixRoYg70xPLWUws5ORTa/lnw+u4amixRS/Ac5U5mQVgp9pnlSUnbNWFaWZQ=="
+    },
+    "pca9685": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/pca9685/-/pca9685-5.0.0.tgz",
+      "integrity": "sha512-3YFh4YJg8aCX3l+xB1PSojpI6AjNpS5QbSAJDfJoftft1SVNzZAE386XFqB8YiVy3ur7DWbafXHcA5ZfA7uUHw==",
+      "requires": {
+        "@types/debug": "4.1.5",
+        "@types/i2c-bus": "^5.1.0",
+        "debug": "^4.3.1",
+        "i2c-bus": "^5.2.1",
+        "rxjs": "^6.6.3"
+      }
+    },
+    "rpio": {
+      "version": "2.4.2",
+      "resolved": "https://registry.npmjs.org/rpio/-/rpio-2.4.2.tgz",
+      "integrity": "sha512-SiWw2VorgUh+0hbu6eJkRGG+luvS9BboXz6PQl8Z49kJ+8Nn7R/b4ohybLIYSMbQqcW1WYqSooadDuv1VOAiFw==",
+      "requires": {
+        "bindings": "~1.5.0",
+        "nan": "^2.14.1"
+      }
+    },
+    "rxjs": {
+      "version": "6.6.7",
+      "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz",
+      "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==",
+      "requires": {
+        "tslib": "^1.9.0"
+      }
+    },
+    "tslib": {
+      "version": "1.14.1",
+      "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
+      "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
+    }
+  }
+}

+ 4 - 6
package.json

@@ -1,18 +1,16 @@
 {
-  "name": "car",
+  "name": "node.socket",
   "version": "1.0.0",
   "description": "",
-  "main": "index.js",
+  "main": "main.js",
   "scripts": {
     "test": "echo \"Error: no test specified\" && exit 1"
   },
   "author": "",
   "license": "ISC",
   "dependencies": {
-    "node-datachannel": "^0.3.4",
-    "socket.io-client": "^4.4.1",
+    "rpio": "^2.1.1",
     "i2c-bus": "^5.2.2",
-    "pca9685": "^5.0.0",
-    "rpio": "^2.4.2"
+    "pca9685": "^5.0.0"
   }
 }

+ 2 - 0
video.sh

@@ -0,0 +1,2 @@
+#!/bin/sh
+/usr/local/bin/mjpg_streamer -i "/usr/local/lib/mjpg-streamer/input_uvc.so -n -f 60 -r 640x360" -o "/usr/local/lib/mjpg-streamer/output_http.so -p 8080 -w /usr/local/share/mjpg-streamer/www"