├── GUI ├── IP.txt ├── requirements.txt ├── Instruction.txt └── logo.png ├── .gitignore ├── client ├── IP.txt ├── requirements.txt ├── Instruction.txt └── logo.png ├── config.json ├── server ├── dist │ ├── robots.txt │ ├── img │ │ ├── bg.jpg │ │ └── icons │ │ │ ├── logo.png │ │ │ ├── favicon.ico │ │ │ ├── favicon-32x32 .png │ │ │ └── safari-pinned-tab.svg │ ├── favicon.ico │ ├── fonts │ │ ├── roboto-latin-100.5cb7edfc.woff │ │ ├── roboto-latin-100.7370c367.woff2 │ │ ├── roboto-latin-300.b00849e0.woff │ │ ├── roboto-latin-300.ef7c6637.woff2 │ │ ├── roboto-latin-400.479970ff.woff2 │ │ ├── roboto-latin-400.60fa3c06.woff │ │ ├── roboto-latin-500.020c97dc.woff2 │ │ ├── roboto-latin-500.87284894.woff │ │ ├── roboto-latin-700.2735a3a6.woff2 │ │ ├── roboto-latin-700.adcde98f.woff │ │ ├── roboto-latin-900.9b3766ef.woff2 │ │ ├── roboto-latin-900.bb1e4dc6.woff │ │ ├── roboto-latin-100italic.f8b1df51.woff2 │ │ ├── roboto-latin-100italic.f9e8e590.woff │ │ ├── roboto-latin-300italic.14286f3b.woff2 │ │ ├── roboto-latin-300italic.4df32891.woff │ │ ├── roboto-latin-400italic.51521a2a.woff2 │ │ ├── roboto-latin-400italic.fe65b833.woff │ │ ├── roboto-latin-500italic.288ad9c6.woff │ │ ├── roboto-latin-500italic.db4a2a23.woff2 │ │ ├── roboto-latin-700italic.81f57861.woff │ │ ├── roboto-latin-700italic.da0e7178.woff2 │ │ ├── roboto-latin-900italic.28f91510.woff │ │ ├── roboto-latin-900italic.ebf6d164.woff2 │ │ ├── materialdesignicons-webfont.2d0a0d8f.eot │ │ ├── materialdesignicons-webfont.b4917be2.woff │ │ ├── materialdesignicons-webfont.d0066537.woff2 │ │ └── materialdesignicons-webfont.f5111234.ttf │ ├── manifest.json │ ├── service-worker.js │ ├── index.html │ ├── precache-manifest.a14d08d959aeaa21de5cdb2a57fec282.js │ └── css │ │ └── app.5a950261.css ├── requirements.txt ├── ultra.py ├── trackingMoudle.py ├── switch.py ├── info.py ├── Kalman_filter.py ├── PID.py ├── findline.py ├── LEDapp.py ├── app.py ├── OLED.py ├── Instruction.txt ├── LED.py ├── config.txt ├── base_camera.py ├── move.py ├── functions.py ├── servo.py ├── appserverAP.py ├── FPV.py ├── appserver.py ├── RPIservo.py ├── server.py ├── webServer.py ├── raspi-config.py └── robotLight.py ├── images ├── App1.jpg ├── App2.jpg ├── putty.png ├── winSSH.png ├── configSSH.png ├── imagerUse.png ├── mermaid.png ├── RPiDownload.png ├── configWIFI.png ├── webControl.png └── imagerDownload.png ├── initPosServos.py ├── LICENSE ├── autorun.py ├── wifi_hotspot_manager.sh ├── instruction.txt └── setup.py /GUI/IP.txt: -------------------------------------------------------------------------------- 1 | IP:192.168.3.242 -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | venv 2 | .idea 3 | -------------------------------------------------------------------------------- /client/IP.txt: -------------------------------------------------------------------------------- 1 | IP:192.168.3.242 -------------------------------------------------------------------------------- /config.json: -------------------------------------------------------------------------------- 1 | { 2 | "production": true 3 | } 4 | -------------------------------------------------------------------------------- /GUI/requirements.txt: -------------------------------------------------------------------------------- 1 | opencv-python 2 | zmq 3 | numpy -------------------------------------------------------------------------------- /client/requirements.txt: -------------------------------------------------------------------------------- 1 | opencv-python 2 | zmq 3 | numpy -------------------------------------------------------------------------------- /server/dist/robots.txt: -------------------------------------------------------------------------------- 1 | User-agent: * 2 | Disallow: 3 | -------------------------------------------------------------------------------- /GUI/Instruction.txt: -------------------------------------------------------------------------------- 1 | for more information: 2 | www.adeept.com 3 | -------------------------------------------------------------------------------- /client/Instruction.txt: -------------------------------------------------------------------------------- 1 | for more information: 2 | www.adeept.com 3 | -------------------------------------------------------------------------------- /GUI/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adeept/Adeept_RaspTank/HEAD/GUI/logo.png -------------------------------------------------------------------------------- /client/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adeept/Adeept_RaspTank/HEAD/client/logo.png -------------------------------------------------------------------------------- /images/App1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adeept/Adeept_RaspTank/HEAD/images/App1.jpg -------------------------------------------------------------------------------- /images/App2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adeept/Adeept_RaspTank/HEAD/images/App2.jpg -------------------------------------------------------------------------------- /images/putty.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adeept/Adeept_RaspTank/HEAD/images/putty.png -------------------------------------------------------------------------------- /images/winSSH.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adeept/Adeept_RaspTank/HEAD/images/winSSH.png -------------------------------------------------------------------------------- /images/configSSH.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adeept/Adeept_RaspTank/HEAD/images/configSSH.png -------------------------------------------------------------------------------- /images/imagerUse.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adeept/Adeept_RaspTank/HEAD/images/imagerUse.png -------------------------------------------------------------------------------- /images/mermaid.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adeept/Adeept_RaspTank/HEAD/images/mermaid.png -------------------------------------------------------------------------------- /images/RPiDownload.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adeept/Adeept_RaspTank/HEAD/images/RPiDownload.png -------------------------------------------------------------------------------- /images/configWIFI.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adeept/Adeept_RaspTank/HEAD/images/configWIFI.png -------------------------------------------------------------------------------- /images/webControl.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adeept/Adeept_RaspTank/HEAD/images/webControl.png -------------------------------------------------------------------------------- /server/dist/img/bg.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adeept/Adeept_RaspTank/HEAD/server/dist/img/bg.jpg -------------------------------------------------------------------------------- /images/imagerDownload.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adeept/Adeept_RaspTank/HEAD/images/imagerDownload.png -------------------------------------------------------------------------------- /server/dist/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adeept/Adeept_RaspTank/HEAD/server/dist/favicon.ico -------------------------------------------------------------------------------- /server/dist/img/icons/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adeept/Adeept_RaspTank/HEAD/server/dist/img/icons/logo.png -------------------------------------------------------------------------------- /server/dist/img/icons/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adeept/Adeept_RaspTank/HEAD/server/dist/img/icons/favicon.ico -------------------------------------------------------------------------------- /server/dist/img/icons/favicon-32x32 .png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adeept/Adeept_RaspTank/HEAD/server/dist/img/icons/favicon-32x32 .png -------------------------------------------------------------------------------- /server/dist/fonts/roboto-latin-100.5cb7edfc.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adeept/Adeept_RaspTank/HEAD/server/dist/fonts/roboto-latin-100.5cb7edfc.woff -------------------------------------------------------------------------------- /server/dist/fonts/roboto-latin-100.7370c367.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adeept/Adeept_RaspTank/HEAD/server/dist/fonts/roboto-latin-100.7370c367.woff2 -------------------------------------------------------------------------------- /server/dist/fonts/roboto-latin-300.b00849e0.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adeept/Adeept_RaspTank/HEAD/server/dist/fonts/roboto-latin-300.b00849e0.woff -------------------------------------------------------------------------------- /server/dist/fonts/roboto-latin-300.ef7c6637.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adeept/Adeept_RaspTank/HEAD/server/dist/fonts/roboto-latin-300.ef7c6637.woff2 -------------------------------------------------------------------------------- /server/dist/fonts/roboto-latin-400.479970ff.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adeept/Adeept_RaspTank/HEAD/server/dist/fonts/roboto-latin-400.479970ff.woff2 -------------------------------------------------------------------------------- /server/dist/fonts/roboto-latin-400.60fa3c06.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adeept/Adeept_RaspTank/HEAD/server/dist/fonts/roboto-latin-400.60fa3c06.woff -------------------------------------------------------------------------------- /server/dist/fonts/roboto-latin-500.020c97dc.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adeept/Adeept_RaspTank/HEAD/server/dist/fonts/roboto-latin-500.020c97dc.woff2 -------------------------------------------------------------------------------- /server/dist/fonts/roboto-latin-500.87284894.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adeept/Adeept_RaspTank/HEAD/server/dist/fonts/roboto-latin-500.87284894.woff -------------------------------------------------------------------------------- /server/dist/fonts/roboto-latin-700.2735a3a6.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adeept/Adeept_RaspTank/HEAD/server/dist/fonts/roboto-latin-700.2735a3a6.woff2 -------------------------------------------------------------------------------- /server/dist/fonts/roboto-latin-700.adcde98f.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adeept/Adeept_RaspTank/HEAD/server/dist/fonts/roboto-latin-700.adcde98f.woff -------------------------------------------------------------------------------- /server/dist/fonts/roboto-latin-900.9b3766ef.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adeept/Adeept_RaspTank/HEAD/server/dist/fonts/roboto-latin-900.9b3766ef.woff2 -------------------------------------------------------------------------------- /server/dist/fonts/roboto-latin-900.bb1e4dc6.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adeept/Adeept_RaspTank/HEAD/server/dist/fonts/roboto-latin-900.bb1e4dc6.woff -------------------------------------------------------------------------------- /server/dist/fonts/roboto-latin-100italic.f8b1df51.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adeept/Adeept_RaspTank/HEAD/server/dist/fonts/roboto-latin-100italic.f8b1df51.woff2 -------------------------------------------------------------------------------- /server/dist/fonts/roboto-latin-100italic.f9e8e590.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adeept/Adeept_RaspTank/HEAD/server/dist/fonts/roboto-latin-100italic.f9e8e590.woff -------------------------------------------------------------------------------- /server/dist/fonts/roboto-latin-300italic.14286f3b.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adeept/Adeept_RaspTank/HEAD/server/dist/fonts/roboto-latin-300italic.14286f3b.woff2 -------------------------------------------------------------------------------- /server/dist/fonts/roboto-latin-300italic.4df32891.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adeept/Adeept_RaspTank/HEAD/server/dist/fonts/roboto-latin-300italic.4df32891.woff -------------------------------------------------------------------------------- /server/dist/fonts/roboto-latin-400italic.51521a2a.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adeept/Adeept_RaspTank/HEAD/server/dist/fonts/roboto-latin-400italic.51521a2a.woff2 -------------------------------------------------------------------------------- /server/dist/fonts/roboto-latin-400italic.fe65b833.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adeept/Adeept_RaspTank/HEAD/server/dist/fonts/roboto-latin-400italic.fe65b833.woff -------------------------------------------------------------------------------- /server/dist/fonts/roboto-latin-500italic.288ad9c6.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adeept/Adeept_RaspTank/HEAD/server/dist/fonts/roboto-latin-500italic.288ad9c6.woff -------------------------------------------------------------------------------- /server/dist/fonts/roboto-latin-500italic.db4a2a23.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adeept/Adeept_RaspTank/HEAD/server/dist/fonts/roboto-latin-500italic.db4a2a23.woff2 -------------------------------------------------------------------------------- /server/dist/fonts/roboto-latin-700italic.81f57861.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adeept/Adeept_RaspTank/HEAD/server/dist/fonts/roboto-latin-700italic.81f57861.woff -------------------------------------------------------------------------------- /server/dist/fonts/roboto-latin-700italic.da0e7178.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adeept/Adeept_RaspTank/HEAD/server/dist/fonts/roboto-latin-700italic.da0e7178.woff2 -------------------------------------------------------------------------------- /server/dist/fonts/roboto-latin-900italic.28f91510.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adeept/Adeept_RaspTank/HEAD/server/dist/fonts/roboto-latin-900italic.28f91510.woff -------------------------------------------------------------------------------- /server/dist/fonts/roboto-latin-900italic.ebf6d164.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adeept/Adeept_RaspTank/HEAD/server/dist/fonts/roboto-latin-900italic.ebf6d164.woff2 -------------------------------------------------------------------------------- /server/dist/fonts/materialdesignicons-webfont.2d0a0d8f.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adeept/Adeept_RaspTank/HEAD/server/dist/fonts/materialdesignicons-webfont.2d0a0d8f.eot -------------------------------------------------------------------------------- /server/dist/fonts/materialdesignicons-webfont.b4917be2.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adeept/Adeept_RaspTank/HEAD/server/dist/fonts/materialdesignicons-webfont.b4917be2.woff -------------------------------------------------------------------------------- /server/dist/fonts/materialdesignicons-webfont.d0066537.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adeept/Adeept_RaspTank/HEAD/server/dist/fonts/materialdesignicons-webfont.d0066537.woff2 -------------------------------------------------------------------------------- /server/dist/fonts/materialdesignicons-webfont.f5111234.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adeept/Adeept_RaspTank/HEAD/server/dist/fonts/materialdesignicons-webfont.f5111234.ttf -------------------------------------------------------------------------------- /server/requirements.txt: -------------------------------------------------------------------------------- 1 | adafruit-pca9685 2 | rpi_ws281x 3 | mpu6050-raspberrypi 4 | flask 5 | flask_cors 6 | websockets 7 | numpy 8 | opencv-contrib-python==3.4.3.18 9 | imutils 10 | zmq 11 | pybase64 12 | psutil 13 | luma.oled 14 | -------------------------------------------------------------------------------- /initPosServos.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # File name : init 3 | # Description : Control Servos 4 | # Author : William 5 | # Date : 2019/02/23 6 | import time 7 | import Adafruit_PCA9685 8 | 9 | pwm = Adafruit_PCA9685.PCA9685() 10 | pwm.set_pwm_freq(50) 11 | 12 | while 1: 13 | pwm.set_all_pwm(0, 300) 14 | time.sleep(1) -------------------------------------------------------------------------------- /server/dist/manifest.json: -------------------------------------------------------------------------------- 1 | {"name":"adeept_bot_controller_web","short_name":"adeept_bot_controller_web","theme_color":"#4DBA87","icons":[{"src":"./img/icons/android-chrome-192x192.png","sizes":"192x192","type":"image/png"},{"src":"./img/icons/android-chrome-512x512.png","sizes":"512x512","type":"image/png"},{"src":"./img/icons/android-chrome-maskable-192x192.png","sizes":"192x192","type":"image/png","purpose":"maskable"},{"src":"./img/icons/android-chrome-maskable-512x512.png","sizes":"512x512","type":"image/png","purpose":"maskable"}],"start_url":".","display":"standalone","background_color":"#000000"} -------------------------------------------------------------------------------- /server/ultra.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | # File name : Ultrasonic.py 3 | # Description : Detection distance and tracking with ultrasonic 4 | # Website : www.gewbot.com 5 | # Author : William 6 | # Date : 2019/02/23 7 | from gpiozero import DistanceSensor 8 | from time import sleep 9 | Tr = 23 10 | Ec = 24 11 | 12 | 13 | sensor = DistanceSensor(echo=Ec, trigger=Tr, max_distance=2) # Maximum detection distance 2m. 14 | 15 | def checkdist(): 16 | return (sensor.distance) *100 # Unit: cm 17 | 18 | if __name__ == '__main__': 19 | while True: 20 | distance = checkdist()*100 21 | print("%.2f cm" %distance) 22 | sleep(0.05) 23 | -------------------------------------------------------------------------------- /server/trackingMoudle.py: -------------------------------------------------------------------------------- 1 | import time 2 | import RPi.GPIO as GPIO 3 | 4 | 5 | line_pin_right = 19 6 | line_pin_middle = 16 7 | line_pin_left = 20 8 | 9 | def setup(): 10 | GPIO.setwarnings(False) 11 | GPIO.setmode(GPIO.BCM) 12 | GPIO.setup(line_pin_right,GPIO.IN) 13 | GPIO.setup(line_pin_middle,GPIO.IN) 14 | GPIO.setup(line_pin_left,GPIO.IN) 15 | #motor.setup() 16 | 17 | 18 | def run(): 19 | status_right = GPIO.input(line_pin_right) 20 | status_middle = GPIO.input(line_pin_middle) 21 | status_left = GPIO.input(line_pin_left) 22 | print('LF3: %d LF2: %d LF1: %d\n'%(status_right,status_middle,status_left)) 23 | time.sleep(0.2) 24 | if __name__ == '__main__': 25 | try: 26 | setup() 27 | while True: 28 | run() 29 | except KeyboardInterrupt: 30 | pass 31 | 32 | 33 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Adeept 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /server/dist/service-worker.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Welcome to your Workbox-powered service worker! 3 | * 4 | * You'll need to register this file in your web app and you should 5 | * disable HTTP caching for this file too. 6 | * See https://goo.gl/nhQhGp 7 | * 8 | * The rest of the code is auto-generated. Please don't update this file 9 | * directly; instead, make changes to your Workbox build configuration 10 | * and re-run your build process. 11 | * See https://goo.gl/2aRDsh 12 | */ 13 | 14 | importScripts("https://storage.googleapis.com/workbox-cdn/releases/4.3.1/workbox-sw.js"); 15 | 16 | importScripts( 17 | "/precache-manifest.a14d08d959aeaa21de5cdb2a57fec282.js" 18 | ); 19 | 20 | workbox.core.setCacheNameDetails({prefix: "adeept_bot_controller_web"}); 21 | 22 | self.addEventListener('message', (event) => { 23 | if (event.data && event.data.type === 'SKIP_WAITING') { 24 | self.skipWaiting(); 25 | } 26 | }); 27 | 28 | /** 29 | * The workboxSW.precacheAndRoute() method efficiently caches and responds to 30 | * requests for URLs in the manifest. 31 | * See https://goo.gl/S9QRab 32 | */ 33 | self.__precacheManifest = [].concat(self.__precacheManifest || []); 34 | workbox.precaching.precacheAndRoute(self.__precacheManifest, {}); 35 | -------------------------------------------------------------------------------- /server/switch.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env/python 2 | # File name : switch.py 3 | # Website : www.adeept.com 4 | # Author : Adeept 5 | # Date : 2025/05/15 6 | 7 | import time 8 | 9 | from gpiozero import LED 10 | 11 | 12 | def switchSetup(): 13 | global led1,led2,led3 14 | led1 = LED(9) 15 | led2 = LED(25) 16 | led3 = LED(11) 17 | 18 | def switch(port, status): 19 | if port == 1: 20 | if status == 1: 21 | led1.on() 22 | elif status == 0: 23 | led1.off() 24 | elif port == 2: 25 | if status == 1: 26 | led2.on() 27 | elif status == 0: 28 | led2.off() 29 | elif port == 3: 30 | if status == 1: 31 | led3.on() 32 | elif status == 0: 33 | led3.off() 34 | else: 35 | print('Wrong Command: Example--switch(3, 1)->to switch on port3') 36 | 37 | def set_all_switch_off(): 38 | switch(1,0) 39 | switch(2,0) 40 | switch(3,0) 41 | 42 | 43 | if __name__ == "__main__": 44 | switchSetup() 45 | while True: 46 | switch(1,1) 47 | time.sleep(1) 48 | switch(2,1) 49 | time.sleep(1) 50 | switch(3,1) 51 | time.sleep(1) 52 | set_all_switch_off() 53 | time.sleep(1) -------------------------------------------------------------------------------- /server/info.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | # File name : Ultrasonic.py 3 | # Description : Detection distance and tracking with ultrasonic 4 | # Website : www.gewbot.com 5 | # Author : William 6 | # Date : 2019/08/28 7 | import psutil 8 | 9 | def get_cpu_tempfunc(): 10 | """ Return CPU temperature """ 11 | result = 0 12 | mypath = "/sys/class/thermal/thermal_zone0/temp" 13 | with open(mypath, 'r') as mytmpfile: 14 | for line in mytmpfile: 15 | result = line 16 | 17 | result = float(result)/1000 18 | result = round(result, 1) 19 | return str(result) 20 | 21 | 22 | def get_gpu_tempfunc(): 23 | """ Return GPU temperature as a character string""" 24 | res = os.popen('/opt/vc/bin/vcgencmd measure_temp').readline() 25 | return res.replace("temp=", "") 26 | 27 | 28 | def get_cpu_use(): 29 | """ Return CPU usage using psutil""" 30 | cpu_cent = psutil.cpu_percent() 31 | return str(cpu_cent) 32 | 33 | 34 | def get_ram_info(): 35 | """ Return RAM usage using psutil """ 36 | ram_cent = psutil.virtual_memory()[2] 37 | return str(ram_cent) 38 | 39 | 40 | def get_swap_info(): 41 | """ Return swap memory usage using psutil """ 42 | swap_cent = psutil.swap_memory()[3] 43 | return str(swap_cent) 44 | -------------------------------------------------------------------------------- /server/Kalman_filter.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/python 2 | # File name : car_dir.py 3 | # Description : By controlling Servo,thecamera can move Up and down,left and right and the Ultrasonic wave can move to left and right. 4 | # Website : www.gewbot.com 5 | # Author : William 6 | # Date : 2018/08/22 7 | import time 8 | 9 | 10 | class Kalman_filter: 11 | def __init__(self,Q,R): 12 | self.Q = Q 13 | self.R = R 14 | 15 | self.P_k_k1 = 1 16 | self.Kg = 0 17 | self.P_k1_k1 = 1 18 | self.x_k_k1 = 0 19 | self.ADC_OLD_Value = 0 20 | self.Z_k = 0 21 | self.kalman_adc_old=0 22 | 23 | def kalman(self,ADC_Value): 24 | 25 | self.Z_k = ADC_Value 26 | 27 | if (abs(self.kalman_adc_old-ADC_Value)>=60): 28 | self.x_k1_k1= ADC_Value*0.382 + self.kalman_adc_old*0.618 29 | else: 30 | self.x_k1_k1 = self.kalman_adc_old; 31 | 32 | self.x_k_k1 = self.x_k1_k1 33 | self.P_k_k1 = self.P_k1_k1 + self.Q 34 | 35 | self.Kg = self.P_k_k1/(self.P_k_k1 + self.R) 36 | 37 | kalman_adc = self.x_k_k1 + self.Kg * (self.Z_k - self.kalman_adc_old) 38 | self.P_k1_k1 = (1 - self.Kg)*self.P_k_k1 39 | self.P_k_k1 = self.P_k1_k1 40 | 41 | self.kalman_adc_old = kalman_adc 42 | 43 | return kalman_adc -------------------------------------------------------------------------------- /server/dist/index.html: -------------------------------------------------------------------------------- 1 | adeept_bot_controller_web
-------------------------------------------------------------------------------- /server/PID.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/python 2 | # File name : car_dir.py 3 | # Description : By controlling Servo,thecamera can move Up and down,left and right and the Ultrasonic wave can move to left and right. 4 | # Website : www.gewbot.com 5 | # Author : William 6 | # Date : 2018/08/22 7 | import time 8 | 9 | 10 | class PID: 11 | def __init__(self): 12 | self.Kp = 0 13 | self.Kd = 0 14 | self.Ki = 0 15 | self.Initialize() 16 | 17 | def SetKp(self,invar): 18 | self.Kp = invar 19 | 20 | def SetKi(self,invar): 21 | self.Ki = invar 22 | 23 | def SetKd(self,invar): 24 | self.Kd = invar 25 | 26 | def SetPrevError(self,preverror): 27 | self.prev_error = preverror 28 | 29 | def Initialize(self): 30 | self.currtime = time.time() 31 | self.prevtime = self.currtime 32 | 33 | self.prev_error = 0 34 | 35 | self.Cp = 0 36 | self.Ci = 0 37 | self.Cd = 0 38 | 39 | def GenOut(self,error): 40 | self.currtime = time.time() 41 | dt = self.currtime - self.prevtime 42 | de = error - self.prev_error 43 | 44 | self.Cp = self.Kp*error 45 | self.Ci += error*dt 46 | 47 | self.Cd = 0 48 | if dt > 0: 49 | self.Cd = de/dt 50 | 51 | self.prevtime = self.currtime 52 | self.prev_error = error 53 | 54 | return self.Cp + (self.Ki*self.Ci) + (self.Kd*self.Cd) 55 | ''' 56 | pid = PID() 57 | pid.SetKp(Kp) 58 | pid.SetKd(Kd) 59 | pid.SetKi(Ki) 60 | 61 | fb = 0 62 | outv = 0 63 | 64 | PID_loop = True 65 | 66 | while PID_loop: 67 | error = Sp - fb 68 | 69 | outv = pid.GenOut(error) 70 | AnalogOut(outv) 71 | 72 | time.sleep(0.05) 73 | 74 | fb = AnalogIn(fb_input) 75 | pass 76 | ''' -------------------------------------------------------------------------------- /server/findline.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | # File name : findline.py 3 | # Description : line tracking 4 | # Website : www.gewbot.com 5 | # Author : William 6 | # Date : 2019/08/28 7 | import RPi.GPIO as GPIO 8 | import time 9 | import move 10 | ''' 11 | status = 1 #Motor rotation 12 | forward = 1 #Motor forward 13 | backward = 0 #Motor backward 14 | 15 | left_spd = num_import_int('E_M1:') #Speed of the car 16 | right_spd = num_import_int('E_M2:') #Speed of the car 17 | left = num_import_int('E_T1:') #Motor Left 18 | right = num_import_int('E_T2:') #Motor Right 19 | ''' 20 | line_pin_right = 19 21 | line_pin_middle = 16 22 | line_pin_left = 20 23 | ''' 24 | left_R = 15 25 | left_G = 16 26 | left_B = 18 27 | 28 | right_R = 19 29 | right_G = 21 30 | right_B = 22 31 | 32 | on = GPIO.LOW 33 | off = GPIO.HIGH 34 | 35 | spd_ad_1 = 1 36 | spd_ad_2 = 1 37 | ''' 38 | def setup(): 39 | GPIO.setwarnings(False) 40 | GPIO.setmode(GPIO.BCM) 41 | GPIO.setup(line_pin_right,GPIO.IN) 42 | GPIO.setup(line_pin_middle,GPIO.IN) 43 | GPIO.setup(line_pin_left,GPIO.IN) 44 | #motor.setup() 45 | 46 | def run(): 47 | status_right = GPIO.input(line_pin_right) 48 | status_middle = GPIO.input(line_pin_middle) 49 | status_left = GPIO.input(line_pin_left) 50 | #print('R%d M%d L%d'%(status_right,status_middle,status_left)) 51 | if status_middle == 1: 52 | move.move(100, 'forward', 'no', 1) 53 | elif status_left == 1: 54 | move.move(100, 'forward', 'right', 0.6) 55 | elif status_right == 1: 56 | move.move(100, 'forward', 'left', 0.6) 57 | else: 58 | move.move(100, 'backward', 'no', 1) 59 | 60 | if __name__ == '__main__': 61 | try: 62 | setup() 63 | move.setup() 64 | while 1: 65 | run() 66 | pass 67 | except KeyboardInterrupt: 68 | move.destroy() 69 | -------------------------------------------------------------------------------- /server/LEDapp.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | # File name : LED.py 3 | # Description : WS_2812 4 | # Website : based on the code from https://github.com/rpi-ws281x/rpi-ws281x-python/blob/master/examples/strandtest.py 5 | # Author : original code by Tony DiCola (tony@tonydicola.com) 6 | # Date : 2019/02/23 7 | import time 8 | from rpi_ws281x import * 9 | import argparse 10 | 11 | # LED strip configuration: 12 | LED_COUNT = 3 # Number of LED pixels. 13 | LED_PIN = 12 # GPIO pin connected to the pixels (18 uses PWM!). 14 | #LED_PIN = 10 # GPIO pin connected to the pixels (10 uses SPI /dev/spidev0.0). 15 | LED_FREQ_HZ = 800000 # LED signal frequency in hertz (usually 800khz) 16 | LED_DMA = 10 # DMA channel to use for generating signal (try 10) 17 | LED_BRIGHTNESS = 255 # Set to 0 for darkest and 255 for brightest 18 | LED_INVERT = False # True to invert the signal (when using NPN transistor level shift) 19 | LED_CHANNEL = 0 # set to '1' for GPIOs 13, 19, 41, 45 or 53 20 | 21 | class LED: 22 | def __init__(self): 23 | self.LED_COUNT = 16 # Number of LED pixels. 24 | self.LED_PIN = 12 # GPIO pin connected to the pixels (18 uses PWM!). 25 | self.LED_FREQ_HZ = 800000 # LED signal frequency in hertz (usually 800khz) 26 | self.LED_DMA = 10 # DMA channel to use for generating signal (try 10) 27 | self.LED_BRIGHTNESS = 255 # Set to 0 for darkest and 255 for brightest 28 | self.LED_INVERT = False # True to invert the signal (when using NPN transistor level shift) 29 | self.LED_CHANNEL = 0 # set to '1' for GPIOs 13, 19, 41, 45 or 53 30 | parser = argparse.ArgumentParser() 31 | parser.add_argument('-c', '--clear', action='store_true', help='clear the display on exit') 32 | args = parser.parse_args() 33 | 34 | # Create NeoPixel object with appropriate configuration. 35 | self.strip = Adafruit_NeoPixel(self.LED_COUNT, self.LED_PIN, self.LED_FREQ_HZ, self.LED_DMA, self.LED_INVERT, self.LED_BRIGHTNESS, self.LED_CHANNEL) 36 | # Intialize the library (must be called once before other functions). 37 | self.strip.begin() 38 | 39 | # Define functions which animate LEDs in various ways. 40 | def colorWipe(self, R, G, B): 41 | """Wipe color across display a pixel at a time.""" 42 | color = Color(R,G,B) 43 | for i in range(self.strip.numPixels()): 44 | self.strip.setPixelColor(i, color) 45 | self.strip.show() 46 | 47 | if __name__ == '__main__': 48 | led = LED() 49 | led.colorWipe(0,0,255) -------------------------------------------------------------------------------- /server/app.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | from importlib import import_module 3 | import os 4 | from flask import Flask, render_template, Response, send_from_directory 5 | from flask_cors import * 6 | # import camera driver 7 | 8 | from camera_opencv import Camera 9 | import threading 10 | 11 | # Raspberry Pi camera module (requires picamera package) 12 | # from camera_pi import Camera 13 | 14 | app = Flask(__name__) 15 | CORS(app, supports_credentials=True) 16 | camera = Camera() 17 | 18 | def gen(camera): 19 | """Video streaming generator function.""" 20 | while True: 21 | frame = camera.get_frame() 22 | yield (b'--frame\r\n' 23 | b'Content-Type: image/jpeg\r\n\r\n' + frame + b'\r\n') 24 | 25 | @app.route('/video_feed') 26 | def video_feed(): 27 | """Video streaming route. Put this in the src attribute of an img tag.""" 28 | return Response(gen(camera), 29 | mimetype='multipart/x-mixed-replace; boundary=frame') 30 | 31 | dir_path = os.path.dirname(os.path.realpath(__file__)) 32 | 33 | @app.route('/api/img/') 34 | def sendimg(filename): 35 | return send_from_directory(dir_path+'/dist/img', filename) 36 | 37 | @app.route('/js/') 38 | def sendjs(filename): 39 | return send_from_directory(dir_path+'/dist/js', filename) 40 | 41 | @app.route('/css/') 42 | def sendcss(filename): 43 | return send_from_directory(dir_path+'/dist/css', filename) 44 | 45 | @app.route('/api/img/icon/') 46 | def sendicon(filename): 47 | return send_from_directory(dir_path+'/dist/img/icon', filename) 48 | 49 | @app.route('/fonts/') 50 | def sendfonts(filename): 51 | return send_from_directory(dir_path+'/dist/fonts', filename) 52 | 53 | @app.route('/') 54 | def sendgen(filename): 55 | return send_from_directory(dir_path+'/dist', filename) 56 | 57 | @app.route('/') 58 | def index(): 59 | return send_from_directory(dir_path+'/dist', 'index.html') 60 | 61 | class webapp: 62 | def __init__(self): 63 | self.camera = camera 64 | 65 | def modeselect(self, modeInput): 66 | Camera.modeSelect = modeInput 67 | 68 | def colorFindSet(self, H, S, V): 69 | camera.colorFindSet(H, S, V) 70 | 71 | def thread(self): 72 | app.run(host='0.0.0.0', threaded=True) 73 | 74 | def startthread(self): 75 | fps_threading=threading.Thread(target=self.thread) #Define a thread for FPV and OpenCV 76 | fps_threading.setDaemon(False) #'True' means it is a front thread,it would close when the mainloop() closes 77 | fps_threading.start() #Thread starts 78 | 79 | 80 | -------------------------------------------------------------------------------- /autorun.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | # File name : motor.py 3 | # Description : Control Motors 4 | # Website : www.adeept.com 5 | # E-mail : support@adeept.com 6 | # Author : William 7 | # Date : 2018/10/12 8 | 9 | import os 10 | import sys 11 | 12 | def search(path,name): 13 | for root, dirs, files in os.walk(path): 14 | if name in dirs or name in files: 15 | flag = 1 16 | root = str(root) 17 | dirs = str(dirs) 18 | return os.path.join(root, dirs) 19 | return -1 20 | 21 | def replace_num(file,initial,new_num): 22 | newline="" 23 | str_num=str(new_num) 24 | with open(file,"r") as f: 25 | for line in f.readlines(): 26 | if(line.find(initial) == 0): 27 | line = (str_num+'\n') 28 | newline += line 29 | with open(file,"w") as f: 30 | f.writelines(newline) 31 | 32 | path_get = str(search('//home/pi/','server.py')) 33 | path_get=path_get[:-15] 34 | 35 | if path_get != -1: 36 | while 1: 37 | command_select = input('Do you want to autostart the sound version or the Test version(without OpenCV)?\nInput "1" to select sound version.\nInput "2" to select Test version(without OpenCV).') 38 | if command_select == '1' or command_select == '2': 39 | break 40 | else: 41 | continue 42 | else: 43 | print('Cannot find the programe for this robot, you need to setup the programe first.') 44 | 45 | 46 | if command_select == '1': 47 | try: 48 | try: 49 | os.system('sudo rm -rf //home/pi/.config/autostart') 50 | except: 51 | pass 52 | os.system('sudo mkdir //home/pi/.config/autostart') 53 | os.system('sudo touch //home/pi/.config/autostart/car.desktop') 54 | with open("//home/pi/.config/autostart/car.desktop",'w') as file_to_write: 55 | file_to_write.write("[Desktop Entry]\n Name=Car\n Comment=Car\n Exec=sudo python3 %sserver.py\n Icon=false\n Terminal=false\n MutipleArgs=false\n Type=Application\n Catagories=Application;Development;\n StartupNotify=true"%path_get) 56 | print('The sound version will start when boot') 57 | except: 58 | pass 59 | elif command_select == '2': 60 | try: 61 | try: 62 | os.system('sudo rm -rf //home/pi/.config/autostart') 63 | except: 64 | pass 65 | os.system('sudo mkdir //home/pi/.config/autostart') 66 | os.system('sudo touch //home/pi/.config/autostart/car.desktop') 67 | with open("//home/pi/.config/autostart/car.desktop",'w') as file_to_write: 68 | file_to_write.write("[Desktop Entry]\n Name=Car\n Comment=Car\n Exec=sudo python3 %sserverTest.py\n Icon=false\n Terminal=false\n MutipleArgs=false\n Type=Application\n Catagories=Application;Development;\n StartupNotify=true"%path_get) 69 | print('The Test version(without OpenCV) will start when boot') 70 | except: 71 | pass 72 | 73 | #path_get=str(path_get) 74 | #print(path_get[:-15]) -------------------------------------------------------------------------------- /server/OLED.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env/python3 2 | # File name : server.py 3 | # Description : for OLED functions 4 | # Website : www.gewbot.com 5 | # Author : William(Based on Adrian Rosebrock's OpenCV code on pyimagesearch.com) 6 | # Date : 2019/08/28 7 | 8 | from luma.core.interface.serial import i2c 9 | from luma.core.render import canvas 10 | from luma.oled.device import ssd1306, ssd1325, ssd1331, sh1106 11 | import time 12 | import threading 13 | 14 | try: 15 | serial = i2c(port=1, address=0x3C) 16 | device = ssd1306(serial, rotate=0) 17 | except: 18 | print('OLED disconnected\nOLED没有连接') 19 | 20 | # Box and text rendered in portrait mode 21 | # with canvas(device) as draw: 22 | # draw.text((0, 0), "WWW.CODELECTRON.COM", fill="white") 23 | # draw.text((0, 10), "WWW.CODELECTRON.COM", fill="white") 24 | # draw.text((0, 20), "WWW.CODELECTRON.COM", fill="white") 25 | # draw.text((0, 30), "WWW.CODELECTRON.COM", fill="white") 26 | # draw.text((0, 40), "WWW.CODELECTRON.COM", fill="white") 27 | # draw.text((0, 50), "WWW.CODELECTRON.COM", fill="white") 28 | # while 1: 29 | # time.sleep(1) 30 | 31 | text_1 = 'GEWBOT.COM' 32 | text_2 = 'IP:CONNECTING' 33 | text_3 = ' OR MODE' 34 | text_4 = 'MPU6050 DETECTING' 35 | text_5 = 'FUNCTION OFF' 36 | text_6 = 'Message:None' 37 | 38 | class OLED_ctrl(threading.Thread): 39 | def __init__(self, *args, **kwargs): 40 | super(OLED_ctrl, self).__init__(*args, **kwargs) 41 | self.__flag = threading.Event() # 用于暂停线程的标识 42 | self.__flag.set() # 设置为True 43 | self.__running = threading.Event() # 用于停止线程的标识 44 | self.__running.set() # 将running设置为True 45 | 46 | def run(self): 47 | while self.__running.isSet(): 48 | self.__flag.wait() # 为True时立即返回, 为False时阻塞直到内部的标识位为True后返回 49 | with canvas(device) as draw: 50 | draw.text((0, 0), text_1, fill="white") 51 | draw.text((0, 10), text_2, fill="white") 52 | draw.text((0, 20), text_3, fill="white") 53 | draw.text((0, 30), text_4, fill="white") 54 | draw.text((0, 40), text_5, fill="white") 55 | draw.text((0, 50), text_6, fill="white") 56 | print('loop') 57 | self.pause() 58 | 59 | def pause(self): 60 | self.__flag.clear() # 设置为False, 让线程阻塞 61 | 62 | def resume(self): 63 | self.__flag.set() # 设置为True, 让线程停止阻塞 64 | 65 | def stop(self): 66 | self.__flag.set() # 将线程从暂停状态恢复, 如何已经暂停的话 67 | self.__running.clear() # 设置为False 68 | 69 | def screen_show(self, position, text): 70 | global text_1, text_2, text_3, text_4, text_5, text_6 71 | if position == 1: 72 | text_1 = text 73 | elif position == 2: 74 | text_2 = text 75 | elif position == 3: 76 | text_3 = text 77 | elif position == 4: 78 | text_4 = text 79 | elif position == 5: 80 | text_5 = text 81 | elif position == 6: 82 | text_6 = text 83 | self.resume() 84 | 85 | if __name__ == '__main__': 86 | screen = OLED_ctrl() 87 | screen.start() 88 | screen.screen_show(1, 'GEWBOT.COM') 89 | while 1: 90 | time.sleep(10) 91 | pass -------------------------------------------------------------------------------- /server/Instruction.txt: -------------------------------------------------------------------------------- 1 | First of all, thank you for purchasing Adeept's product. 2 | 3 | The .py program in the folder client is the program required on the PC. 4 | The .py program in the folder server is the program required on the robot. 5 | 6 | This instruction focuses on the programs in the folder server. When you encounter problems, you can refer to this description to solve the problem. 7 | 8 | 9 | 1.What should I do if the robot does not automatically run the program when I turn it on? 10 | First cause: the program is not installed completely, probably because the server connection of the dependent libraries needed is unstable, resulting in incomplete download of the dependent libraries.The full version of the program needs to install the appropriate dependencies to run properly. 11 | Second cause: Linux is case sensitive.The case sensitvity of the name when you clone from Github is different from the one of the autostart file of the default path. 12 | 13 | Solution: try the beta program - a program named serverTest.py in the folder server. 14 | If you need the beta program to run automatically every time you boot, execute autorun.py - enter "2" to select the autorun beta - enter. 15 | If you need to change to the full version of the autorun program every time you boot, execute autorun.py - enter "1" to select the full version of autorun - enter. 16 | 17 | 18 | 2.What should I do if the servo is moving in the opposite direction? 19 | Cause: the servos were produced in different batches, the moving direction of them may be different. 20 | 21 | Solution: We have reserved an interface for adjusting the direction of the servo in the program, which makes it much more easier to debug. 22 | All motion-related code is written in the program server/move.py. 23 | Enter the following command to open (note that it is not to execute) move.py and edit: 24 | sudo nano (path)/move.py 25 | (The path varies depending on the product you bought. Take RaspTank as an example. The path of move.py is //home/pi/adeept_rasptank/server/move.py) 26 | After opening move.py, change the value of set_direction to 0 (the default is 1), then press ctrl+x to exit, press Y to save change, and press Enter to confirm. 27 | 28 | 29 | 3. What should I do if the it fails to realize good self-stabilization? 30 | Cause: The IPD controler is used for self-stabilization. You need to input the appropriate PID parameters to achieve perfect stabilization. The PID parameters of each robot are different. 31 | 32 | Solution: If the reaction is slow, you can increase the P value appropriately (the line75 of move.py). If the reaction is too fast (or swing back and forth), you can reduce the P value appropriately. 33 | If the reaction speed is normal but there is overshoot, you need to increase the I value appropriately. 34 | The D value is differential and usually does not need to be changed for this product. 35 | 36 | The fun of creation lies in solving problems 37 | If you have any other questions, please e-mail us at support@adeept.com -------------------------------------------------------------------------------- /server/LED.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | # File name : LED.py 3 | # Description : WS_2812 4 | # Website : based on the code from https://github.com/rpi-ws281x/rpi-ws281x-python/blob/master/examples/strandtest.py 5 | # Author : original code by Tony DiCola (tony@tonydicola.com) 6 | # Date : 2019/02/23 7 | import time 8 | from rpi_ws281x import * 9 | import argparse 10 | 11 | # LED strip configuration: 12 | LED_COUNT = 12 # Number of LED pixels. 13 | LED_PIN = 12 # GPIO pin connected to the pixels (18 uses PWM!). 14 | #LED_PIN = 10 # GPIO pin connected to the pixels (10 uses SPI /dev/spidev0.0). 15 | LED_FREQ_HZ = 800000 # LED signal frequency in hertz (usually 800khz) 16 | LED_DMA = 10 # DMA channel to use for generating signal (try 10) 17 | LED_BRIGHTNESS = 255 # Set to 0 for darkest and 255 for brightest 18 | LED_INVERT = False # True to invert the signal (when using NPN transistor level shift) 19 | LED_CHANNEL = 0 # set to '1' for GPIOs 13, 19, 41, 45 or 53 20 | 21 | class LED: 22 | def __init__(self): 23 | self.LED_COUNT = 16 # Number of LED pixels. 24 | self.LED_PIN = 12 # GPIO pin connected to the pixels (18 uses PWM!). 25 | self.LED_FREQ_HZ = 800000 # LED signal frequency in hertz (usually 800khz) 26 | self.LED_DMA = 10 # DMA channel to use for generating signal (try 10) 27 | self.LED_BRIGHTNESS = 255 # Set to 0 for darkest and 255 for brightest 28 | self.LED_INVERT = False # True to invert the signal (when using NPN transistor level shift) 29 | self.LED_CHANNEL = 0 # set to '1' for GPIOs 13, 19, 41, 45 or 53 30 | parser = argparse.ArgumentParser() 31 | parser.add_argument('-c', '--clear', action='store_true', help='clear the display on exit') 32 | args = parser.parse_args() 33 | 34 | # Create NeoPixel object with appropriate configuration. 35 | self.strip = Adafruit_NeoPixel(self.LED_COUNT, self.LED_PIN, self.LED_FREQ_HZ, self.LED_DMA, self.LED_INVERT, self.LED_BRIGHTNESS, self.LED_CHANNEL) 36 | # Intialize the library (must be called once before other functions). 37 | self.strip.begin() 38 | 39 | # Define functions which animate LEDs in various ways. 40 | # def colorWipe(self, R, G, B): 41 | # def colorWipe(self, color, wait_ms=0): 42 | # """Wipe color across display a pixel at a time.""" 43 | # for i in range(self.strip.numPixels()): 44 | # self.strip.setPixelColor(i, color) 45 | # self.strip.show() 46 | # time.sleep(wait_ms / 1000.0) 47 | 48 | def colorWipe(self, R, G, B): 49 | color = Color(R,G,B) 50 | for i in range(self.strip.numPixels()): 51 | self.strip.setPixelColor(i, color) 52 | self.strip.show() 53 | 54 | if __name__ == '__main__': 55 | led = LED() 56 | try: 57 | while True: 58 | led.colorWipe(255, 0, 0) # red 59 | time.sleep(1) 60 | led.colorWipe(0, 255, 0) # green 61 | time.sleep(1) 62 | led.colorWipe(0, 0, 255) # blue 63 | time.sleep(1) 64 | except: 65 | led.colorWipe(0,0,0) # Lights out 66 | -------------------------------------------------------------------------------- /server/config.txt: -------------------------------------------------------------------------------- 1 | #L0 2 | L0_MAX:450 3 | L0_MIN:225 4 | L0_ST1:373 5 | L0_ST2:368 6 | L0_ST3:368 7 | L0_ST4:373 8 | L0_ST5:307 9 | L0_ST6:263 10 | L0_ST7:200 11 | L0_ST8:475 12 | L0_ST9:217 13 | L0_ST10:504 14 | #L1 15 | L1_MAX:500 16 | L1_MIN:100 17 | L1_ST1:158 18 | L1_ST2:200 19 | L1_ST3:250 20 | L1_ST4:325 21 | L1_ST5:523 22 | L1_ST6:321 23 | L1_ST7:360 24 | L1_ST8:360 25 | L1_ST9:360 26 | L1_ST10:360 27 | #L2 28 | L2_MAX:500 29 | L2_MIN:156 30 | L2_ST1:100 31 | L2_ST2:500 32 | L2_ST3:300 33 | L2_ST4:110 34 | L2_ST5:420 35 | L2_ST6:303 36 | L2_ST7:360 37 | L2_ST8:430 38 | L2_ST9:360 39 | L2_ST10:360 40 | #L3 41 | L3_MAX:500 42 | L3_MIN:280 43 | L3_ST1:285 44 | L3_ST2:367 45 | L3_ST3:367 46 | L3_ST4:285 47 | L3_ST5:350 48 | L3_ST6:414 49 | L3_ST7:360 50 | L3_ST8:360 51 | L3_ST9:360 52 | L3_ST10:360 53 | #L4 54 | L4_MAX:489 55 | L4_MIN:130 56 | L4_ST1:500 57 | L4_ST2:280 58 | L4_ST3:280 59 | L4_ST4:338 60 | L4_ST5:590 61 | L4_ST6:363 62 | L4_ST7:360 63 | L4_ST8:360 64 | L4_ST9:360 65 | L4_ST10:360 66 | #L5 67 | L5_MAX:500 68 | L5_MIN:120 69 | L5_ST1:104 70 | L5_ST2:121 71 | L5_ST3:300 72 | L5_ST4:500 73 | L5_ST5:165 74 | L5_ST6:300 75 | L5_ST7:360 76 | L5_ST8:360 77 | L5_ST9:360 78 | L5_ST10:360 79 | #L6 80 | L6_MAX:453 81 | L6_MIN:270 82 | L6_ST1:339 83 | L6_ST2:320 84 | L6_ST3:320 85 | L6_ST4:340 86 | L6_ST5:350 87 | L6_ST6:360 88 | L6_ST7:360 89 | L6_ST8:360 90 | L6_ST9:360 91 | L6_ST10:360 92 | #L7 93 | L7_MAX:500 94 | L7_MIN:123 95 | L7_ST1:193 96 | L7_ST2:314 97 | L7_ST3:340 98 | L7_ST4:340 99 | L7_ST5:350 100 | L7_ST6:360 101 | L7_ST7:360 102 | L7_ST8:360 103 | L7_ST9:360 104 | L7_ST10:360 105 | #L8 106 | L8_MAX:500 107 | L8_MIN:120 108 | L8_ST1:485 109 | L8_ST2:497 110 | L8_ST3:300 111 | L8_ST4:108 112 | L8_ST5:350 113 | L8_ST6:360 114 | L8_ST7:360 115 | L8_ST8:360 116 | L8_ST9:360 117 | L8_ST10:360 118 | #L9 119 | L9_MAX:380 120 | L9_MIN:174 121 | L9_ST1:342 122 | L9_ST2:320 123 | L9_ST3:320 124 | L9_ST4:343 125 | L9_ST5:350 126 | L9_ST6:360 127 | L9_ST7:360 128 | L9_ST8:360 129 | L9_ST9:360 130 | L9_ST10:360 131 | #L10 132 | L10_MAX:501 133 | L10_MIN:136 134 | L10_ST1:486 135 | L10_ST2:350 136 | L10_ST3:307 137 | L10_ST4:379 138 | L10_ST5:350 139 | L10_ST6:360 140 | L10_ST7:360 141 | L10_ST8:360 142 | L10_ST9:360 143 | L10_ST10:360 144 | #L11 145 | L11_MAX:300 146 | L11_MIN:201 147 | L11_ST1:138 148 | L11_ST2:115 149 | L11_ST3:300 150 | L11_ST4:493 151 | L11_ST5:350 152 | L11_ST6:360 153 | L11_ST7:360 154 | L11_ST8:360 155 | L11_ST9:360 156 | L11_ST10:360 157 | #L12 158 | L12_MAX:430 159 | L12_MIN:300 160 | L12_ST1:430 161 | L12_ST2:131 162 | L12_ST3:298 163 | L12_ST4:120 164 | L12_ST5:350 165 | L12_ST6:360 166 | L12_ST7:360 167 | L12_ST8:360 168 | L12_ST9:360 169 | L12_ST10:360 170 | #L13 171 | L13_MAX:443 172 | L13_MIN:139 173 | L13_ST1:429 174 | L13_ST2:227 175 | L13_ST3:298 176 | L13_ST4:340 177 | L13_ST5:350 178 | L13_ST6:360 179 | L13_ST7:360 180 | L13_ST8:360 181 | L13_ST9:360 182 | L13_ST10:360 183 | #L14 184 | L14_MAX:500 185 | L14_MIN:300 186 | L14_ST1:316 187 | L14_ST2:108 188 | L14_ST3:487 189 | L14_ST4:340 190 | L14_ST5:350 191 | L14_ST6:360 192 | L14_ST7:360 193 | L14_ST8:360 194 | L14_ST9:360 195 | L14_ST10:360 196 | #L15 197 | L15_MAX:500 198 | L15_MIN:300 199 | L15_ST1:339 200 | L15_ST2:194 201 | L15_ST3:330 202 | L15_ST4:340 203 | L15_ST5:350 204 | L15_ST6:360 205 | L15_ST7:360 206 | L15_ST8:360 207 | L15_ST9:360 208 | L15_ST10:360 -------------------------------------------------------------------------------- /wifi_hotspot_manager.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Configuration parameters - modify these values according to your needs 4 | SYSTEM_WIFI_CONN="preconfigured" # Default connection name for Bookworm system 5 | HOTSPOT_SSID="Adeept_Robot" 6 | HOTSPOT_PASSWORD="12345678" # At least 8 characters 7 | HOTSPOT_INTERFACE="wlan0" 8 | WIFI_AP_GATEWAY="192.168.4.1" 9 | 10 | # Wait for network service to be ready 11 | echo "Waiting for network service to start..." 12 | while ! nmcli general status > /dev/null 2>&1; do 13 | sleep 1 14 | done 15 | 16 | # Check WiFi connection status (for preconfigured connection) 17 | check_wifi_connection() { 18 | # Check if preconfigured connection is active 19 | nmcli connection show --active | grep -q "$SYSTEM_WIFI_CONN" 20 | return $? 21 | } 22 | 23 | # Get SSID of system preconfigured connection 24 | get_preconfigured_ssid() { 25 | nmcli connection show "$SYSTEM_WIFI_CONN" | grep "ssid" | awk '{print $2}' 26 | } 27 | 28 | # Connect to system preconfigured WiFi 29 | connect_wifi() { 30 | local ssid=$(get_preconfigured_ssid) 31 | echo "Attempting to connect to system preconfigured WiFi: $ssid (connection name: $SYSTEM_WIFI_CONN)" 32 | 33 | # Check if connection exists 34 | if ! nmcli connection show | grep -q "$SYSTEM_WIFI_CONN"; then 35 | echo "Error: System preconfigured connection $SYSTEM_WIFI_CONN does not exist" 36 | return 1 37 | fi 38 | 39 | # Attempt connection 40 | nmcli connection up "$SYSTEM_WIFI_CONN" ifname "$HOTSPOT_INTERFACE" 41 | 42 | # Wait for connection to complete 43 | sleep 10 44 | 45 | # Check if connection was successful 46 | if check_wifi_connection; then 47 | echo "System preconfigured WiFi connected successfully" 48 | return 0 49 | else 50 | echo "Failed to connect to system preconfigured WiFi" 51 | return 1 52 | fi 53 | } 54 | 55 | # Start hotspot 56 | start_hotspot() { 57 | echo "Starting hotspot: $HOTSPOT_SSID" 58 | 59 | # First shut down any existing hotspot connection 60 | if nmcli connection show | grep -q "$HOTSPOT_SSID"; then 61 | nmcli connection down "$HOTSPOT_SSID" 62 | fi 63 | 64 | # Create or modify hotspot configuration 65 | if ! nmcli connection show | grep -q "$HOTSPOT_SSID"; then 66 | nmcli connection add type wifi con-name "$HOTSPOT_SSID" ifname "$HOTSPOT_INTERFACE" ssid "$HOTSPOT_SSID" 67 | fi 68 | 69 | # Configure hotspot parameters 70 | nmcli connection modify "$HOTSPOT_SSID" connection.autoconnect no 71 | nmcli connection modify "$HOTSPOT_SSID" wifi.mode ap 72 | nmcli connection modify "$HOTSPOT_SSID" wifi-sec.key-mgmt wpa-psk 73 | nmcli connection modify "$HOTSPOT_SSID" wifi-sec.psk "$HOTSPOT_PASSWORD" 74 | nmcli connection modify "$HOTSPOT_SSID" ipv4.addresses "$WIFI_AP_GATEWAY/24" 75 | nmcli connection modify "$HOTSPOT_SSID" ipv4.method shared 76 | nmcli connection modify "$HOTSPOT_SSID" ipv6.method ignore 77 | 78 | # Start the hotspot 79 | nmcli connection up "$HOTSPOT_SSID" ifname "$HOTSPOT_INTERFACE" 80 | 81 | echo "Hotspot started successfully" 82 | } 83 | 84 | # Main logic 85 | main() { 86 | # First disconnect all possible connections 87 | nmcli connection down id "$SYSTEM_WIFI_CONN" > /dev/null 2>&1 88 | nmcli connection down id "$HOTSPOT_SSID" > /dev/null 2>&1 89 | 90 | # Attempt to connect to system preconfigured WiFi 91 | if connect_wifi; then 92 | exit 0 93 | fi 94 | 95 | # If WiFi connection fails, start hotspot 96 | start_hotspot 97 | } 98 | 99 | # Execute main logic 100 | main 101 | -------------------------------------------------------------------------------- /instruction.txt: -------------------------------------------------------------------------------- 1 | First of all, the program should be done in the SD card, including writing the Raspberry Pi system, 2 | downloading and installing the Rasptank program. 3 | 4 | Pay attention to the case sensitivity during process of git clone . The specific operation process 5 | is in the document and manual. It will automatically start up at boot after the program is successfully installed. 6 | 7 | You need to connect the driver board and the Raspberry Pi, and before turn it on, connect the servo with the driver board. 8 | Wait until the servo rotates to specified position to assemble. 9 | 10 | The servo is 20 teeth and will have an error of less than 9° during the installation process, which is normal. 11 | 12 | --------------------------------------------------------------------------------------------------------------------------- 13 | 14 | The .py program in the folder client is the program required on the PC. 15 | The .py program in the folder server is the program required on the robot. 16 | 17 | This instruction focuses on the programs in the folder server. When you encounter problems, you can refer to this description to solve the problem. 18 | 19 | 20 | 1.What should I do if the robot does not automatically run the program when I turn it on? 21 | First cause: the program is not installed completely, probably because the server connection of the dependent libraries needed is unstable, resulting in incomplete download of the dependent libraries.The full version of the program needs to install the appropriate dependencies to run properly. 22 | Second cause: Linux is case sensitive.The case sensitvity of the name when you clone from Github is different from the one of the autostart file of the default path. 23 | 24 | Solution: try the beta program - a program named serverTest.py in the folder server. 25 | If you need the beta program to run automatically every time you boot, execute autorun.py - enter "2" to select the autorun beta - enter. 26 | If you need to change to the full version of the autorun program every time you boot, execute autorun.py - enter "1" to select the full version of autorun - enter. 27 | 28 | 29 | 2.What should I do if the servo is moving in the opposite direction? 30 | Cause: the servos were produced in different batches, the moving direction of them may be different. 31 | 32 | Solution: We have reserved an interface for adjusting the direction of the servo in the program, which makes it much more easier to debug. 33 | All motion-related code is written in the program server/move.py. 34 | Enter the following command to open (note that it is not to execute) move.py and edit: 35 | sudo nano (path)/move.py 36 | (The path varies depending on the product you bought. Take RaspClaws as an example. The path of move.py is //home/pi/adeept_raspclaws/server/move.py) 37 | After opening move.py, change the value of Set_Direction to 0 (the default is 1), then press ctrl+x to exit, press Y to save change, and press Enter to confirm. 38 | 39 | 40 | 3. What should I do if the it fails to realize good self-stabilization? 41 | Cause: The IPD controler is used for self-stabilization. You need to input the appropriate PID parameters to achieve perfect stabilization. The PID parameters of each robot are different. 42 | 43 | Solution: If the reaction is slow, you can increase the P value appropriately (the line75 of move.py). If the reaction is too fast (or swing back and forth), you can reduce the P value appropriately. 44 | If the reaction speed is normal but there is overshoot, you need to increase the I value appropriately. 45 | The D value is differential and usually does not need to be changed for this product. 46 | 47 | The fun of creation lies in solving problems 48 | If you have any other questions, please e-mail us at support@adeept.com 49 | -------------------------------------------------------------------------------- /server/base_camera.py: -------------------------------------------------------------------------------- 1 | import time 2 | import threading 3 | import cv2 4 | try: 5 | from greenlet import getcurrent as get_ident 6 | except ImportError: 7 | try: 8 | from thread import get_ident 9 | except ImportError: 10 | from _thread import get_ident 11 | 12 | 13 | class CameraEvent(object): 14 | """An Event-like class that signals all active clients when a new frame is 15 | available. 16 | """ 17 | def __init__(self): 18 | self.events = {} 19 | 20 | def wait(self): 21 | """Invoked from each client's thread to wait for the next frame.""" 22 | ident = get_ident() 23 | if ident not in self.events: 24 | # this is a new client 25 | # add an entry for it in the self.events dict 26 | # each entry has two elements, a threading.Event() and a timestamp 27 | self.events[ident] = [threading.Event(), time.time()] 28 | return self.events[ident][0].wait() 29 | 30 | def set(self): 31 | """Invoked by the camera thread when a new frame is available.""" 32 | now = time.time() 33 | remove = None 34 | for ident, event in self.events.items(): 35 | if not event[0].isSet(): 36 | # if this client's event is not set, then set it 37 | # also update the last set timestamp to now 38 | event[0].set() 39 | event[1] = now 40 | else: 41 | # if the client's event is already set, it means the client 42 | # did not process a previous frame 43 | # if the event stays set for more than 5 seconds, then assume 44 | # the client is gone and remove it 45 | if now - event[1] > 5: 46 | remove = ident 47 | if remove: 48 | del self.events[remove] 49 | 50 | def clear(self): 51 | """Invoked from each client's thread after a frame was processed.""" 52 | self.events[get_ident()][0].clear() 53 | 54 | 55 | class BaseCamera(object): 56 | thread = None # background thread that reads frames from camera 57 | frame = None # current frame is stored here by background thread 58 | last_access = 0 # time of last client access to the camera 59 | event = CameraEvent() 60 | 61 | def __init__(self): 62 | """Start the background camera thread if it isn't running yet.""" 63 | if BaseCamera.thread is None: 64 | BaseCamera.last_access = time.time() 65 | 66 | # start background frame thread 67 | BaseCamera.thread = threading.Thread(target=self._thread) 68 | BaseCamera.thread.start() 69 | 70 | # wait until frames are available 71 | while self.get_frame() is None: 72 | time.sleep(0) 73 | 74 | def get_frame(self): 75 | """Return the current camera frame.""" 76 | BaseCamera.last_access = time.time() 77 | 78 | # wait for a signal from the camera thread 79 | BaseCamera.event.wait() 80 | BaseCamera.event.clear() 81 | 82 | return BaseCamera.frame 83 | 84 | @staticmethod 85 | def frames(): 86 | """"Generator that returns frames from the camera.""" 87 | raise RuntimeError('Must be implemented by subclasses.') 88 | 89 | @classmethod 90 | def _thread(cls): 91 | """Camera background thread.""" 92 | print('Starting camera thread.') 93 | frames_iterator = cls.frames() 94 | for frame in frames_iterator: 95 | BaseCamera.frame = frame 96 | BaseCamera.event.set() # send signal to clients 97 | time.sleep(0) 98 | 99 | # if there hasn't been any clients asking for frames in 100 | # the last 10 seconds then stop the thread 101 | # if time.time() - BaseCamera.last_access > 10: 102 | # frames_iterator.close() 103 | # print('Stopping camera thread due to inactivity.') 104 | # break 105 | BaseCamera.thread = None 106 | -------------------------------------------------------------------------------- /server/move.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # File name : move.py 3 | # Description : Control Motor 4 | # Product : GWR 5 | # Website : www.gewbot.com 6 | # Author : William 7 | # Date : 2019/07/24 8 | import time 9 | from board import SCL, SDA 10 | import busio 11 | from adafruit_pca9685 import PCA9685 12 | from adafruit_motor import motor 13 | 14 | # motor_EN_A: Pin7 | motor_EN_B: Pin11 15 | # motor_A: Pin8,Pin10 | motor_B: Pin13,Pin12 16 | 17 | MOTOR_M1_IN1 = 15 #Define the positive pole of M1 18 | MOTOR_M1_IN2 = 14 #Define the negative pole of M1 19 | MOTOR_M2_IN1 = 12 #Define the positive pole of M2 20 | MOTOR_M2_IN2 = 13 #Define the negative pole of M2 21 | 22 | Dir_forward = 0 23 | Dir_backward = 1 24 | 25 | left_forward = 0 26 | left_backward = 1 27 | 28 | right_forward = 0 29 | right_backward= 1 30 | 31 | pwn_A = 0 32 | pwm_B = 0 33 | FREQ = 50 34 | 35 | 36 | 37 | def map(x,in_min,in_max,out_min,out_max): 38 | return (x - in_min)/(in_max - in_min) *(out_max - out_min) +out_min 39 | 40 | def setup():#Motor initialization 41 | global motor1,motor2,motor3,motor4,pwm_motor,pwm_motor 42 | i2c = busio.I2C(SCL, SDA) 43 | pwm_motor = PCA9685(i2c, address=0x40) #default 0x40 44 | 45 | pwm_motor.frequency = FREQ 46 | 47 | motor1 = motor.DCMotor(pwm_motor.channels[MOTOR_M1_IN1],pwm_motor.channels[MOTOR_M1_IN2] ) 48 | motor1.decay_mode = (motor.SLOW_DECAY) 49 | motor2 = motor.DCMotor(pwm_motor.channels[MOTOR_M2_IN1],pwm_motor.channels[MOTOR_M2_IN2] ) 50 | motor2.decay_mode = (motor.SLOW_DECAY) 51 | 52 | 53 | 54 | def motorStop():#Motor stops 55 | global motor1,motor2 56 | motor1.throttle = 0 57 | motor2.throttle = 0 58 | 59 | 60 | def Motor(channel,direction,motor_speed): 61 | # channel,1~4:M1~M4 62 | if motor_speed > 100: 63 | motor_speed = 100 64 | elif motor_speed < 0: 65 | motor_speed = 0 66 | 67 | speed = map(motor_speed, 0, 100, 0, 1.0) 68 | 69 | pwm_motor.frequency = FREQ 70 | # Prevent the servo from affecting the frequency of the motor 71 | if direction == 1: 72 | speed = -speed 73 | if channel == 1: 74 | motor1.throttle = speed 75 | elif channel == 2: 76 | motor2.throttle = speed 77 | 78 | 79 | 80 | 81 | def motor_left(status, direction, speed):#Motor 2 positive and negative rotation 82 | if status == 0: # stop 83 | motorStop() 84 | else: 85 | if direction == Dir_backward: 86 | Motor(1, Dir_forward, speed) 87 | Motor(2, Dir_backward, speed) 88 | elif direction == Dir_forward: 89 | Motor(1, Dir_backward, speed) 90 | Motor(2, Dir_forward, speed) 91 | 92 | def motor_right(status, direction, speed):#Motor 1 positive and negative rotation 93 | if status == 0: # stop 94 | motorStop() 95 | else: 96 | if direction == Dir_backward: 97 | Motor(1, Dir_backward, speed) 98 | Motor(2, Dir_forward, speed) 99 | elif direction == Dir_forward: 100 | Motor(1, Dir_forward, speed) 101 | Motor(2, Dir_backward, speed) 102 | 103 | 104 | def move(speed, direction, turn, radius=0.6): # 0 < radius <= 1 105 | #speed = 100 106 | if direction == 'forward': 107 | if turn == 'right': 108 | motor_left(0, left_forward, int(speed*radius)) 109 | motor_right(1, right_backward, speed) 110 | elif turn == 'left': 111 | motor_left(1, left_backward, speed) 112 | motor_right(0, right_forward, int(speed*radius)) 113 | else: 114 | motor_left(1, left_backward, speed) 115 | motor_right(1, right_backward, speed) 116 | elif direction == 'backward': 117 | if turn == 'right': 118 | motor_left(0, left_backward, int(speed*radius)) 119 | motor_right(1, right_forward, speed) 120 | elif turn == 'left': 121 | motor_left(1, left_forward, speed) 122 | motor_right(0, right_backward, int(speed*radius)) 123 | else: 124 | motor_left(1, left_forward, speed) 125 | motor_right(1, right_forward, speed) 126 | elif direction == 'no': 127 | if turn == 'right': 128 | motor_left(1, left_backward, speed) 129 | motor_right(1, right_forward, speed) 130 | elif turn == 'left': 131 | motor_left(1, left_forward, speed) 132 | motor_right(1, right_backward, speed) 133 | else: 134 | motorStop() 135 | else: 136 | pass 137 | 138 | 139 | 140 | 141 | def destroy(): 142 | motorStop() 143 | pwm_motor.deinit() 144 | 145 | if __name__ == '__main__': 146 | try: 147 | speed_set = 60 148 | setup() 149 | move(speed_set, 'forward', 'no', 0.8) 150 | time.sleep(1.3) 151 | motorStop() 152 | destroy() 153 | except KeyboardInterrupt: 154 | destroy() 155 | 156 | -------------------------------------------------------------------------------- /server/dist/precache-manifest.a14d08d959aeaa21de5cdb2a57fec282.js: -------------------------------------------------------------------------------- 1 | self.__precacheManifest = (self.__precacheManifest || []).concat([ 2 | { 3 | "revision": "953e3d9f8e140d7d21be", 4 | "url": "/css/app.5a950261.css" 5 | }, 6 | { 7 | "revision": "8d733f44c3bf8783b8f7", 8 | "url": "/css/chunk-vendors.a6374dcc.css" 9 | }, 10 | { 11 | "revision": "2d0a0d8f5f173be15a67aa084db94fe6", 12 | "url": "/fonts/materialdesignicons-webfont.2d0a0d8f.eot" 13 | }, 14 | { 15 | "revision": "b4917be25082eb793b5363f2fdb5f282", 16 | "url": "/fonts/materialdesignicons-webfont.b4917be2.woff" 17 | }, 18 | { 19 | "revision": "d0066537ab6a4c6f8285a5aeb3ba5f09", 20 | "url": "/fonts/materialdesignicons-webfont.d0066537.woff2" 21 | }, 22 | { 23 | "revision": "f51112347be6b44f9ef46151a971430d", 24 | "url": "/fonts/materialdesignicons-webfont.f5111234.ttf" 25 | }, 26 | { 27 | "revision": "5cb7edfceb233100075dc9a1e12e8da3", 28 | "url": "/fonts/roboto-latin-100.5cb7edfc.woff" 29 | }, 30 | { 31 | "revision": "7370c3679472e9560965ff48a4399d0b", 32 | "url": "/fonts/roboto-latin-100.7370c367.woff2" 33 | }, 34 | { 35 | "revision": "f8b1df51ba843179fa1cc9b53d58127a", 36 | "url": "/fonts/roboto-latin-100italic.f8b1df51.woff2" 37 | }, 38 | { 39 | "revision": "f9e8e590b4e0f1ff83469bb2a55b8488", 40 | "url": "/fonts/roboto-latin-100italic.f9e8e590.woff" 41 | }, 42 | { 43 | "revision": "b00849e00f4c2331cddd8ffb44a6720b", 44 | "url": "/fonts/roboto-latin-300.b00849e0.woff" 45 | }, 46 | { 47 | "revision": "ef7c6637c68f269a882e73bcb57a7f6a", 48 | "url": "/fonts/roboto-latin-300.ef7c6637.woff2" 49 | }, 50 | { 51 | "revision": "14286f3ba79c6627433572dfa925202e", 52 | "url": "/fonts/roboto-latin-300italic.14286f3b.woff2" 53 | }, 54 | { 55 | "revision": "4df32891a5f2f98a363314f595482e08", 56 | "url": "/fonts/roboto-latin-300italic.4df32891.woff" 57 | }, 58 | { 59 | "revision": "479970ffb74f2117317f9d24d9e317fe", 60 | "url": "/fonts/roboto-latin-400.479970ff.woff2" 61 | }, 62 | { 63 | "revision": "60fa3c0614b8fb2f394fa29944c21540", 64 | "url": "/fonts/roboto-latin-400.60fa3c06.woff" 65 | }, 66 | { 67 | "revision": "51521a2a8da71e50d871ac6fd2187e87", 68 | "url": "/fonts/roboto-latin-400italic.51521a2a.woff2" 69 | }, 70 | { 71 | "revision": "fe65b8335ee19dd944289f9ed3178c78", 72 | "url": "/fonts/roboto-latin-400italic.fe65b833.woff" 73 | }, 74 | { 75 | "revision": "020c97dc8e0463259c2f9df929bb0c69", 76 | "url": "/fonts/roboto-latin-500.020c97dc.woff2" 77 | }, 78 | { 79 | "revision": "87284894879f5b1c229cb49c8ff6decc", 80 | "url": "/fonts/roboto-latin-500.87284894.woff" 81 | }, 82 | { 83 | "revision": "288ad9c6e8b43cf02443a1f499bdf67e", 84 | "url": "/fonts/roboto-latin-500italic.288ad9c6.woff" 85 | }, 86 | { 87 | "revision": "db4a2a231f52e497c0191e8966b0ee58", 88 | "url": "/fonts/roboto-latin-500italic.db4a2a23.woff2" 89 | }, 90 | { 91 | "revision": "2735a3a69b509faf3577afd25bdf552e", 92 | "url": "/fonts/roboto-latin-700.2735a3a6.woff2" 93 | }, 94 | { 95 | "revision": "adcde98f1d584de52060ad7b16373da3", 96 | "url": "/fonts/roboto-latin-700.adcde98f.woff" 97 | }, 98 | { 99 | "revision": "81f57861ed4ac74741f5671e1dff2fd9", 100 | "url": "/fonts/roboto-latin-700italic.81f57861.woff" 101 | }, 102 | { 103 | "revision": "da0e717829e033a69dec97f1e155ae42", 104 | "url": "/fonts/roboto-latin-700italic.da0e7178.woff2" 105 | }, 106 | { 107 | "revision": "9b3766ef4a402ad3fdeef7501a456512", 108 | "url": "/fonts/roboto-latin-900.9b3766ef.woff2" 109 | }, 110 | { 111 | "revision": "bb1e4dc6333675d11ada2e857e7f95d7", 112 | "url": "/fonts/roboto-latin-900.bb1e4dc6.woff" 113 | }, 114 | { 115 | "revision": "28f9151055c950874d2c6803a39b425b", 116 | "url": "/fonts/roboto-latin-900italic.28f91510.woff" 117 | }, 118 | { 119 | "revision": "ebf6d1640ccddb99fb49f73c052c55a8", 120 | "url": "/fonts/roboto-latin-900italic.ebf6d164.woff2" 121 | }, 122 | { 123 | "revision": "2b2cbdd767cfdd25ff1d67efa6c6d44f", 124 | "url": "/img/bg.jpg" 125 | }, 126 | { 127 | "revision": "15e494011ee2dfd636a304a6a4656bfc", 128 | "url": "/index.html" 129 | }, 130 | { 131 | "revision": "953e3d9f8e140d7d21be", 132 | "url": "/js/app.0ea6d772.js" 133 | }, 134 | { 135 | "revision": "8d733f44c3bf8783b8f7", 136 | "url": "/js/chunk-vendors.217ac283.js" 137 | }, 138 | { 139 | "revision": "3a7172e1d88475e22caf9c660a7e700d", 140 | "url": "/manifest.json" 141 | }, 142 | { 143 | "revision": "b6216d61c03e6ce0c9aea6ca7808f7ca", 144 | "url": "/robots.txt" 145 | } 146 | ]); -------------------------------------------------------------------------------- /server/functions.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # File name : servo.py 3 | # Description : Control Functions 4 | # Author : William 5 | # Date : 2020/03/17 6 | import time 7 | from gpiozero import InputDevice 8 | import threading 9 | import Adafruit_PCA9685 10 | import os 11 | import json 12 | import ultra 13 | import Kalman_filter 14 | import move 15 | 16 | move.setup() 17 | 18 | kalman_filter_X = Kalman_filter.Kalman_filter(0.01,0.1) 19 | 20 | pwm = Adafruit_PCA9685.PCA9685(address=0x40, busnum=1) 21 | pwm.set_pwm_freq(50) 22 | 23 | # MPU_connection = 1 24 | # try: 25 | # sensor = mpu6050(0x68) 26 | # print('mpu6050 connected, PT MODE ON') 27 | # except: 28 | # MPU_connection = 0 29 | # print('mpu6050 disconnected, ARM MODE ON') 30 | 31 | curpath = os.path.realpath(__file__) 32 | thisPath = "/" + os.path.dirname(curpath) 33 | 34 | def num_import_int(initial): #Call this function to import data from '.txt' file 35 | global r 36 | with open(thisPath+"/RPIservo.py") as f: 37 | for line in f.readlines(): 38 | if(line.find(initial) == 0): 39 | r=line 40 | begin=len(list(initial)) 41 | snum=r[begin:] 42 | n=int(snum) 43 | return n 44 | 45 | pwm0_direction = 1 46 | pwm0_init = num_import_int('init_pwm0 = ') 47 | pwm0_max = 520 48 | pwm0_min = 100 49 | pwm0_pos = pwm0_init 50 | 51 | pwm1_direction = 1 52 | pwm1_init = num_import_int('init_pwm1 = ') 53 | pwm1_max = 520 54 | pwm1_min = 100 55 | pwm1_pos = pwm1_init 56 | 57 | pwm2_direction = 1 58 | pwm2_init = num_import_int('init_pwm2 = ') 59 | pwm2_max = 520 60 | pwm2_min = 100 61 | pwm2_pos = pwm2_init 62 | 63 | line_pin_right = 19 64 | line_pin_middle = 16 65 | line_pin_left = 20 66 | 67 | def pwmGenOut(angleInput): 68 | return int(round(23/9*angleInput)) 69 | 70 | 71 | def setup(): 72 | global track_line_left, track_line_middle,track_line_right 73 | track_line_left = InputDevice(pin=line_pin_left) 74 | track_line_middle = InputDevice(pin=line_pin_middle) 75 | track_line_right = InputDevice(pin=line_pin_right) 76 | 77 | 78 | class Functions(threading.Thread): 79 | def __init__(self, *args, **kwargs): 80 | self.functionMode = 'none' 81 | self.steadyGoal = 0 82 | 83 | self.scanNum = 3 84 | self.scanList = [0,0,0] 85 | self.scanPos = 1 86 | self.scanDir = 1 87 | self.rangeKeep = 0.7 88 | self.scanRange = 100 89 | self.scanServo = 1 90 | self.turnServo = 0 91 | self.turnWiggle = 200 92 | 93 | setup() 94 | 95 | super(Functions, self).__init__(*args, **kwargs) 96 | self.__flag = threading.Event() 97 | self.__flag.clear() 98 | 99 | def radarScan(self): 100 | global pwm0_pos 101 | scan_speed = 3 102 | result = [] 103 | 104 | if pwm0_direction: 105 | pwm0_pos = pwm0_max 106 | pwm.set_pwm(1, 0, pwm0_pos) 107 | time.sleep(0.8) 108 | 109 | while pwm0_pos>pwm0_min: 110 | pwm0_pos-=scan_speed 111 | pwm.set_pwm(1, 0, pwm0_pos) 112 | dist = ultra.checkdist() 113 | if dist > 20: 114 | continue 115 | theta = 180 - (pwm0_pos-100)/2.55 # +30 deviation 116 | result.append([dist, theta]) 117 | else: 118 | pwm0_pos = pwm0_min 119 | pwm.set_pwm(1, 0, pwm0_pos) 120 | time.sleep(0.8) 121 | 122 | while pwm0_pos 20: 127 | continue 128 | theta = (pwm0_pos-100)/2.55 129 | result.append([dist, theta]) 130 | pwm.set_pwm(1, 0, pwm0_init) 131 | return result 132 | 133 | 134 | def pause(self): 135 | self.functionMode = 'none' 136 | move.move(80, 'no', 'no', 0.5) 137 | self.__flag.clear() 138 | 139 | 140 | def resume(self): 141 | self.__flag.set() 142 | 143 | 144 | def automatic(self): 145 | self.functionMode = 'Automatic' 146 | self.resume() 147 | 148 | 149 | def trackLine(self): 150 | self.functionMode = 'trackLine' 151 | self.resume() 152 | 153 | 154 | def steady(self,goalPos): 155 | self.functionMode = 'Steady' 156 | self.steadyGoal = goalPos 157 | self.resume() 158 | 159 | 160 | def trackLineProcessing(self): 161 | status_right = track_line_right.value 162 | status_middle = track_line_middle.value 163 | status_left = track_line_left.value 164 | #print('R%d M%d L%d'%(status_right,status_middle,status_left)) 165 | if status_middle == 1: 166 | move.move(100, 'forward', 'no', 1) 167 | elif status_left == 1: 168 | move.move(100, 'no', 'right', 1) 169 | elif status_right == 1: 170 | move.move(100, 'no', 'left', 1) 171 | else: 172 | move.move(100, 'backward', 'no', 1) 173 | 174 | time.sleep(0.1) 175 | 176 | 177 | def automaticProcessing(self): 178 | print('automaticProcessing') 179 | if self.rangeKeep/3 > ultra.checkdist(): 180 | move.move(100, 'backward', 'no', 0.5) 181 | elif self.rangeKeep > ultra.checkdist(): 182 | move.move(100, 'no', 'left', 0.5) 183 | else: 184 | move.move(100, 'forward', 'no', 0.5) 185 | time.sleep(0.1) 186 | if self.functionMode == 'none': 187 | move.move(80, 'no', 'no', 0.5) 188 | 189 | 190 | def functionGoing(self): 191 | if self.functionMode == 'none': 192 | self.pause() 193 | elif self.functionMode == 'Automatic': 194 | self.automaticProcessing() 195 | elif self.functionMode == 'trackLine': 196 | self.trackLineProcessing() 197 | 198 | 199 | def run(self): 200 | while 1: 201 | self.__flag.wait() 202 | self.functionGoing() 203 | pass 204 | 205 | 206 | if __name__ == '__main__': 207 | pass 208 | # fuc=Functions() 209 | # fuc.radarScan() 210 | # fuc.start() 211 | # fuc.automatic() 212 | # # fuc.steady(300) 213 | # time.sleep(30) 214 | # fuc.pause() 215 | # time.sleep(1) 216 | # move.move(80, 'no', 'no', 0.5) 217 | -------------------------------------------------------------------------------- /server/servo.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # File name : servo.py 3 | # Description : Control Servos 4 | # Author : William 5 | # Date : 2019/02/23 6 | from __future__ import division 7 | import time 8 | import RPi.GPIO as GPIO 9 | import sys 10 | import Adafruit_PCA9685 11 | import ultra 12 | 13 | ''' 14 | change this form 1 to 0 to reverse servos 15 | ''' 16 | pwm0_direction = 1 17 | pwm1_direction = 1 18 | pwm2_direction = 1 19 | pwm3_direction = 1 20 | 21 | 22 | pwm = Adafruit_PCA9685.PCA9685() 23 | pwm.set_pwm_freq(50) 24 | 25 | pwm0_init = 300 26 | pwm0_max = 450 27 | pwm0_min = 150 28 | pwm0_pos = pwm0_init 29 | 30 | pwm1_init = 300 31 | pwm1_max = 480 32 | pwm1_min = 160 33 | pwm1_pos = pwm1_init 34 | 35 | pwm2_init = 300 36 | pwm2_max = 500 37 | pwm2_min = 100 38 | pwm2_pos = pwm2_init 39 | 40 | pwm3_init = 300 41 | pwm3_max = 500 42 | pwm3_min = 300 43 | pwm3_pos = pwm3_init 44 | 45 | org_pos = 300 46 | 47 | 48 | def radar_scan(): 49 | global pwm0_pos 50 | scan_result = 'U: ' 51 | scan_speed = 1 52 | if pwm0_direction: 53 | pwm0_pos = pwm0_max 54 | pwm.set_pwm(0, 0, pwm0_pos) 55 | time.sleep(0.5) 56 | scan_result += str(ultra.checkdist()) 57 | scan_result += ' ' 58 | while pwm0_pos>pwm0_min: 59 | pwm0_pos-=scan_speed 60 | pwm.set_pwm(0, 0, pwm0_pos) 61 | scan_result += str(ultra.checkdist()) 62 | scan_result += ' ' 63 | pwm.set_pwm(0, 0, pwm0_init) 64 | else: 65 | pwm0_pos = pwm0_min 66 | pwm.set_pwm(0, 0, pwm0_pos) 67 | time.sleep(0.5) 68 | scan_result += str(ultra.checkdist()) 69 | scan_result += ' ' 70 | while pwm0_pos max_genout: 84 | raw_output = max_genout 85 | elif raw < min_genout: 86 | raw_output = min_genout 87 | else: 88 | raw_output = raw 89 | return int(raw_output) 90 | 91 | 92 | def camera_ang(direction, ang): 93 | global org_pos 94 | if ang == 'no': 95 | ang = 50 96 | if look_direction: 97 | if direction == 'lookdown': 98 | org_pos+=ang 99 | org_pos = ctrl_range(org_pos, look_max, look_min) 100 | elif direction == 'lookup': 101 | org_pos-=ang 102 | org_pos = ctrl_range(org_pos, look_max, look_min) 103 | elif direction == 'home': 104 | org_pos = 300 105 | else: 106 | if direction == 'lookdown': 107 | org_pos-=ang 108 | org_pos = ctrl_range(org_pos, look_max, look_min) 109 | elif direction == 'lookup': 110 | org_pos+=ang 111 | org_pos = ctrl_range(org_pos, look_max, look_min) 112 | elif direction == 'home': 113 | org_pos = 300 114 | 115 | pwm.set_all_pwm(0,org_pos) 116 | 117 | 118 | def lookleft(speed): 119 | global pwm0_pos 120 | if pwm0_direction: 121 | pwm0_pos += speed 122 | pwm0_pos = ctrl_range(pwm0_pos, pwm0_max, pwm0_min) 123 | pwm.set_pwm(0, 0, pwm0_pos) 124 | else: 125 | pwm0_pos -= speed 126 | pwm0_pos = ctrl_range(pwm0_pos, pwm0_max, pwm0_min) 127 | pwm.set_pwm(0, 0, pwm0_pos) 128 | 129 | 130 | def lookright(speed): 131 | global pwm0_pos 132 | if pwm0_direction: 133 | pwm0_pos -= speed 134 | pwm0_pos = ctrl_range(pwm0_pos, pwm0_max, pwm0_min) 135 | pwm.set_pwm(0, 0, pwm0_pos) 136 | else: 137 | pwm0_pos += speed 138 | pwm0_pos = ctrl_range(pwm0_pos, pwm0_max, pwm0_min) 139 | pwm.set_pwm(0, 0, pwm0_pos) 140 | 141 | 142 | def up(speed): 143 | global pwm1_pos 144 | if pwm1_direction: 145 | pwm1_pos -= speed 146 | pwm1_pos = ctrl_range(pwm1_pos, pwm1_max, pwm1_min) 147 | pwm.set_pwm(1, 0, pwm1_pos) 148 | else: 149 | pwm1_pos += speed 150 | pwm1_pos = ctrl_range(pwm1_pos, pwm1_max, pwm1_min) 151 | pwm.set_pwm(1, 0, pwm1_pos) 152 | #print(pwm1_pos) 153 | 154 | 155 | def down(speed): 156 | global pwm1_pos 157 | if pwm1_direction: 158 | pwm1_pos += speed 159 | pwm1_pos = ctrl_range(pwm1_pos, pwm1_max, pwm1_min) 160 | pwm.set_pwm(1, 0, pwm1_pos) 161 | else: 162 | pwm1_pos -= speed 163 | pwm1_pos = ctrl_range(pwm1_pos, pwm1_max, pwm1_min) 164 | pwm.set_pwm(1, 0, pwm1_pos) 165 | #print(pwm1_pos) 166 | 167 | def lookup(speed): 168 | global pwm2_pos 169 | if pwm2_direction: 170 | pwm2_pos -= speed 171 | pwm2_pos = ctrl_range(pwm2_pos, pwm2_max, pwm2_min) 172 | pwm.set_pwm(2, 0, pwm2_pos) 173 | else: 174 | pwm2_pos += speed 175 | pwm2_pos = ctrl_range(pwm2_pos, pwm2_max, pwm2_min) 176 | pwm.set_pwm(2, 0, pwm2_pos) 177 | 178 | 179 | def lookdown(speed): 180 | global pwm2_pos 181 | if pwm2_direction: 182 | pwm2_pos += speed 183 | pwm2_pos = ctrl_range(pwm2_pos, pwm2_max, pwm2_min) 184 | pwm.set_pwm(2, 0, pwm2_pos) 185 | else: 186 | pwm2_pos -= speed 187 | pwm2_pos = ctrl_range(pwm2_pos, pwm2_max, pwm2_min) 188 | pwm.set_pwm(2, 0, pwm2_pos) 189 | 190 | 191 | def grab(speed): 192 | global pwm3_pos 193 | if pwm3_direction: 194 | pwm3_pos -= speed 195 | pwm3_pos = ctrl_range(pwm3_pos, pwm3_max, pwm3_min) 196 | pwm.set_pwm(3, 0, pwm3_pos) 197 | else: 198 | pwm3_pos += speed 199 | pwm3_pos = ctrl_range(pwm3_pos, pwm3_max, pwm3_min) 200 | pwm.set_pwm(3, 0, pwm3_pos) 201 | print(pwm3_pos) 202 | 203 | 204 | def loose(speed): 205 | global pwm3_pos 206 | if pwm3_direction: 207 | pwm3_pos += speed 208 | pwm3_pos = ctrl_range(pwm3_pos, pwm3_max, pwm3_min) 209 | pwm.set_pwm(3, 0, pwm3_pos) 210 | else: 211 | pwm3_pos -= speed 212 | pwm3_pos = ctrl_range(pwm3_pos, pwm3_max, pwm3_min) 213 | pwm.set_pwm(3, 0, pwm3_pos) 214 | print(pwm3_pos) 215 | 216 | 217 | def servo_init(): 218 | pwm.set_pwm(0, 0, pwm0_pos) 219 | pwm.set_pwm(1, 0, pwm1_pos) 220 | pwm.set_pwm(2, 0, pwm2_max) 221 | pwm.set_pwm(3, 0, pwm3_pos) 222 | try: 223 | pwm.set_all_pwm(0, 300) 224 | except: 225 | pass 226 | 227 | 228 | def clean_all(): 229 | global pwm 230 | pwm = Adafruit_PCA9685.PCA9685() 231 | pwm.set_pwm_freq(50) 232 | pwm.set_all_pwm(0, 0) 233 | 234 | 235 | def ahead(): 236 | global pwm0_pos, pwm1_pos 237 | pwm.set_pwm(0, 0, pwm0_init) 238 | pwm.set_pwm(1, 0, (pwm1_max-20)) 239 | pwm0_pos = pwm0_init 240 | pwm1_pos = pwm1_max-20 241 | 242 | 243 | def get_direction(): 244 | return (pwm0_pos - pwm0_init) 245 | 246 | 247 | if __name__ == '__main__': 248 | 249 | channel = 0 # servo port number. 250 | while True: 251 | pwm.set_pwm(channel, 0, 150) 252 | time.sleep(1) 253 | pwm.set_pwm(channel, 0, 450) 254 | time.sleep(1) 255 | 256 | -------------------------------------------------------------------------------- /server/appserverAP.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env/python 2 | # File name : appserverAP.py 3 | # Author : William 4 | # Date : 2019/10/28 5 | 6 | import socket 7 | import threading 8 | import time 9 | import os 10 | from rpi_ws281x import * 11 | import LED 12 | import move 13 | import servo 14 | 15 | LED = LED.LED() 16 | LED.colorWipe(Color(80,255,0)) 17 | 18 | step_set = 1 19 | speed_set = 100 20 | rad = 0.6 21 | 22 | direction_command = 'no' 23 | turn_command = 'no' 24 | pos_input = 1 25 | catch_input = 1 26 | cir_input = 6 27 | 28 | 29 | def app_ctrl(): 30 | app_HOST = '' 31 | app_PORT = 10123 32 | app_BUFSIZ = 1024 33 | app_ADDR = (app_HOST, app_PORT) 34 | 35 | def ap_thread(): 36 | os.system("sudo create_ap wlan0 eth0 AdeeptCar 12345678") 37 | 38 | def setup(): 39 | move.setup() 40 | 41 | def appCommand(data_input): 42 | global direction_command, turn_command, pos_input, catch_input, cir_input 43 | if data_input == 'forwardStart\n': 44 | direction_command = 'forward' 45 | move.move(speed_set, direction_command, turn_command, rad) 46 | 47 | elif data_input == 'backwardStart\n': 48 | direction_command = 'backward' 49 | move.move(speed_set, direction_command, turn_command, rad) 50 | 51 | elif data_input == 'leftStart\n': 52 | turn_command = 'left' 53 | move.move(speed_set, direction_command, turn_command, rad) 54 | 55 | elif data_input == 'rightStart\n': 56 | turn_command = 'right' 57 | move.move(speed_set, direction_command, turn_command, rad) 58 | 59 | elif 'forwardStop' in data_input: 60 | direction_command = 'no' 61 | move.move(speed_set, direction_command, turn_command, rad) 62 | 63 | elif 'backwardStop' in data_input: 64 | direction_command = 'no' 65 | move.move(speed_set, direction_command, turn_command, rad) 66 | 67 | elif 'leftStop' in data_input: 68 | turn_command = 'no' 69 | move.move(speed_set, direction_command, turn_command, rad) 70 | 71 | elif 'rightStop' in data_input: 72 | turn_command = 'no' 73 | move.move(speed_set, direction_command, turn_command, rad) 74 | 75 | 76 | if data_input == 'lookLeftStart\n': 77 | if cir_input < 12: 78 | cir_input+=1 79 | servo.cir_pos(cir_input) 80 | 81 | elif data_input == 'lookRightStart\n': 82 | if cir_input > 1: 83 | cir_input-=1 84 | servo.cir_pos(cir_input) 85 | 86 | elif data_input == 'downStart\n': 87 | servo.camera_ang('lookdown',10) 88 | 89 | elif data_input == 'upStart\n': 90 | servo.camera_ang('lookup',10) 91 | 92 | elif 'lookLeftStop' in data_input: 93 | pass 94 | elif 'lookRightStop' in data_input: 95 | pass 96 | elif 'downStop' in data_input: 97 | pass 98 | elif 'upStop' in data_input: 99 | pass 100 | 101 | 102 | if data_input == 'aStart\n': 103 | if pos_input < 17: 104 | pos_input+=1 105 | servo.hand_pos(pos_input) 106 | 107 | elif data_input == 'bStart\n': 108 | if pos_input > 1: 109 | pos_input-=1 110 | servo.hand_pos(pos_input) 111 | 112 | elif data_input == 'cStart\n': 113 | if catch_input < 13: 114 | catch_input+=3 115 | servo.catch(catch_input) 116 | 117 | elif data_input == 'dStart\n': 118 | if catch_input > 1: 119 | catch_input-=3 120 | servo.catch(catch_input) 121 | 122 | elif 'aStop' in data_input: 123 | pass 124 | elif 'bStop' in data_input: 125 | pass 126 | elif 'cStop' in data_input: 127 | pass 128 | elif 'dStop' in data_input: 129 | pass 130 | 131 | print(data_input) 132 | 133 | def appconnect(): 134 | global AppCliSock, AppAddr 135 | try: 136 | s =socket.socket(socket.AF_INET,socket.SOCK_DGRAM) 137 | s.connect(("1.1.1.1",80)) 138 | ipaddr_check=s.getsockname()[0] 139 | s.close() 140 | print(ipaddr_check) 141 | 142 | AppSerSock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 143 | AppSerSock.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1) 144 | AppSerSock.bind(app_ADDR) 145 | AppSerSock.listen(5) 146 | print('waiting for App connection...') 147 | AppCliSock, AppAddr = AppSerSock.accept() 148 | print('...App connected from :', AppAddr) 149 | except: 150 | ap_threading=threading.Thread(target=ap_thread) #Define a thread for data receiving 151 | ap_threading.setDaemon(True) #'True' means it is a front thread,it would close when the mainloop() closes 152 | ap_threading.start() #Thread starts 153 | 154 | LED.colorWipe(Color(0,16,50)) 155 | time.sleep(1) 156 | LED.colorWipe(Color(0,16,100)) 157 | time.sleep(1) 158 | LED.colorWipe(Color(0,16,150)) 159 | time.sleep(1) 160 | LED.colorWipe(Color(0,16,200)) 161 | time.sleep(1) 162 | LED.colorWipe(Color(0,16,255)) 163 | time.sleep(1) 164 | LED.colorWipe(Color(35,255,35)) 165 | 166 | AppSerSock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 167 | AppSerSock.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1) 168 | AppSerSock.bind(app_ADDR) 169 | AppSerSock.listen(5) 170 | print('waiting for App connection...') 171 | AppCliSock, AppAddr = AppSerSock.accept() 172 | print('...App connected from :', AppAddr) 173 | 174 | appconnect() 175 | setup() 176 | app_threading=threading.Thread(target=appconnect) #Define a thread for FPV and OpenCV 177 | app_threading.setDaemon(True) #'True' means it is a front thread,it would close when the mainloop() closes 178 | app_threading.start() #Thread starts 179 | 180 | while 1: 181 | data = '' 182 | data = str(AppCliSock.recv(app_BUFSIZ).decode()) 183 | if not data: 184 | continue 185 | appCommand(data) 186 | pass 187 | 188 | AppConntect_threading=threading.Thread(target=app_ctrl) #Define a thread for FPV and OpenCV 189 | AppConntect_threading.setDaemon(True) #'True' means it is a front thread,it would close when the mainloop() closes 190 | AppConntect_threading.start() #Thread starts 191 | 192 | if __name__ == '__main__': 193 | i = 1 194 | while 1: 195 | i += 1 196 | print(i) 197 | time.sleep(30) 198 | pass -------------------------------------------------------------------------------- /server/dist/css/app.5a950261.css: -------------------------------------------------------------------------------- 1 | .appBar[data-v-2f6fc0b6]{-webkit-animation:shadowLight-data-v-2f6fc0b6 4s;animation:shadowLight-data-v-2f6fc0b6 4s;-webkit-animation-iteration-count:infinite;animation-iteration-count:infinite;-webkit-animation-direction:alternate;animation-direction:alternate;z-index:100;-webkit-box-shadow:0 -.2rem .7rem .1rem #b1b1b1;box-shadow:0 -.2rem .7rem .1rem #b1b1b1}@-webkit-keyframes shadowLight-data-v-2f6fc0b6{0%{-webkit-box-shadow:0 -.2rem .7rem .1rem #646464;box-shadow:0 -.2rem .7rem .1rem #646464}to{-webkit-box-shadow:0 .2rem .7rem .1rem #b1b1b1;box-shadow:0 .2rem .7rem .1rem #b1b1b1}}@keyframes shadowLight-data-v-2f6fc0b6{0%{-webkit-box-shadow:0 -.2rem .7rem .1rem #646464;box-shadow:0 -.2rem .7rem .1rem #646464}to{-webkit-box-shadow:0 .2rem .7rem .1rem #b1b1b1;box-shadow:0 .2rem .7rem .1rem #b1b1b1}}.mod-wrapper[data-v-68bf214e] .v-input__slider{margin-bottom:-.5rem}.mod-wrapper[data-v-68bf214e] .v-input__slider .v-label{border-radius:.3rem;background-color:#f0f0f0;padding:0 .3rem;margin:0}.mod-wrapper[data-v-68bf214e] .v-input__slider .v-slider{margin:0 .8rem}.mod-wrapper[data-v-68bf214e] .v-input__slider .v-slider .v-slider__track-fill{background-color:#263238!important}.mod-wrapper[data-v-68bf214e] .v-input__slider .v-slider .v-slider__track-background{background-color:#fff!important}.mod-wrapper[data-v-68bf214e] .v-input__slider .v-slider .v-slider__thumb,.mod-wrapper[data-v-68bf214e] .v-input__slider .v-slider .v-slider__thumb:before{background-color:#fafafa!important}.mod-wrapper[data-v-68bf214e] .v-input__slider .v-slider .v-slider__thumb-label{color:#aaa!important;background-color:#ededed!important}.mod-sheet[data-v-68bf214e]{border-radius:.4rem .4rem;-webkit-box-shadow:0 0 .7rem .25rem hsla(0,0%,100%,.7);box-shadow:0 0 .7rem .25rem hsla(0,0%,100%,.7)}.mod-sheet .mod-title[data-v-68bf214e]{border-radius:.4rem .4rem 0 0;padding:.2rem 1rem 0 .8rem;font-weight:500;margin:0;background-color:#fff;overflow:hidden;white-space:nowrap;text-overflow:ellipsis}.mod-sheet .mod-wrapper[data-v-68bf214e]{border-radius:0 0 .4rem .4rem;width:100%;padding:.1px 1rem .6rem 1rem;background-color:#cfd8dc}.vedio-wrapper[data-v-024a6bab]{position:relative;overflow:hidden;border-radius:.4rem;height:0;width:100%;padding-bottom:75%;margin-top:.5rem}.vedio-wrapper .draw-area[data-v-024a6bab]{position:absolute;top:0;padding-bottom:75%;width:100%}.vedio-wrapper .vedio[data-v-024a6bab]{top:.5rem;margin-bottom:-8px;width:100%}.vedio-wrapper .canvas[data-v-024a6bab]{width:100%}.status-wrapper[data-v-05264423]{margin:0 -.3rem;-ms-flex-wrap:wrap;flex-wrap:wrap}.status-wrapper .chips[data-v-05264423],.status-wrapper[data-v-05264423]{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center}.status-wrapper .chips[data-v-05264423]{-webkit-box-shadow:#000 0 0 .1rem 1px;box-shadow:0 0 .1rem 1px #000;width:100%;margin:0!important;margin-top:.4rem!important;padding:0 4%}.status-wrapper .chips .chip-title[data-v-05264423]{padding-right:.3rem}.buttons[data-v-726ac712]{margin-top:.5rem;min-width:0!important}.button-child[data-v-b4e411fa]{display:-webkit-box;display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between;width:100%}.button-child .buttons[data-v-b4e411fa]{margin-top:.5rem}.CVFL-wrapper[data-v-38858175]{display:-webkit-box;display:-ms-flexbox;display:flex}.CVFL-wrapper .sliders[data-v-38858175]{width:75%}.CVFL-wrapper .sliders[data-v-38858175] label{margin:0}.CVFL-wrapper .sliders[data-v-38858175] .v-input{margin-left:0!important;margin-right:0!important}.CVFL-wrapper .CVFL-bottons[data-v-38858175]{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column;-ms-flex-pack:distribute;justify-content:space-around;width:25%}.CVFL-wrapper .CVFL-bottons .button[data-v-38858175]{width:100%}.CVFL-wrapper .colorButton[data-v-38858175]{position:relative;overflow:hidden}.CVFL-wrapper .colorButton[data-v-38858175]:after{content:"";width:100%;height:100%;position:absolute;top:0;left:0;border-bottom:5px solid #bfbfbf;border-color:inherit;-webkit-transform-origin:top left}.colorSelecter[data-v-38858175] .v-color-picker__swatch{width:16%;padding:0 1%}.colorSelecter[data-v-38858175] .v-color-picker__color{width:100%}.color-picker-child[data-v-3dbdf3cf] .v-color-picker__swatch{width:16%;padding:0 1%}.color-picker-child[data-v-3dbdf3cf] .v-color-picker__color{width:100%}.FC-bottons[data-v-5a57ef1d]{display:-webkit-box;display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between;width:100%}.FC-bottons .button[data-v-5a57ef1d]{margin-top:.5rem;width:100%}.colorButton[data-v-5a57ef1d]{position:relative;overflow:hidden}.colorButton[data-v-5a57ef1d]:after{content:"";width:100%;height:100%;position:absolute;top:0;left:0;border-bottom:5px solid #bfbfbf;border-color:inherit;-webkit-transform-origin:top left}.expansion[data-v-4404e3bc]{-webkit-user-select:text;-moz-user-select:text;-ms-user-select:text;user-select:text;padding-top:.5rem}.expansion .v-expansion-panel-header[data-v-4404e3bc]{font-weight:650}.area-bg[data-v-ff914742]{display:-webkit-box;display:-ms-flexbox;display:flex;position:absolute;min-height:100%;width:100%;background:url(/api/img/bg.jpg) fixed top}.area-wrapper[data-v-ff914742]{margin:0 auto;min-height:100%;min-width:320px;width:85rem;max-width:85rem;background-color:#263238}.innerRow[data-v-ff914742]{margin:-12px}.controll-area[data-v-ff914742]{min-height:100%;max-width:80rem}.controll-area .sheets[data-v-ff914742]{background-color:#b0bec5}.light[data-v-b9aab66e]{position:absolute;-webkit-transition:margin-left linear;transition:margin-left linear;width:0;-webkit-box-shadow:0 0 .9rem .1rem #c7c7c7;box-shadow:0 0 .9rem .1rem #c7c7c7}::-webkit-scrollbar{display:none}html{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-ms-touch-action:manipulation;touch-action:manipulation}.col{-ms-flex-preferred-size:auto;flex-basis:auto} 2 | 3 | /*! normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css */html{line-height:1.15;-webkit-text-size-adjust:100%}body{margin:0}main{display:block}h1{font-size:2em;margin:.67em 0}hr{-webkit-box-sizing:content-box;box-sizing:content-box;height:0;overflow:visible}pre{font-family:monospace,monospace;font-size:1em}a{background-color:transparent}abbr[title]{border-bottom:none;text-decoration:underline;-webkit-text-decoration:underline dotted;text-decoration:underline dotted}b,strong{font-weight:bolder}code,kbd,samp{font-family:monospace,monospace;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}img{border-style:none}button,input,optgroup,select,textarea{font-family:inherit;font-size:100%;line-height:1.15;margin:0}button,input{overflow:visible}button,select{text-transform:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{border-style:none;padding:0}[type=button]:-moz-focusring,[type=reset]:-moz-focusring,[type=submit]:-moz-focusring,button:-moz-focusring{outline:1px dotted ButtonText}fieldset{padding:.35em .75em .625em}legend{-webkit-box-sizing:border-box;box-sizing:border-box;color:inherit;display:table;max-width:100%;padding:0;white-space:normal}progress{vertical-align:baseline}textarea{overflow:auto}[type=checkbox],[type=radio]{-webkit-box-sizing:border-box;box-sizing:border-box;padding:0}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}details{display:block}summary{display:list-item}[hidden],template{display:none} -------------------------------------------------------------------------------- /server/FPV.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env/python3 2 | # File name : server.py 3 | # Description : for FPV video and OpenCV functions 4 | # Website : www.adeept.com 5 | # E-mail : support@adeept.com 6 | # Author : William(Based on Adrian Rosebrock's OpenCV code on pyimagesearch.com) 7 | # Date : 2018/08/22 8 | 9 | import time 10 | import threading 11 | import cv2 12 | import zmq 13 | import base64 14 | import picamera 15 | from picamera.array import PiRGBArray 16 | import argparse 17 | import imutils 18 | from collections import deque 19 | import psutil 20 | import os 21 | import servo 22 | import PID 23 | import LED 24 | import datetime 25 | from rpi_ws281x import * 26 | import move 27 | 28 | pid = PID.PID() 29 | pid.SetKp(0.5) 30 | pid.SetKd(0) 31 | pid.SetKi(0) 32 | Y_lock = 0 33 | X_lock = 0 34 | tor = 17 35 | FindColorMode = 0 36 | WatchDogMode = 0 37 | UltraData = 3 38 | LED = LED.LED() 39 | 40 | class FPV: 41 | def __init__(self): 42 | self.frame_num = 0 43 | self.fps = 0 44 | 45 | self.colorUpper = (44, 255, 255) 46 | self.colorLower = (24, 100, 100) 47 | 48 | 49 | def SetIP(self,invar): 50 | self.IP = invar 51 | 52 | 53 | def FindColor(self,invar): 54 | global FindColorMode 55 | FindColorMode = invar 56 | if not FindColorMode: 57 | servo.camera_ang('home',0) 58 | 59 | 60 | def WatchDog(self,invar): 61 | global WatchDogMode 62 | WatchDogMode = invar 63 | 64 | 65 | def UltraData(self,invar): 66 | global UltraData 67 | UltraData = invar 68 | 69 | 70 | def capture_thread(self,IPinver): 71 | ap = argparse.ArgumentParser() #OpenCV initialization 72 | ap.add_argument("-b", "--buffer", type=int, default=64, 73 | help="max buffer size") 74 | args = vars(ap.parse_args()) 75 | pts = deque(maxlen=args["buffer"]) 76 | 77 | font = cv2.FONT_HERSHEY_SIMPLEX 78 | 79 | camera = picamera.PiCamera() 80 | camera.resolution = (640, 480) 81 | camera.framerate = 20 82 | rawCapture = PiRGBArray(camera, size=(640, 480)) 83 | 84 | context = zmq.Context() 85 | footage_socket = context.socket(zmq.PUB) 86 | print(IPinver) 87 | footage_socket.connect('tcp://%s:5555'%IPinver) 88 | 89 | avg = None 90 | motionCounter = 0 91 | #time.sleep(4) 92 | lastMovtionCaptured = datetime.datetime.now() 93 | 94 | for frame in camera.capture_continuous(rawCapture, format="bgr", use_video_port=True): 95 | frame_image = frame.array 96 | cv2.line(frame_image,(300,240),(340,240),(128,255,128),1) 97 | cv2.line(frame_image,(320,220),(320,260),(128,255,128),1) 98 | timestamp = datetime.datetime.now() 99 | 100 | if FindColorMode: 101 | 102 | ####>>>OpenCV Start<<<#### 103 | hsv = cv2.cvtColor(frame_image, cv2.COLOR_BGR2HSV) 104 | mask = cv2.inRange(hsv, self.colorLower, self.colorUpper) 105 | mask = cv2.erode(mask, None, iterations=2) 106 | mask = cv2.dilate(mask, None, iterations=2) 107 | cnts = cv2.findContours(mask.copy(), cv2.RETR_EXTERNAL, 108 | cv2.CHAIN_APPROX_SIMPLE)[-2] 109 | center = None 110 | if len(cnts) > 0: 111 | cv2.putText(frame_image,'Target Detected',(40,60), font, 0.5,(255,255,255),1,cv2.LINE_AA) 112 | c = max(cnts, key=cv2.contourArea) 113 | ((x, y), radius) = cv2.minEnclosingCircle(c) 114 | M = cv2.moments(c) 115 | center = (int(M["m10"] / M["m00"]), int(M["m01"] / M["m00"])) 116 | X = int(x) 117 | Y = int(y) 118 | if radius > 10: 119 | cv2.rectangle(frame_image,(int(x-radius),int(y+radius)),(int(x+radius),int(y-radius)),(255,255,255),1) 120 | 121 | if Y < (240-tor): 122 | error = (240-Y)/5 123 | outv = int(round((pid.GenOut(error)),0)) 124 | servo.camera_ang('lookup',outv) 125 | Y_lock = 0 126 | elif Y > (240+tor): 127 | error = (Y-240)/5 128 | outv = int(round((pid.GenOut(error)),0)) 129 | servo.camera_ang('lookdown',outv) 130 | Y_lock = 0 131 | else: 132 | Y_lock = 1 133 | 134 | 135 | if X < (320-tor*3): 136 | move.move(70, 'no', 'left', 0.6) 137 | #time.sleep(0.1) 138 | #move.motorStop() 139 | X_lock = 0 140 | elif X > (330+tor*3): 141 | move.move(70, 'no', 'right', 0.6) 142 | #time.sleep(0.1) 143 | #move.motorStop() 144 | X_lock = 0 145 | else: 146 | move.motorStop() 147 | X_lock = 1 148 | 149 | if X_lock == 1 and Y_lock == 1: 150 | if UltraData > 0.5: 151 | LED.colorWipe(Color(255,16,0)) 152 | move.move(70, 'forward', 'no', 0.6) 153 | elif UltraData < 0.4: 154 | LED.colorWipe(Color(0,16,255)) 155 | move.move(70, 'backward', 'no', 0.6) 156 | print(UltraData) 157 | else: 158 | move.motorStop() 159 | 160 | 161 | else: 162 | cv2.putText(frame_image,'Target Detecting',(40,60), font, 0.5,(255,255,255),1,cv2.LINE_AA) 163 | move.motorStop() 164 | 165 | for i in range(1, len(pts)): 166 | if pts[i - 1] is None or pts[i] is None: 167 | continue 168 | thickness = int(np.sqrt(args["buffer"] / float(i + 1)) * 2.5) 169 | cv2.line(frame_image, pts[i - 1], pts[i], (0, 0, 255), thickness) 170 | ####>>>OpenCV Ends<<<#### 171 | 172 | 173 | if WatchDogMode: 174 | gray = cv2.cvtColor(frame_image, cv2.COLOR_BGR2GRAY) 175 | gray = cv2.GaussianBlur(gray, (21, 21), 0) 176 | 177 | if avg is None: 178 | print("[INFO] starting background model...") 179 | avg = gray.copy().astype("float") 180 | rawCapture.truncate(0) 181 | continue 182 | 183 | cv2.accumulateWeighted(gray, avg, 0.5) 184 | frameDelta = cv2.absdiff(gray, cv2.convertScaleAbs(avg)) 185 | 186 | # threshold the delta image, dilate the thresholded image to fill 187 | # in holes, then find contours on thresholded image 188 | thresh = cv2.threshold(frameDelta, 5, 255, 189 | cv2.THRESH_BINARY)[1] 190 | thresh = cv2.dilate(thresh, None, iterations=2) 191 | cnts = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL, 192 | cv2.CHAIN_APPROX_SIMPLE) 193 | cnts = imutils.grab_contours(cnts) 194 | #print('x') 195 | 196 | # loop over the contours 197 | for c in cnts: 198 | # if the contour is too small, ignore it 199 | if cv2.contourArea(c) < 5000: 200 | continue 201 | 202 | # compute the bounding box for the contour, draw it on the frame, 203 | # and update the text 204 | (x, y, w, h) = cv2.boundingRect(c) 205 | cv2.rectangle(frame_image, (x, y), (x + w, y + h), (128, 255, 0), 1) 206 | text = "Occupied" 207 | motionCounter += 1 208 | #print(motionCounter) 209 | #print(text) 210 | LED.colorWipe(Color(255,16,0)) 211 | lastMovtionCaptured = timestamp 212 | 213 | if (timestamp - lastMovtionCaptured).seconds >= 0.5: 214 | LED.colorWipe(Color(0,16,255)) 215 | 216 | 217 | encoded, buffer = cv2.imencode('.jpg', frame_image) 218 | jpg_as_text = base64.b64encode(buffer) 219 | footage_socket.send(jpg_as_text) 220 | 221 | rawCapture.truncate(0) 222 | 223 | 224 | if __name__ == '__main__': 225 | fpv=FPV() 226 | while 1: 227 | fpv.capture_thread('192.168.0.110') 228 | pass 229 | 230 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | # coding=utf-8 3 | # File name : setup.py 4 | # Author : Devin 5 | 6 | import os 7 | import time 8 | import subprocess 9 | 10 | username = os.popen("echo ${SUDO_USER:-$(who -m | awk '{ print $1 }')}").readline().strip() # pi 11 | user_home = os.popen('getent passwd %s | cut -d: -f 6'%username).readline().strip() # home 12 | 13 | curpath = os.path.realpath(__file__) 14 | thisPath = "/" + os.path.dirname(curpath) 15 | 16 | print(thisPath) 17 | 18 | def replace_num(file,initial,new_num): 19 | newline="" 20 | str_num=str(new_num) 21 | with open(file,"r") as f: 22 | for line in f.readlines(): 23 | if(line.find(initial) == 0): 24 | line = (str_num+'\n') 25 | newline += line 26 | with open(file,"w") as f: 27 | f.writelines(newline) 28 | 29 | 30 | def run_command(cmd=""): 31 | import subprocess 32 | p = subprocess.Popen( 33 | cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) 34 | result = p.stdout.read().decode('utf-8') 35 | status = p.poll() 36 | return status, result 37 | 38 | def check_rpi_model(): 39 | _, result = run_command("cat /proc/device-tree/model |awk '{print $3}'") 40 | result = result.strip() 41 | if result == '3': 42 | return int(3) 43 | elif result == '4': 44 | return int(4) 45 | else: 46 | return None 47 | 48 | def check_raspbain_version(): 49 | _, result = run_command("cat /etc/debian_version|awk -F. '{print $1}'") 50 | return int(result.strip()) 51 | 52 | def check_python_version(): 53 | import sys 54 | major = int(sys.version_info.major) 55 | minor = int(sys.version_info.minor) 56 | micro = int(sys.version_info.micro) 57 | return major, minor, micro 58 | 59 | def check_os_bit(): 60 | ''' 61 | # import platform 62 | # machine_type = platform.machine() 63 | latest bullseye uses a 64-bit kernel 64 | This method is no longer applicable, the latest raspbian will uses 64-bit kernel 65 | (kernel 6.1.x) by default, "uname -m" shows "aarch64", 66 | but the system is still 32-bit. 67 | ''' 68 | _ , os_bit = run_command("getconf LONG_BIT") 69 | return int(os_bit) 70 | 71 | def check_systemctl_service(service_name): 72 | return subprocess.run( 73 | ["systemctl", "is-active", service_name], 74 | capture_output=True, text=True 75 | ).stdout.strip() == "active" 76 | 77 | 78 | commands_apt = [ 79 | "sudo apt-get update", 80 | "sudo apt-get install python3-gpiozero python3-pigpio", 81 | "sudo apt-get install -y python3-pyqt5 python3-opengl", 82 | "sudo apt-get install -y python3-picamera2", 83 | "sudo apt-get install -y python3-opencv", 84 | "sudo apt-get install -y opencv-data", 85 | "sudo apt-get install -y python3-pyaudio" 86 | ] 87 | mark_apt = 0 88 | for x in range(3): 89 | for command in commands_apt: 90 | if os.system(command) != 0: 91 | print("Error running installation step apt") 92 | mark_apt = 1 93 | if mark_apt == 0: 94 | break 95 | 96 | commands_pip_1 = [ 97 | "sudo pip3 install adafruit-circuitpython-motor", 98 | "sudo pip3 install adafruit-circuitpython-pca9685", 99 | "sudo pip3 install flask", 100 | "sudo pip3 install flask_cors", 101 | "sudo pip3 install numpy", 102 | "sudo pip3 install pyzmq", 103 | "sudo pip3 install imutils zmq pybase64 psutil", 104 | "sudo pip3 install websockets==13.0", 105 | "sudo pip3 install rpi_ws281x", 106 | "sudo pip3 install adafruit-circuitpython-ads7830", 107 | "sudo pip3 install adafruit-pca9685" 108 | ] 109 | commands_pip_2 = [ 110 | "sudo pip3 install adafruit-circuitpython-motor --break-system-packages", 111 | "sudo pip3 install adafruit-circuitpython-pca9685 --break-system-packages", 112 | "sudo pip3 install flask --break-system-packages", 113 | "sudo pip3 install flask_cors --break-system-packages", 114 | "sudo pip3 install numpy --break-system-packages", 115 | "sudo pip3 install pyzmq --break-system-packages", 116 | "sudo pip3 install imutils zmq pybase64 psutil --break-system-packages", 117 | "sudo pip3 install websockets==13.0 --break-system-packages", 118 | "sudo pip3 install rpi_ws281x --break-system-packages", 119 | "sudo pip3 install adafruit-circuitpython-ads7830 --break-system-packages", 120 | "sudo pip3 install adafruit-pca9685 --break-system-packages" 121 | ] 122 | mark_pip = 0 123 | OS_version = check_raspbain_version() 124 | if OS_version <= 11: 125 | for x in range(3): 126 | for command in commands_pip_1: 127 | if os.system(command) != 0: 128 | print("Error running installation step pip") 129 | mark_pip = 1 130 | if mark_pip == 0: 131 | break 132 | else: 133 | for x in range(3): 134 | for command in commands_pip_2: 135 | if os.system(command) != 0: 136 | print("Error running installation step pip") 137 | mark_pip = 1 138 | if mark_pip == 0: 139 | break 140 | 141 | 142 | wifi_service_name="wifi-hotspot-manager.service" 143 | if not check_systemctl_service(wifi_service_name): 144 | # wifi and hotspot switch script 145 | os.system(f"sudo cp {thisPath}/wifi_hotspot_manager.sh /home/pi") 146 | os.system("sudo chmod +x /home/pi/wifi_hotspot_manager.sh") 147 | 148 | 149 | wifi_service_content="""[Unit] 150 | Description=WiFi and Hotspot Manager Service 151 | After=network.target NetworkManager.service 152 | Wants=NetworkManager.service 153 | 154 | [Service] 155 | Type=oneshot 156 | ExecStart=/home/pi/wifi_hotspot_manager.sh 157 | User=root 158 | RemainAfterExit=yes 159 | 160 | [Install] 161 | WantedBy=multi-user.target 162 | """ 163 | # system-level services must be placed in this directory 164 | wifi_service_file_path = "/etc/systemd/system/" + wifi_service_name 165 | 166 | try: 167 | # Write to the service file (requires root privileges) 168 | with open(wifi_service_file_path, "w") as f: 169 | f.write(wifi_service_content) 170 | print(f"Service file created: {wifi_service_file_path}") 171 | 172 | # Set file permissions 173 | os.chmod(wifi_service_file_path, 0o644) 174 | 175 | # Reload systemd configuration, enable and start the service 176 | subprocess.run(["sudo", "systemctl", "daemon-reload"], check=True) 177 | subprocess.run(["sudo", "systemctl", "enable", wifi_service_name], check=True) 178 | 179 | print(f"Service {wifi_service_name} has been enabled and started") 180 | except subprocess.CalledProcessError as e: 181 | print(f"Command execution failed: {e}") 182 | except Exception as e: 183 | print(f"An error occurred: {e}") 184 | 185 | 186 | robot_service_name="Adeept_Robot.service" 187 | if not check_systemctl_service(robot_service_name): 188 | # auto start script 189 | try: 190 | os.system("sudo touch /"+ user_home +"/startup.sh") 191 | with open("/"+ user_home +"/startup.sh",'w') as file_to_write: 192 | #you can choose how to control the robot 193 | file_to_write.write("#!/bin/sh\nsleep 5\nsudo python3 " + thisPath + "/server/webServer.py") 194 | except: 195 | pass 196 | os.system("sudo chmod 777 /"+ user_home +"/startup.sh") 197 | 198 | #config systemctl service 199 | # Define the content of the systemd service file 200 | robot_service_content=f"""[Unit] 201 | Description=Auto-start robot control script 202 | After={wifi_service_name} 203 | 204 | [Service] 205 | Type=simple 206 | User=root 207 | WorkingDirectory=/home/pi 208 | ExecStart=/home/pi/startup.sh 209 | Restart=no 210 | 211 | [Install] 212 | WantedBy=multi-user.target 213 | """ 214 | 215 | # Path for the service file (system-level services must be placed in this directory) 216 | robot_service_file_path = "/etc/systemd/system/" + robot_service_name 217 | 218 | try: 219 | # Write to the service file (requires root privileges) 220 | with open(robot_service_file_path, "w") as f: 221 | f.write(robot_service_content) 222 | print(f"Service file created: {robot_service_file_path}") 223 | 224 | # Set file permissions 225 | os.chmod(robot_service_file_path, 0o644) 226 | 227 | # Reload systemd configuration, enable and start the service 228 | subprocess.run(["sudo", "systemctl", "daemon-reload"], check=True) 229 | subprocess.run(["sudo", "systemctl", "enable", robot_service_name], check=True) 230 | 231 | print(f"Service {robot_service_name} has been enabled and started") 232 | except subprocess.CalledProcessError as e: 233 | print(f"Command execution failed: {e}") 234 | except Exception as e: 235 | print(f"An error occurred: {e}") 236 | 237 | 238 | print('The program in Raspberry Pi has been installed, disconnected and restarted. \nYou can now power off the Raspberry Pi to install the camera and driver board (Robot HAT). \nAfter turning on again, the Raspberry Pi will automatically run the program to set the servos port signal to turn the servos to the middle position, which is convenient for mechanical assembly.') 239 | print('restarting...') 240 | os.system("sudo reboot") 241 | -------------------------------------------------------------------------------- /server/appserver.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env/python 2 | # File name : server.py 3 | # Production : Gtank 4 | # Website : www.gewbot.com 5 | # E-mail : gewubot@163.com 6 | # Author : William 7 | # Date : 2019/10/28 8 | 9 | import socket 10 | import threading 11 | import time 12 | import os 13 | import LED 14 | import move 15 | import servo 16 | import switch 17 | servo.servo_init() 18 | switch.switchSetup() 19 | switch.set_all_switch_off() 20 | LED = LED.LED() 21 | LED.colorWipe(80,255,0) 22 | 23 | step_set = 1 24 | speed_set = 100 25 | rad = 0.6 26 | 27 | direction_command = 'no' 28 | turn_command = 'no' 29 | servo_command = 'no' 30 | pos_input = 1 31 | catch_input = 1 32 | cir_input = 6 33 | 34 | servo_speed = 11 35 | 36 | 37 | class Servo_ctrl(threading.Thread): 38 | def __init__(self, *args, **kwargs): 39 | super(Servo_ctrl, self).__init__(*args, **kwargs) 40 | self.__flag = threading.Event() # 用于暂停线程的标识 41 | self.__flag.set() # 设置为True 42 | self.__running = threading.Event() # 用于停止线程的标识 43 | self.__running.set() # 将running设置为True 44 | 45 | def run(self): 46 | while self.__running.isSet(): 47 | self.__flag.wait() # 为True时立即返回, 为False时阻塞直到内部的标识位为True后返回 48 | if servo_command == 'lookleft': 49 | servo.lookleft(servo_speed) 50 | elif servo_command == 'lookright': 51 | servo.lookright(servo_speed) 52 | elif servo_command == 'up': 53 | servo.up(servo_speed) 54 | elif servo_command == 'down': 55 | servo.down(servo_speed) 56 | elif servo_command == 'lookup': 57 | servo.lookup(servo_speed) 58 | elif servo_command == 'lookdown': 59 | servo.lookdown(servo_speed) 60 | elif servo_command == 'grab': 61 | servo.grab(servo_speed) 62 | elif servo_command == 'loose': 63 | servo.loose(servo_speed) 64 | else: 65 | pass 66 | time.sleep(0.07) 67 | 68 | def pause(self): 69 | self.__flag.clear() # 设置为False, 让线程阻塞 70 | 71 | def resume(self): 72 | self.__flag.set() # 设置为True, 让线程停止阻塞 73 | 74 | def stop(self): 75 | self.__flag.set() # 将线程从暂停状态恢复, 如何已经暂停的话 76 | self.__running.clear() # 设置为False 77 | 78 | 79 | def app_ctrl(): 80 | global servo_move 81 | app_HOST = '' 82 | app_PORT = 10123 83 | app_BUFSIZ = 1024 84 | app_ADDR = (app_HOST, app_PORT) 85 | 86 | servo_move = Servo_ctrl() 87 | servo_move.start() 88 | servo_move.pause() 89 | 90 | def ap_thread(): 91 | os.system("sudo create_ap wlan0 eth0 Groovy 12345678") 92 | 93 | def setup(): 94 | move.setup() 95 | 96 | def appCommand(data_input): 97 | global direction_command, turn_command, servo_command 98 | if data_input == 'forwardStart\n': 99 | direction_command = 'forward' 100 | move.move(speed_set, direction_command, turn_command, rad) 101 | 102 | elif data_input == 'backwardStart\n': 103 | direction_command = 'backward' 104 | move.move(speed_set, direction_command, turn_command, rad) 105 | 106 | elif data_input == 'leftStart\n': 107 | turn_command = 'left' 108 | move.move(speed_set, direction_command, turn_command, rad) 109 | 110 | elif data_input == 'rightStart\n': 111 | turn_command = 'right' 112 | move.move(speed_set, direction_command, turn_command, rad) 113 | 114 | elif 'forwardStop' in data_input: 115 | direction_command = 'no' 116 | move.move(speed_set, direction_command, turn_command, rad) 117 | 118 | elif 'backwardStop' in data_input: 119 | direction_command = 'no' 120 | move.move(speed_set, direction_command, turn_command, rad) 121 | 122 | elif 'leftStop' in data_input: 123 | turn_command = 'no' 124 | move.move(speed_set, direction_command, turn_command, rad) 125 | 126 | elif 'rightStop' in data_input: 127 | turn_command = 'no' 128 | move.move(speed_set, direction_command, turn_command, rad) 129 | 130 | 131 | if data_input == 'lookLeftStart\n': 132 | servo_command = 'lookleft' 133 | servo_move.resume() 134 | 135 | elif data_input == 'lookRightStart\n': 136 | servo_command = 'lookright' 137 | servo_move.resume() 138 | 139 | elif data_input == 'downStart\n': 140 | servo_command = 'down' 141 | servo_move.resume() 142 | 143 | elif data_input == 'upStart\n': 144 | servo_command = 'up' 145 | servo_move.resume() 146 | 147 | elif 'lookLeftStop' in data_input: 148 | servo_move.pause() 149 | servo_command = 'no' 150 | elif 'lookRightStop' in data_input: 151 | servo_move.pause() 152 | servo_command = 'no' 153 | elif 'downStop' in data_input: 154 | servo_move.pause() 155 | servo_command = 'no' 156 | elif 'upStop' in data_input: 157 | servo_move.pause() 158 | servo_command = 'no' 159 | 160 | 161 | if data_input == 'aStart\n': 162 | servo_command = 'grab' 163 | servo_move.resume() 164 | 165 | elif data_input == 'bStart\n': 166 | servo_command = 'loose' 167 | servo_move.resume() 168 | 169 | elif data_input == 'cStart\n': 170 | switch.switch(1,1) 171 | switch.switch(2,1) 172 | switch.switch(3,1) 173 | 174 | elif data_input == 'dStart\n': 175 | switch.switch(1,0) 176 | switch.switch(2,0) 177 | switch.switch(3,0) 178 | 179 | elif 'aStop' in data_input: 180 | servo_move.pause() 181 | servo_command = 'no' 182 | elif 'bStop' in data_input: 183 | servo_move.pause() 184 | servo_command = 'no' 185 | elif 'cStop' in data_input: 186 | pass 187 | elif 'dStop' in data_input: 188 | pass 189 | 190 | print(data_input) 191 | 192 | def appconnect(): 193 | global AppCliSock, AppAddr 194 | try: 195 | s =socket.socket(socket.AF_INET,socket.SOCK_DGRAM) 196 | s.connect(("1.1.1.1",80)) 197 | ipaddr_check=s.getsockname()[0] 198 | s.close() 199 | print(ipaddr_check) 200 | 201 | AppSerSock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 202 | AppSerSock.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1) 203 | AppSerSock.bind(app_ADDR) 204 | AppSerSock.listen(5) 205 | print('waiting for App connection...') 206 | AppCliSock, AppAddr = AppSerSock.accept() 207 | print('...App connected from :', AppAddr) 208 | except: 209 | ap_threading=threading.Thread(target=ap_thread) #Define a thread for data receiving 210 | ap_threading.setDaemon(True) #'True' means it is a front thread,it would close when the mainloop() closes 211 | ap_threading.start() #Thread starts 212 | 213 | LED.colorWipe(0,16,50) 214 | time.sleep(1) 215 | LED.colorWipe(0,16,100) 216 | time.sleep(1) 217 | LED.colorWipe(0,16,150) 218 | time.sleep(1) 219 | LED.colorWipe(0,16,200) 220 | time.sleep(1) 221 | LED.colorWipe(0,16,255) 222 | time.sleep(1) 223 | LED.colorWipe(35,255,35) 224 | 225 | AppSerSock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 226 | AppSerSock.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1) 227 | AppSerSock.bind(app_ADDR) 228 | AppSerSock.listen(5) 229 | print('waiting for App connection...') 230 | AppCliSock, AppAddr = AppSerSock.accept() 231 | print('...App connected from :', AppAddr) 232 | 233 | appconnect() 234 | setup() 235 | app_threading=threading.Thread(target=appconnect) #Define a thread for FPV and OpenCV 236 | app_threading.setDaemon(True) #'True' means it is a front thread,it would close when the mainloop() closes 237 | app_threading.start() #Thread starts 238 | 239 | while 1: 240 | data = '' 241 | data = str(AppCliSock.recv(app_BUFSIZ).decode()) 242 | if not data: 243 | continue 244 | appCommand(data) 245 | pass 246 | 247 | AppConntect_threading=threading.Thread(target=app_ctrl) #Define a thread for FPV and OpenCV 248 | AppConntect_threading.setDaemon(True) #'True' means it is a front thread,it would close when the mainloop() closes 249 | AppConntect_threading.start() #Thread starts 250 | 251 | if __name__ == '__main__': 252 | i = 1 253 | try: 254 | while 1: 255 | i += 1 256 | print(i) 257 | time.sleep(30) 258 | pass 259 | except: 260 | servo_move.stop() 261 | move.move(0, 'no', 'no', rad) 262 | LED.colorWipe(0,0,0) -------------------------------------------------------------------------------- /server/RPIservo.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # File name : servo.py 3 | # Description : Control Servos 4 | # Author : William 5 | # Date : 2019/02/23 6 | from __future__ import division 7 | import time 8 | import RPi.GPIO as GPIO 9 | import sys 10 | import Adafruit_PCA9685 11 | import threading 12 | 13 | import random 14 | ''' 15 | change this form 1 to -1 to reverse servos 16 | ''' 17 | pwm = Adafruit_PCA9685.PCA9685(address=0x40, busnum=1) 18 | pwm.set_pwm_freq(50) 19 | 20 | init_pwm0 = 300 21 | init_pwm1 = 300 22 | init_pwm2 = 300 23 | init_pwm3 = 300 24 | 25 | init_pwm4 = 300 26 | init_pwm5 = 300 27 | init_pwm6 = 300 28 | init_pwm7 = 300 29 | 30 | init_pwm8 = 300 31 | init_pwm9 = 300 32 | init_pwm10 = 300 33 | init_pwm11 = 300 34 | 35 | init_pwm12 = 300 36 | init_pwm13 = 300 37 | init_pwm14 = 300 38 | init_pwm15 = 300 39 | 40 | class ServoCtrl(threading.Thread): 41 | 42 | def __init__(self, *args, **kwargs): 43 | self.sc_direction = [1,1,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,1] 44 | self.initPos = [init_pwm0,init_pwm1,init_pwm2,init_pwm3, 45 | init_pwm4,init_pwm5,init_pwm6,init_pwm7, 46 | init_pwm8,init_pwm9,init_pwm10,init_pwm11, 47 | init_pwm12,init_pwm13,init_pwm14,init_pwm15] 48 | self.goalPos = [300,300,300,300, 300,300,300,300 ,300,300,300,300 ,300,300,300,300] 49 | self.nowPos = [300,300,300,300, 300,300,300,300 ,300,300,300,300 ,300,300,300,300] 50 | self.bufferPos = [300.0,300.0,300.0,300.0, 300.0,300.0,300.0,300.0 ,300.0,300.0,300.0,300.0 ,300.0,300.0,300.0,300.0] 51 | self.lastPos = [300,300,300,300, 300,300,300,300 ,300,300,300,300 ,300,300,300,300] 52 | self.ingGoal = [300,300,300,300, 300,300,300,300 ,300,300,300,300 ,300,300,300,300] 53 | # self.maxPos = [560,560,560,560, 560,560,560,560 ,560,560,560,560 ,560,560,560,560] 54 | self.maxPos = [520,520,520,520, 520,520,520,520 ,520,520,520,520 ,520,520,520,520] 55 | self.minPos = [100,100,100,100, 100,100,100,100 ,100,100,100,100 ,100,100,100,100] 56 | self.scSpeed = [0,0,0,0, 0,0,0,0 ,0,0,0,0 ,0,0,0,0] 57 | 58 | # self.ctrlRangeMax = 560 59 | self.ctrlRangeMax = 520 60 | self.ctrlRangeMin = 100 61 | self.angleRange = 180 62 | 63 | ''' 64 | scMode: 'init' 'auto' 'certain' 'quick' 'wiggle' 65 | ''' 66 | self.scMode = 'auto' 67 | self.scTime = 2.0 68 | self.scSteps = 30 69 | 70 | self.scDelay = 0.037 71 | self.scMoveTime = 0.037 72 | 73 | self.goalUpdate = 0 74 | self.wiggleID = 0 75 | self.wiggleDirection = 1 76 | 77 | super(ServoCtrl, self).__init__(*args, **kwargs) 78 | self.__flag = threading.Event() 79 | self.__flag.clear() 80 | 81 | 82 | def pause(self): 83 | print('......................pause..........................') 84 | self.__flag.clear() 85 | 86 | 87 | def resume(self): 88 | print('resume') 89 | self.__flag.set() 90 | 91 | 92 | def moveInit(self): 93 | self.scMode = 'init' 94 | for i in range(0,16): 95 | pwm.set_pwm(i,0,self.initPos[i]) 96 | self.lastPos[i] = self.initPos[i] 97 | self.nowPos[i] = self.initPos[i] 98 | self.bufferPos[i] = float(self.initPos[i]) 99 | self.goalPos[i] = self.initPos[i] 100 | self.pause() 101 | 102 | 103 | def initConfig(self, ID, initInput, moveTo): 104 | if initInput > self.minPos[ID] and initInput < self.maxPos[ID]: 105 | self.initPos[ID] = initInput 106 | if moveTo: 107 | pwm.set_pwm(ID,0,self.initPos[ID]) 108 | else: 109 | print('initPos Value Error.') 110 | 111 | 112 | def moveServoInit(self, ID): 113 | self.scMode = 'init' 114 | for i in range(0,len(ID)): 115 | pwm.set_pwm(ID[i], 0, self.initPos[ID[i]]) 116 | self.lastPos[ID[i]] = self.initPos[ID[i]] 117 | self.nowPos[ID[i]] = self.initPos[ID[i]] 118 | self.bufferPos[ID[i]] = float(self.initPos[ID[i]]) 119 | self.goalPos[ID[i]] = self.initPos[ID[i]] 120 | self.pause() 121 | 122 | 123 | def posUpdate(self): 124 | self.goalUpdate = 1 125 | for i in range(0,16): 126 | self.lastPos[i] = self.nowPos[i] 127 | self.goalUpdate = 0 128 | 129 | 130 | def speedUpdate(self, IDinput, speedInput): 131 | for i in range(0,len(IDinput)): 132 | self.scSpeed[IDinput[i]] = speedInput[i] 133 | 134 | 135 | def moveAuto(self): 136 | for i in range(0,16): 137 | self.ingGoal[i] = self.goalPos[i] 138 | 139 | for i in range(0, self.scSteps): 140 | for dc in range(0,16): 141 | if not self.goalUpdate: 142 | self.nowPos[dc] = int(round((self.lastPos[dc] + (((self.goalPos[dc] - self.lastPos[dc])/self.scSteps)*(i+1))),0)) 143 | pwm.set_pwm(dc, 0, self.nowPos[dc]) 144 | 145 | if self.ingGoal != self.goalPos: 146 | self.posUpdate() 147 | time.sleep(self.scTime/self.scSteps) 148 | return 1 149 | time.sleep((self.scTime/self.scSteps - self.scMoveTime)) 150 | 151 | self.posUpdate() 152 | self.pause() 153 | return 0 154 | 155 | 156 | def moveCert(self): 157 | for i in range(0,16): 158 | self.ingGoal[i] = self.goalPos[i] 159 | self.bufferPos[i] = self.lastPos[i] 160 | 161 | while self.nowPos != self.goalPos: 162 | for i in range(0,16): 163 | if self.lastPos[i] < self.goalPos[i]: 164 | self.bufferPos[i] += self.pwmGenOut(self.scSpeed[i])/(1/self.scDelay) 165 | newNow = int(round(self.bufferPos[i], 0)) 166 | if newNow > self.goalPos[i]:newNow = self.goalPos[i] 167 | self.nowPos[i] = newNow 168 | elif self.lastPos[i] > self.goalPos[i]: 169 | self.bufferPos[i] -= self.pwmGenOut(self.scSpeed[i])/(1/self.scDelay) 170 | newNow = int(round(self.bufferPos[i], 0)) 171 | if newNow < self.goalPos[i]:newNow = self.goalPos[i] 172 | self.nowPos[i] = newNow 173 | 174 | if not self.goalUpdate: 175 | pwm.set_pwm(i, 0, self.nowPos[i]) 176 | 177 | if self.ingGoal != self.goalPos: 178 | self.posUpdate() 179 | return 1 180 | self.posUpdate() 181 | time.sleep(self.scDelay-self.scMoveTime) 182 | 183 | else: 184 | self.pause() 185 | return 0 186 | 187 | 188 | def pwmGenOut(self, angleInput): 189 | return int(round(((self.ctrlRangeMax-self.ctrlRangeMin)/self.angleRange*angleInput),0)) 190 | 191 | 192 | def setAutoTime(self, autoSpeedSet): 193 | self.scTime = autoSpeedSet 194 | 195 | 196 | def setDelay(self, delaySet): 197 | self.scDelay = delaySet 198 | 199 | 200 | def autoSpeed(self, ID, angleInput): 201 | self.scMode = 'auto' 202 | self.goalUpdate = 1 203 | for i in range(0,len(ID)): 204 | newGoal = self.initPos[ID[i]] + self.pwmGenOut(angleInput[i])*self.sc_direction[ID[i]] 205 | if newGoal>self.maxPos[ID[i]]:newGoal=self.maxPos[ID[i]] 206 | elif newGoalself.maxPos[ID[i]]:newGoal=self.maxPos[ID[i]] 218 | elif newGoal self.maxPos[self.wiggleID]:self.bufferPos[self.wiggleID] = self.maxPos[self.wiggleID] 229 | elif self.bufferPos[self.wiggleID] < self.minPos[self.wiggleID]:self.bufferPos[self.wiggleID] = self.minPos[self.wiggleID] 230 | self.nowPos[self.wiggleID] = newNow 231 | self.lastPos[self.wiggleID] = newNow 232 | if self.bufferPos[self.wiggleID] < self.maxPos[self.wiggleID] and self.bufferPos[self.wiggleID] > self.minPos[self.wiggleID]: 233 | pwm.set_pwm(self.wiggleID, 0, self.nowPos[self.wiggleID]) 234 | else: 235 | self.stopWiggle() 236 | time.sleep(self.scDelay-self.scMoveTime) 237 | 238 | 239 | def stopWiggle(self): 240 | self.pause() 241 | self.posUpdate() 242 | 243 | 244 | def singleServo(self, ID, direcInput, speedSet): 245 | self.wiggleID = ID 246 | self.wiggleDirection = direcInput 247 | self.scSpeed[ID] = speedSet 248 | self.scMode = 'wiggle' 249 | self.posUpdate() 250 | self.resume() 251 | 252 | 253 | def moveAngle(self, ID, angleInput): 254 | self.nowPos[ID] = int(self.initPos[ID] + self.sc_direction[ID]*self.pwmGenOut(angleInput)) 255 | if self.nowPos[ID] > self.maxPos[ID]:self.nowPos[ID] = self.maxPos[ID] 256 | elif self.nowPos[ID] < self.minPos[ID]:self.nowPos[ID] = self.minPos[ID] 257 | self.lastPos[ID] = self.nowPos[ID] 258 | pwm.set_pwm(ID, 0, self.nowPos[ID]) 259 | 260 | 261 | def scMove(self): 262 | if self.scMode == 'init': 263 | self.moveInit() 264 | elif self.scMode == 'auto': 265 | self.moveAuto() 266 | elif self.scMode == 'certain': 267 | self.moveCert() 268 | elif self.scMode == 'wiggle': 269 | self.moveWiggle() 270 | 271 | 272 | def setPWM(self, ID, PWM_input): 273 | self.lastPos[ID] = PWM_input 274 | self.nowPos[ID] = PWM_input 275 | self.bufferPos[ID] = float(PWM_input) 276 | self.goalPos[ID] = PWM_input 277 | pwm.set_pwm(ID, 0, PWM_input) 278 | self.pause() 279 | 280 | 281 | def run(self): 282 | while 1: 283 | self.__flag.wait() 284 | self.scMove() 285 | pass 286 | 287 | 288 | if __name__ == '__main__': 289 | sc = ServoCtrl() 290 | sc.start() 291 | while 1: 292 | sc.moveAngle(0,(random.random()*100-50)) 293 | time.sleep(1) 294 | sc.moveAngle(1,(random.random()*100-50)) 295 | time.sleep(1) 296 | ''' 297 | sc.singleServo(0, 1, 5) 298 | time.sleep(6) 299 | sc.singleServo(0, -1, 30) 300 | time.sleep(1) 301 | ''' 302 | ''' 303 | delaytime = 5 304 | sc.certSpeed([0,7], [60,0], [40,60]) 305 | print('xx1xx') 306 | time.sleep(delaytime) 307 | 308 | sc.certSpeed([0,7], [0,60], [40,60]) 309 | print('xx2xx') 310 | time.sleep(delaytime+2) 311 | 312 | # sc.moveServoInit([0]) 313 | # time.sleep(delaytime) 314 | ''' 315 | ''' 316 | pwm.set_pwm(0,0,560) 317 | time.sleep(1) 318 | pwm.set_pwm(0,0,100) 319 | time.sleep(2) 320 | ''' 321 | pass 322 | pass 323 | -------------------------------------------------------------------------------- /server/dist/img/icons/safari-pinned-tab.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 7 | 8 | Created by potrace 1.11, written by Peter Selinger 2001-2013 9 | 10 | 12 | 148 | 149 | 150 | -------------------------------------------------------------------------------- /server/server.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env/python 2 | # File name : server.py 3 | # Production : RaspTank 4 | # Website : www.adeept.com 5 | # E-mail : support@adeept.com 6 | # Author : William 7 | # Date : 2018/08/22 8 | 9 | import socket 10 | import time 11 | import threading 12 | import move 13 | import Adafruit_PCA9685 14 | pwm = Adafruit_PCA9685.PCA9685() 15 | pwm.set_pwm_freq(50) 16 | pwm.set_all_pwm(0,300) 17 | from rpi_ws281x import * 18 | import argparse 19 | import os 20 | import ultra 21 | import FPV 22 | import psutil 23 | import servo 24 | import LED 25 | import findline 26 | 27 | step_set = 1 28 | speed_set = 100 29 | rad = 0.6 30 | 31 | new_frame = 0 32 | direction_command = 'no' 33 | turn_command = 'no' 34 | #pwm = Adafruit_PCA9685.PCA9685() 35 | #pwm.set_pwm_freq(50) 36 | pos_input = 1 37 | catch_input = 1 38 | cir_input = 6 39 | 40 | ultrasonicMode = 0 41 | FindLineMode = 0 42 | FindColorMode = 0 43 | 44 | 45 | def app_ctrl(): 46 | app_HOST = '' 47 | app_PORT = 10123 48 | app_BUFSIZ = 1024 49 | app_ADDR = (app_HOST, app_PORT) 50 | 51 | AppSerSock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 52 | AppSerSock.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1) 53 | AppSerSock.bind(app_ADDR) 54 | 55 | def setup(): 56 | move.setup() 57 | 58 | def appCommand(data_input): 59 | global direction_command, turn_command, pos_input, catch_input, cir_input 60 | if data_input == 'forwardStart\n': 61 | direction_command = 'forward' 62 | move.move(speed_set, direction_command, turn_command, rad) 63 | 64 | elif data_input == 'backwardStart\n': 65 | direction_command = 'backward' 66 | move.move(speed_set, direction_command, turn_command, rad) 67 | 68 | elif data_input == 'leftStart\n': 69 | turn_command = 'left' 70 | move.move(speed_set, direction_command, turn_command, rad) 71 | 72 | elif data_input == 'rightStart\n': 73 | turn_command = 'right' 74 | move.move(speed_set, direction_command, turn_command, rad) 75 | 76 | elif 'forwardStop' in data_input: 77 | direction_command = 'no' 78 | move.move(speed_set, direction_command, turn_command, rad) 79 | 80 | elif 'backwardStop' in data_input: 81 | direction_command = 'no' 82 | move.move(speed_set, direction_command, turn_command, rad) 83 | 84 | elif 'leftStop' in data_input: 85 | turn_command = 'no' 86 | move.move(speed_set, direction_command, turn_command, rad) 87 | 88 | elif 'rightStop' in data_input: 89 | turn_command = 'no' 90 | move.move(speed_set, direction_command, turn_command, rad) 91 | 92 | 93 | if data_input == 'lookLeftStart\n': 94 | if cir_input < 12: 95 | cir_input+=1 96 | servo.cir_pos(cir_input) 97 | 98 | elif data_input == 'lookRightStart\n': 99 | if cir_input > 1: 100 | cir_input-=1 101 | servo.cir_pos(cir_input) 102 | 103 | elif data_input == 'downStart\n': 104 | servo.camera_ang('lookdown',10) 105 | 106 | elif data_input == 'upStart\n': 107 | servo.camera_ang('lookup',10) 108 | 109 | elif 'lookLeftStop' in data_input: 110 | pass 111 | elif 'lookRightStop' in data_input: 112 | pass 113 | elif 'downStop' in data_input: 114 | pass 115 | elif 'upStop' in data_input: 116 | pass 117 | 118 | 119 | if data_input == 'aStart\n': 120 | if pos_input < 17: 121 | pos_input+=1 122 | servo.hand_pos(pos_input) 123 | 124 | elif data_input == 'bStart\n': 125 | if pos_input > 1: 126 | pos_input-=1 127 | servo.hand_pos(pos_input) 128 | 129 | elif data_input == 'cStart\n': 130 | if catch_input < 13: 131 | catch_input+=3 132 | servo.catch(catch_input) 133 | 134 | elif data_input == 'dStart\n': 135 | if catch_input > 1: 136 | catch_input-=3 137 | servo.catch(catch_input) 138 | 139 | elif 'aStop' in data_input: 140 | pass 141 | elif 'bStop' in data_input: 142 | pass 143 | elif 'cStop' in data_input: 144 | pass 145 | elif 'dStop' in data_input: 146 | pass 147 | 148 | print(data_input) 149 | 150 | def appconnect(): 151 | global AppCliSock, AppAddr 152 | AppSerSock.listen(5) 153 | print('waiting for App connection...') 154 | AppCliSock, AppAddr = AppSerSock.accept() 155 | print('...App connected from :', AppAddr) 156 | 157 | appconnect() 158 | setup() 159 | app_threading=threading.Thread(target=appconnect) #Define a thread for FPV and OpenCV 160 | app_threading.setDaemon(True) #'True' means it is a front thread,it would close when the mainloop() closes 161 | app_threading.start() #Thread starts 162 | 163 | while 1: 164 | data = '' 165 | data = str(AppCliSock.recv(app_BUFSIZ).decode()) 166 | if not data: 167 | continue 168 | appCommand(data) 169 | pass 170 | 171 | AppConntect_threading=threading.Thread(target=app_ctrl) #Define a thread for FPV and OpenCV 172 | AppConntect_threading.setDaemon(True) #'True' means it is a front thread,it would close when the mainloop() closes 173 | AppConntect_threading.start() #Thread starts 174 | 175 | 176 | def findline_thread(): #Line tracking mode 177 | while 1: 178 | while FindLineMode: 179 | findline.run() 180 | time.sleep(0.2) 181 | 182 | def get_cpu_tempfunc(): 183 | """ Return CPU temperature """ 184 | result = 0 185 | mypath = "/sys/class/thermal/thermal_zone0/temp" 186 | with open(mypath, 'r') as mytmpfile: 187 | for line in mytmpfile: 188 | result = line 189 | 190 | result = float(result)/1000 191 | result = round(result, 1) 192 | return str(result) 193 | 194 | 195 | def get_gpu_tempfunc(): 196 | """ Return GPU temperature as a character string""" 197 | res = os.popen('/opt/vc/bin/vcgencmd measure_temp').readline() 198 | return res.replace("temp=", "") 199 | 200 | 201 | def get_cpu_use(): 202 | """ Return CPU usage using psutil""" 203 | cpu_cent = psutil.cpu_percent() 204 | return str(cpu_cent) 205 | 206 | 207 | def get_ram_info(): 208 | """ Return RAM usage using psutil """ 209 | ram_cent = psutil.virtual_memory()[2] 210 | return str(ram_cent) 211 | 212 | 213 | def get_swap_info(): 214 | """ Return swap memory usage using psutil """ 215 | swap_cent = psutil.swap_memory()[3] 216 | return str(swap_cent) 217 | 218 | 219 | def info_get(): 220 | global cpu_t,cpu_u,gpu_t,ram_info 221 | while 1: 222 | cpu_t = get_cpu_tempfunc() 223 | cpu_u = get_cpu_use() 224 | ram_info = get_ram_info() 225 | time.sleep(3) 226 | 227 | 228 | def info_send_client(): 229 | SERVER_IP = addr[0] 230 | SERVER_PORT = 2256 #Define port serial 231 | SERVER_ADDR = (SERVER_IP, SERVER_PORT) 232 | Info_Socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) #Set connection value for socket 233 | Info_Socket.connect(SERVER_ADDR) 234 | print(SERVER_ADDR) 235 | while 1: 236 | try: 237 | Info_Socket.send((get_cpu_tempfunc()+' '+get_cpu_use()+' '+get_ram_info()).encode()) 238 | time.sleep(1) 239 | except: 240 | pass 241 | 242 | 243 | def ultra_send_client(): 244 | ultra_IP = addr[0] 245 | ultra_PORT = 2257 #Define port serial 246 | ultra_ADDR = (ultra_IP, ultra_PORT) 247 | ultra_Socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) #Set connection value for socket 248 | ultra_Socket.connect(ultra_ADDR) 249 | print(ultra_ADDR) 250 | while 1: 251 | while ultrasonicMode: 252 | try: 253 | if not FindColorMode: 254 | ultra_Socket.send(str(round(ultra.checkdist(),2)).encode()) 255 | time.sleep(0.5) 256 | continue 257 | fpv.UltraData(round(ultra.checkdist(),2)) 258 | time.sleep(0.2) 259 | except: 260 | pass 261 | time.sleep(0.5) 262 | 263 | 264 | def FPV_thread(): 265 | fpv=FPV.FPV() 266 | fpv.capture_thread(addr[0]) 267 | 268 | 269 | def ap_thread(): 270 | os.system("sudo create_ap wlan0 eth0 AdeeptCar 12345678") 271 | 272 | 273 | def run(): 274 | global direction_command, turn_command, pos_input, catch_input, cir_input, ultrasonicMode, FindLineMode, FindColorMode 275 | move.setup() 276 | findline.setup() 277 | 278 | info_threading=threading.Thread(target=info_send_client) #Define a thread for FPV and OpenCV 279 | info_threading.setDaemon(True) #'True' means it is a front thread,it would close when the mainloop() closes 280 | info_threading.start() #Thread starts 281 | 282 | ultra_threading=threading.Thread(target=ultra_send_client) #Define a thread for FPV and OpenCV 283 | ultra_threading.setDaemon(True) #'True' means it is a front thread,it would close when the mainloop() closes 284 | ultra_threading.start() #Thread starts 285 | 286 | findline_threading=threading.Thread(target=findline_thread) #Define a thread for FPV and OpenCV 287 | findline_threading.setDaemon(True) #'True' means it is a front thread,it would close when the mainloop() closes 288 | findline_threading.start() #Thread starts 289 | #move.stand() 290 | 291 | ws_R = 0 292 | ws_G = 0 293 | ws_B = 0 294 | 295 | Y_pitch = 0 296 | Y_pitch_MAX = 200 297 | Y_pitch_MIN = -200 298 | 299 | while True: 300 | data = '' 301 | data = str(tcpCliSock.recv(BUFSIZ).decode()) 302 | if not data: 303 | continue 304 | elif 'forward' == data: 305 | direction_command = 'forward' 306 | move.move(speed_set, direction_command, turn_command, rad) 307 | elif 'backward' == data: 308 | direction_command = 'backward' 309 | move.move(speed_set, direction_command, turn_command, rad) 310 | elif 'DS' in data: 311 | direction_command = 'no' 312 | move.move(speed_set, direction_command, turn_command, rad) 313 | 314 | elif 'left' == data: 315 | turn_command = 'left' 316 | move.move(speed_set, direction_command, turn_command, rad) 317 | elif 'right' == data: 318 | turn_command = 'right' 319 | move.move(speed_set, direction_command, turn_command, rad) 320 | elif 'TS' in data: 321 | turn_command = 'no' 322 | move.move(speed_set, direction_command, turn_command, rad) 323 | 324 | elif 'out' == data: 325 | if pos_input < 17: 326 | pos_input+=1 327 | servo.hand_pos(pos_input) 328 | elif 'in' == data: 329 | if pos_input > 1: 330 | pos_input-=1 331 | servo.hand_pos(pos_input) 332 | 333 | elif 'headup' == data: 334 | servo.camera_ang('lookup',0) 335 | elif 'headdown' == data: 336 | servo.camera_ang('lookdown',0) 337 | elif 'headhome' == data: 338 | servo.initPosAll() 339 | 340 | elif 'c_left' == data: 341 | if cir_input < 12: 342 | cir_input+=1 343 | servo.cir_pos(cir_input) 344 | elif 'c_right' == data: 345 | if cir_input > 1: 346 | cir_input-=1 347 | servo.cir_pos(cir_input) 348 | 349 | elif 'catch' == data: 350 | if catch_input < 13: 351 | catch_input+=1 352 | servo.catch(catch_input) 353 | elif 'loose' == data: 354 | if catch_input > 1: 355 | catch_input-=1 356 | servo.catch(catch_input) 357 | 358 | elif 'wsR' in data: 359 | try: 360 | set_R=data.split() 361 | ws_R = int(set_R[1]) 362 | LED.colorWipe(ws_R,ws_G,ws_B) 363 | except: 364 | pass 365 | elif 'wsG' in data: 366 | try: 367 | set_G=data.split() 368 | ws_G = int(set_G[1]) 369 | LED.colorWipe(ws_R,ws_G,ws_B) 370 | except: 371 | pass 372 | elif 'wsB' in data: 373 | try: 374 | set_B=data.split() 375 | ws_B = int(set_B[1]) 376 | LED.colorWipe(ws_R,ws_G,ws_B) 377 | except: 378 | pass 379 | 380 | elif 'FindColor' in data: 381 | fpv.FindColor(1) 382 | FindColorMode = 1 383 | ultrasonicMode = 1 384 | tcpCliSock.send(('FindColor').encode()) 385 | 386 | elif 'WatchDog' in data: 387 | fpv.WatchDog(1) 388 | tcpCliSock.send(('WatchDog').encode()) 389 | 390 | elif 'steady' in data: 391 | ultrasonicMode = 1 392 | tcpCliSock.send(('steady').encode()) 393 | 394 | elif 'FindLine' in data: 395 | FindLineMode = 1 396 | tcpCliSock.send(('FindLine').encode()) 397 | 398 | elif 'funEnd' in data: 399 | fpv.FindColor(0) 400 | fpv.WatchDog(0) 401 | ultrasonicMode = 0 402 | FindLineMode = 0 403 | FindColorMode = 0 404 | tcpCliSock.send(('FunEnd').encode()) 405 | move.motorStop() 406 | time.sleep(0.3) 407 | move.motorStop() 408 | 409 | else: 410 | pass 411 | #print(data) 412 | 413 | 414 | if __name__ == '__main__': 415 | 416 | HOST = '' 417 | PORT = 10223 #Define port serial 418 | BUFSIZ = 1024 #Define buffer size 419 | ADDR = (HOST, PORT) 420 | pwm.set_all_pwm(0,300) 421 | 422 | try: 423 | LED = LED.LED() 424 | LED.colorWipe(Color(255,16,0)) 425 | except ModuleNotFoundError as e: 426 | print('Use "sudo pip3 install rpi_ws281x" to install WS_281x package') 427 | pass 428 | 429 | while 1: 430 | try: 431 | s =socket.socket(socket.AF_INET,socket.SOCK_DGRAM) 432 | s.connect(("1.1.1.1",80)) 433 | ipaddr_check=s.getsockname()[0] 434 | s.close() 435 | print(ipaddr_check) 436 | except: 437 | ap_threading=threading.Thread(target=ap_thread) #Define a thread for data receiving 438 | ap_threading.setDaemon(True) #'True' means it is a front thread,it would close when the mainloop() closes 439 | ap_threading.start() #Thread starts 440 | 441 | LED.colorWipe(0,16,50) 442 | time.sleep(1) 443 | LED.colorWipe(0,16,100) 444 | time.sleep(1) 445 | LED.colorWipe(0,16,150) 446 | time.sleep(1) 447 | LED.colorWipe(0,16,200) 448 | time.sleep(1) 449 | LED.colorWipe(0,16,255) 450 | time.sleep(1) 451 | LED.colorWipe(35,255,35) 452 | 453 | try: 454 | tcpSerSock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 455 | tcpSerSock.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1) 456 | tcpSerSock.bind(ADDR) 457 | tcpSerSock.listen(5) #Start server,waiting for client 458 | print('waiting for connection...') 459 | tcpCliSock, addr = tcpSerSock.accept() 460 | print('...connected from :', addr) 461 | 462 | fpv=FPV.FPV() 463 | fps_threading=threading.Thread(target=FPV_thread) #Define a thread for FPV and OpenCV 464 | fps_threading.setDaemon(True) #'True' means it is a front thread,it would close when the mainloop() closes 465 | fps_threading.start() #Thread starts 466 | break 467 | except: 468 | LED.colorWipe(0,0,0) 469 | 470 | try: 471 | LED.colorWipe(0,80,255) 472 | except: 473 | pass 474 | run() 475 | try: 476 | pwm.set_all_pwm(0,0) 477 | run() 478 | except: 479 | LED.colorWipe(0,0,0) 480 | servo.clean_all() 481 | move.destroy() 482 | -------------------------------------------------------------------------------- /server/webServer.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env/python 2 | # File name : server.py 3 | # Production : GWR 4 | # Website : www.adeept.com 5 | # Author : William 6 | # Date : 2020/03/17 7 | 8 | import time 9 | import threading 10 | import move 11 | import os 12 | import info 13 | import RPIservo 14 | 15 | import functions 16 | import robotLight 17 | import switch 18 | import socket 19 | 20 | #websocket 21 | import asyncio 22 | import websockets 23 | 24 | import json 25 | import app 26 | 27 | OLED_connection = 1 28 | try: 29 | import OLED 30 | screen = OLED.OLED_ctrl() 31 | screen.start() 32 | screen.screen_show(1, 'ADEEPT.COM') 33 | except: 34 | OLED_connection = 0 35 | print('OLED disconnected') 36 | pass 37 | 38 | functionMode = 0 39 | speed_set = 100 40 | rad = 0.5 41 | turnWiggle = 60 42 | 43 | scGear = RPIservo.ServoCtrl() 44 | scGear.moveInit() 45 | 46 | P_sc = RPIservo.ServoCtrl() 47 | P_sc.start() 48 | 49 | T_sc = RPIservo.ServoCtrl() 50 | T_sc.start() 51 | 52 | H1_sc = RPIservo.ServoCtrl() 53 | H1_sc.start() 54 | 55 | H2_sc = RPIservo.ServoCtrl() 56 | H2_sc.start() 57 | 58 | G_sc = RPIservo.ServoCtrl() 59 | G_sc.start() 60 | 61 | # modeSelect = 'none' 62 | modeSelect = 'PT' 63 | 64 | init_pwm0 = scGear.initPos[0] 65 | init_pwm1 = scGear.initPos[1] 66 | init_pwm2 = scGear.initPos[2] 67 | init_pwm3 = scGear.initPos[3] 68 | init_pwm4 = scGear.initPos[4] 69 | 70 | fuc = functions.Functions() 71 | fuc.start() 72 | 73 | curpath = os.path.realpath(__file__) 74 | thisPath = "/" + os.path.dirname(curpath) 75 | 76 | direction_command = 'no' 77 | turn_command = 'no' 78 | 79 | def servoPosInit(): 80 | scGear.initConfig(0,init_pwm0,1) 81 | P_sc.initConfig(1,init_pwm1,1) 82 | T_sc.initConfig(2,init_pwm2,1) 83 | H1_sc.initConfig(3,init_pwm3,1) 84 | G_sc.initConfig(4,init_pwm4,1) 85 | 86 | 87 | def replace_num(initial,new_num): #Call this function to replace data in '.txt' file 88 | global r 89 | newline="" 90 | str_num=str(new_num) 91 | with open(thisPath+"/RPIservo.py","r") as f: 92 | for line in f.readlines(): 93 | if(line.find(initial) == 0): 94 | line = initial+"%s" %(str_num+"\n") 95 | newline += line 96 | with open(thisPath+"/RPIservo.py","w") as f: 97 | f.writelines(newline) 98 | 99 | 100 | def ap_thread(): 101 | os.system("sudo create_ap wlan0 eth0 Adeept 12345678") 102 | 103 | 104 | def functionSelect(command_input, response): 105 | global functionMode 106 | if 'scan' == command_input: 107 | if OLED_connection: 108 | screen.screen_show(5,'SCANNING') 109 | if modeSelect == 'PT': 110 | radar_send = fuc.radarScan() 111 | print(radar_send) 112 | response['title'] = 'scanResult' 113 | response['data'] = radar_send 114 | time.sleep(0.3) 115 | 116 | elif 'findColor' == command_input: 117 | if OLED_connection: 118 | screen.screen_show(5,'FindColor') 119 | if modeSelect == 'PT': 120 | flask_app.modeselect('findColor') 121 | 122 | elif 'motionGet' == command_input: 123 | if OLED_connection: 124 | screen.screen_show(5,'MotionGet') 125 | flask_app.modeselect('watchDog') 126 | 127 | elif 'stopCV' == command_input: 128 | flask_app.modeselect('none') 129 | switch.switch(1,0) 130 | switch.switch(2,0) 131 | switch.switch(3,0) 132 | 133 | elif 'police' == command_input: 134 | if OLED_connection: 135 | screen.screen_show(5,'POLICE') 136 | RL.police() 137 | 138 | elif 'policeOff' == command_input: 139 | RL.pause() 140 | move.motorStop() 141 | 142 | elif 'automatic' == command_input: 143 | if OLED_connection: 144 | screen.screen_show(5,'Automatic') 145 | if modeSelect == 'PT': 146 | fuc.automatic() 147 | else: 148 | fuc.pause() 149 | 150 | elif 'automaticOff' == command_input: 151 | fuc.pause() 152 | move.motorStop() 153 | 154 | elif 'trackLine' == command_input: 155 | fuc.trackLine() 156 | if OLED_connection: 157 | screen.screen_show(5,'TrackLine') 158 | 159 | elif 'trackLineOff' == command_input: 160 | fuc.pause() 161 | move.motorStop() 162 | 163 | elif 'steadyCamera' == command_input: 164 | if OLED_connection: 165 | screen.screen_show(5,'SteadyCamera') 166 | fuc.steady(T_sc.lastPos[2]) 167 | 168 | elif 'steadyCameraOff' == command_input: 169 | fuc.pause() 170 | move.motorStop() 171 | 172 | 173 | def switchCtrl(command_input, response): 174 | if 'Switch_1_on' in command_input: 175 | switch.switch(1,1) 176 | 177 | elif 'Switch_1_off' in command_input: 178 | switch.switch(1,0) 179 | 180 | elif 'Switch_2_on' in command_input: 181 | switch.switch(2,1) 182 | 183 | elif 'Switch_2_off' in command_input: 184 | switch.switch(2,0) 185 | 186 | elif 'Switch_3_on' in command_input: 187 | switch.switch(3,1) 188 | 189 | elif 'Switch_3_off' in command_input: 190 | switch.switch(3,0) 191 | 192 | 193 | def robotCtrl(command_input, response): 194 | global direction_command, turn_command 195 | if 'forward' == command_input: 196 | direction_command = 'forward' 197 | move.move(speed_set, 'forward', 'no', rad) 198 | 199 | elif 'backward' == command_input: 200 | direction_command = 'backward' 201 | move.move(speed_set, 'backward', 'no', rad) 202 | 203 | elif 'DS' in command_input: 204 | direction_command = 'no' 205 | if turn_command == 'no': 206 | move.move(speed_set, 'no', 'no', rad) 207 | 208 | 209 | elif 'left' == command_input: 210 | turn_command = 'left' 211 | move.move(speed_set, 'no', 'left', rad) 212 | 213 | elif 'right' == command_input: 214 | turn_command = 'right' 215 | move.move(speed_set, 'no', 'right', rad) 216 | 217 | elif 'TS' in command_input: 218 | turn_command = 'no' 219 | if direction_command == 'no': 220 | move.move(speed_set, 'no', 'no', rad) 221 | else: 222 | move.move(speed_set, direction_command, 'no', rad) 223 | 224 | 225 | elif 'lookleft' == command_input: 226 | P_sc.singleServo(14, -1, 3) 227 | 228 | elif 'lookright' == command_input: 229 | P_sc.singleServo(14, 1, 3) 230 | 231 | elif 'LRstop' in command_input: 232 | P_sc.stopWiggle() 233 | 234 | 235 | elif 'up' == command_input: 236 | T_sc.singleServo(11, -1, 3) 237 | 238 | elif 'down' == command_input: 239 | T_sc.singleServo(11, 1, 3) 240 | 241 | elif 'UDstop' in command_input: 242 | T_sc.stopWiggle() 243 | 244 | 245 | elif 'handup' == command_input: 246 | # H1_sc.singleServo(12, 1, 7) 247 | 248 | H2_sc.singleServo(13, -1, 7) 249 | 250 | elif 'handdown' == command_input: 251 | # H1_sc.singleServo(12, -1, 7) 252 | 253 | H2_sc.singleServo(13, 1, 7) 254 | 255 | elif 'HAstop' in command_input: 256 | # H1_sc.stopWiggle() 257 | H2_sc.stopWiggle() 258 | 259 | elif 'armup' == command_input: 260 | H1_sc.singleServo(12, 1, 7) 261 | 262 | # H2_sc.singleServo(13, 1, 7) 263 | 264 | elif 'armdown' == command_input: 265 | H1_sc.singleServo(12, -1, 7) 266 | 267 | # H2_sc.singleServo(13, -1, 7) 268 | 269 | elif 'Armstop' in command_input: 270 | H1_sc.stopWiggle() 271 | # H2_sc.stopWiggle() 272 | 273 | elif 'grab' == command_input: 274 | G_sc.singleServo(15, 1, 3) 275 | 276 | elif 'loose' == command_input: 277 | G_sc.singleServo(15, -1, 3) 278 | 279 | elif 'stop' == command_input: 280 | G_sc.stopWiggle() 281 | 282 | elif 'home' == command_input: 283 | P_sc.moveServoInit([11]) 284 | T_sc.moveServoInit([14]) 285 | H1_sc.moveServoInit([12]) 286 | H2_sc.moveServoInit([13]) 287 | G_sc.moveServoInit([15]) 288 | 289 | 290 | def configPWM(command_input, response): 291 | global init_pwm0, init_pwm1, init_pwm2, init_pwm3, init_pwm4 292 | if 'SiLeft' == command_input: 293 | init_pwm0 += 1 294 | scGear.setPWM(0,init_pwm0) 295 | elif 'SiRight' == command_input: 296 | init_pwm0 -= 1 297 | scGear.setPWM(0,-init_pwm0) 298 | elif 'PWM0MS' == command_input: 299 | scGear.initConfig(0,init_pwm0,1) 300 | replace_num('init_pwm0 = ', init_pwm0) 301 | 302 | elif 'PWM1MS' == command_input: 303 | init_pwm1 = P_sc.lastPos[1] 304 | P_sc.initConfig(1,P_sc.lastPos[1],1) 305 | replace_num('init_pwm1 = ', P_sc.lastPos[1]) 306 | 307 | elif 'PWM2MS' == command_input: 308 | init_pwm2 = T_sc.lastPos[2] 309 | T_sc.initConfig(2,T_sc.lastPos[2],1) 310 | print('LLLLLS',T_sc.lastPos[2]) 311 | replace_num('init_pwm2 = ', T_sc.lastPos[2]) 312 | 313 | elif 'PWM3MS' == command_input: 314 | init_pwm3 = H_sc.lastPos[3] 315 | H1_sc.initConfig(3,H1_sc.lastPos[3],1) 316 | replace_num('init_pwm3 = ', H_sc.lastPos[3]) 317 | 318 | elif 'PWM4MS' == command_input: 319 | init_pwm4 = G_sc.lastPos[4] 320 | G_sc.initConfig(4,G_sc.lastPos[4],1) 321 | replace_num('init_pwm4 = ', G_sc.lastPos[4]) 322 | 323 | elif 'PWMINIT' == command_input: 324 | print(init_pwm1) 325 | servoPosInit() 326 | 327 | elif 'PWMD' == command_input: 328 | init_pwm0,init_pwm1,init_pwm2,init_pwm3,init_pwm4=300,300,300,300,300 329 | scGear.initConfig(0,init_pwm0,1) 330 | replace_num('init_pwm0 = ', 300) 331 | 332 | P_sc.initConfig(1,300,1) 333 | replace_num('init_pwm1 = ', 300) 334 | 335 | T_sc.initConfig(2,300,1) 336 | replace_num('init_pwm2 = ', 300) 337 | 338 | H1_sc.initConfig(3,300,1) 339 | replace_num('init_pwm3 = ', 300) 340 | 341 | G_sc.initConfig(4,300,1) 342 | replace_num('init_pwm4 = ', 300) 343 | ''' 344 | def update_code(): 345 | # Update local to be consistent with remote 346 | projectPath = thisPath[:-7] 347 | with open(f'{projectPath}/config.json', 'r') as f1: 348 | config = json.load(f1) 349 | if not config['production']: 350 | print('Update code') 351 | # Force overwriting local code 352 | if os.system(f'cd {projectPath} && sudo git fetch --all && sudo git reset --hard origin/master && sudo git pull') == 0: 353 | print('Update successfully') 354 | print('Restarting...') 355 | os.system('sudo reboot') 356 | ''' 357 | def wifi_check(): 358 | try: 359 | s =socket.socket(socket.AF_INET,socket.SOCK_DGRAM) 360 | s.connect(("1.1.1.1",80)) 361 | ipaddr_check=s.getsockname()[0] 362 | s.close() 363 | print(ipaddr_check) 364 | # update_code() 365 | if OLED_connection: 366 | screen.screen_show(2, 'IP:'+ipaddr_check) 367 | screen.screen_show(3, 'AP MODE OFF') 368 | except: 369 | ap_threading=threading.Thread(target=ap_thread) #Define a thread for data receiving 370 | ap_threading.setDaemon(True) #'True' means it is a front thread,it would close when the mainloop() closes 371 | ap_threading.start() #Thread starts 372 | if OLED_connection: 373 | screen.screen_show(2, 'AP Starting 10%') 374 | RL.setColor(0,16,50) 375 | time.sleep(1) 376 | if OLED_connection: 377 | screen.screen_show(2, 'AP Starting 30%') 378 | RL.setColor(0,16,100) 379 | time.sleep(1) 380 | if OLED_connection: 381 | screen.screen_show(2, 'AP Starting 50%') 382 | RL.setColor(0,16,150) 383 | time.sleep(1) 384 | if OLED_connection: 385 | screen.screen_show(2, 'AP Starting 70%') 386 | RL.setColor(0,16,200) 387 | time.sleep(1) 388 | if OLED_connection: 389 | screen.screen_show(2, 'AP Starting 90%') 390 | RL.setColor(0,16,255) 391 | time.sleep(1) 392 | if OLED_connection: 393 | screen.screen_show(2, 'AP Starting 100%') 394 | RL.setColor(35,255,35) 395 | if OLED_connection: 396 | screen.screen_show(2, 'IP:192.168.12.1') 397 | screen.screen_show(3, 'AP MODE ON') 398 | 399 | async def check_permit(websocket): 400 | while True: 401 | recv_str = await websocket.recv() 402 | cred_dict = recv_str.split(":") 403 | if cred_dict[0] == "admin" and cred_dict[1] == "123456": 404 | response_str = "congratulation, you have connect with server\r\nnow, you can do something else" 405 | await websocket.send(response_str) 406 | return True 407 | else: 408 | response_str = "sorry, the username or password is wrong, please submit again" 409 | await websocket.send(response_str) 410 | 411 | async def recv_msg(websocket): 412 | global speed_set, modeSelect 413 | move.setup() 414 | direction_command = 'no' 415 | turn_command = 'no' 416 | 417 | while True: 418 | response = { 419 | 'status' : 'ok', 420 | 'title' : '', 421 | 'data' : None 422 | } 423 | 424 | data = '' 425 | data = await websocket.recv() 426 | try: 427 | data = json.loads(data) 428 | except Exception as e: 429 | print('not A JSON') 430 | 431 | if not data: 432 | continue 433 | 434 | if isinstance(data,str): 435 | robotCtrl(data, response) 436 | 437 | switchCtrl(data, response) 438 | 439 | functionSelect(data, response) 440 | 441 | configPWM(data, response) 442 | 443 | if 'get_info' == data: 444 | response['title'] = 'get_info' 445 | response['data'] = [info.get_cpu_tempfunc(), info.get_cpu_use(), info.get_ram_info()] 446 | 447 | if 'wsB' in data: 448 | try: 449 | set_B=data.split() 450 | speed_set = int(set_B[1]) 451 | except: 452 | pass 453 | 454 | elif 'AR' == data: 455 | modeSelect = 'AR' 456 | screen.screen_show(4, 'ARM MODE ON') 457 | try: 458 | fpv.changeMode('ARM MODE ON') 459 | except: 460 | pass 461 | 462 | elif 'PT' == data: 463 | modeSelect = 'PT' 464 | screen.screen_show(4, 'PT MODE ON') 465 | try: 466 | fpv.changeMode('PT MODE ON') 467 | except: 468 | pass 469 | 470 | #CVFL 471 | elif 'CVFL' == data: 472 | flask_app.modeselect('findlineCV') 473 | 474 | elif 'CVFLColorSet' in data: 475 | color = int(data.split()[1]) 476 | flask_app.camera.colorSet(color) 477 | 478 | elif 'CVFLL1' in data: 479 | pos = int(data.split()[1]) 480 | flask_app.camera.linePosSet_1(pos) 481 | 482 | elif 'CVFLL2' in data: 483 | pos = int(data.split()[1]) 484 | flask_app.camera.linePosSet_2(pos) 485 | 486 | elif 'CVFLSP' in data: 487 | err = int(data.split()[1]) 488 | flask_app.camera.errorSet(err) 489 | 490 | elif 'defEC' in data:#Z 491 | fpv.defaultExpCom() 492 | 493 | elif(isinstance(data,dict)): 494 | if data['title'] == "findColorSet": 495 | color = data['data'] 496 | flask_app.colorFindSet(color[0],color[1],color[2]) 497 | 498 | if not functionMode: 499 | if OLED_connection: 500 | screen.screen_show(5,'Functions OFF') 501 | else: 502 | pass 503 | 504 | print(data) 505 | response = json.dumps(response) 506 | await websocket.send(response) 507 | 508 | async def main_logic(websocket, path): 509 | await check_permit(websocket) 510 | await recv_msg(websocket) 511 | 512 | if __name__ == '__main__': 513 | switch.switchSetup() 514 | switch.set_all_switch_off() 515 | 516 | HOST = '' 517 | PORT = 10223 #Define port serial 518 | BUFSIZ = 1024 #Define buffer size 519 | ADDR = (HOST, PORT) 520 | 521 | global flask_app 522 | flask_app = app.webapp() 523 | flask_app.startthread() 524 | 525 | try: 526 | # global WS2812 527 | robotlight_check = robotLight.check_rpi_model() 528 | if robotlight_check == 5: 529 | print("\033[1;33m WS2812 officially does not support Raspberry Pi 5 for the time being, and the WS2812 LED cannot be used on Raspberry Pi 5.\033[0m") 530 | WS2812_mark = 0 # WS2812 not compatible 531 | else: 532 | print("WS2812 success!") 533 | WS2812_mark = 1 534 | WS2812=robotLight.RobotWS2812() 535 | WS2812.start() 536 | WS2812.breath(70,70,255) 537 | except: 538 | print('Use "sudo pip3 install rpi_ws281x" to install WS_281x package\n使用"sudo pip3 install rpi_ws281x"命令来安装rpi_ws281x') 539 | pass 540 | 541 | while 1: 542 | wifi_check() 543 | try: #Start server,waiting for client 544 | start_server = websockets.serve(main_logic, '0.0.0.0', 8888) 545 | asyncio.get_event_loop().run_until_complete(start_server) 546 | print('waiting for connection...') 547 | # print('...connected from :', addr) 548 | break 549 | except Exception as e: 550 | print(e) 551 | if WS2812_mark: 552 | WS2812.setColor(0,0,0) 553 | else: 554 | pass 555 | 556 | try: 557 | asyncio.get_event_loop().run_forever() 558 | except Exception as e: 559 | print(e) 560 | if WS2812_mark: 561 | WS2812.setColor(0,0,0) 562 | else: 563 | pass 564 | move.destroy() 565 | -------------------------------------------------------------------------------- /server/raspi-config.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | # File name : server.py 3 | # Description : The main program server takes control of Ultrasonic,Motor,Servo by receiving the order from the client through TCP and carrying out the corresponding operation. 4 | # Website : www.adeept.com 5 | # E-mail : support@adeept.com 6 | # Author : William 7 | # Date : 2018/10/12 8 | 9 | import socket 10 | import time 11 | import Adafruit_PCA9685 12 | import os 13 | 14 | 15 | pwm = Adafruit_PCA9685.PCA9685() #Ultrasonic Control 16 | pwm.set_pwm_freq(50) 17 | 18 | def replace_num(initial,new_num): #Call this function to replace data in '.txt' file 19 | global r 20 | newline="" 21 | str_num=str(new_num) 22 | with open("config.txt","r") as f: 23 | for line in f.readlines(): 24 | if(line.find(initial) == 0): 25 | line = initial+"%s" %(str_num+"\n") 26 | newline += line 27 | with open("config.txt","w") as f: 28 | f.writelines(newline) 29 | 30 | def num_import_int(initial): #Call this function to import data from '.txt' file 31 | global r 32 | with open("config.txt") as f: 33 | for line in f.readlines(): 34 | if(line.find(initial) == 0): 35 | r=line 36 | begin=len(list(initial)) 37 | snum=r[begin:] 38 | n=int(snum) 39 | return n 40 | 41 | #L0 42 | L0_MAX = num_import_int('L0_MAX:') 43 | L0_MIN = num_import_int('L0_MIN:') 44 | L0_ST1 = num_import_int('L0_ST1:') 45 | L0_ST2 = num_import_int('L0_ST2:') 46 | L0_ST3 = num_import_int('L0_ST3:') 47 | L0_ST4 = num_import_int('L0_ST4:') 48 | L0_ST5 = num_import_int('L0_ST5:') 49 | L0_ST6 = num_import_int('L0_ST6:') 50 | L0_ST7 = num_import_int('L0_ST7:') 51 | L0_ST8 = num_import_int('L0_ST8:') 52 | L0_ST9 = num_import_int('L0_ST9:') 53 | L0_ST10 = num_import_int('L0_ST10:') 54 | #L1 55 | L1_MAX = num_import_int('L1_MAX:') 56 | L1_MIN = num_import_int('L1_MIN:') 57 | L1_ST1 = num_import_int('L1_ST1:') 58 | L1_ST2 = num_import_int('L1_ST2:') 59 | L1_ST3 = num_import_int('L1_ST3:') 60 | L1_ST4 = num_import_int('L1_ST4:') 61 | L1_ST5 = num_import_int('L1_ST5:') 62 | L1_ST6 = num_import_int('L1_ST6:') 63 | L1_ST7 = num_import_int('L1_ST7:') 64 | L1_ST8 = num_import_int('L1_ST8:') 65 | L1_ST9 = num_import_int('L1_ST9:') 66 | L1_ST10 = num_import_int('L1_ST10:') 67 | #L2 68 | L2_MAX = num_import_int('L2_MAX:') 69 | L2_MIN = num_import_int('L2_MIN:') 70 | L2_ST1 = num_import_int('L2_ST1:') 71 | L2_ST2 = num_import_int('L2_ST2:') 72 | L2_ST3 = num_import_int('L2_ST3:') 73 | L2_ST4 = num_import_int('L2_ST4:') 74 | L2_ST5 = num_import_int('L2_ST5:') 75 | L2_ST6 = num_import_int('L2_ST6:') 76 | L2_ST7 = num_import_int('L2_ST7:') 77 | L2_ST8 = num_import_int('L2_ST8:') 78 | L2_ST9 = num_import_int('L2_ST9:') 79 | L2_ST10 = num_import_int('L2_ST10:') 80 | #L3 81 | L3_MAX = num_import_int('L3_MAX:') 82 | L3_MIN = num_import_int('L3_MIN:') 83 | L3_ST1 = num_import_int('L3_ST1:') 84 | L3_ST2 = num_import_int('L3_ST2:') 85 | L3_ST3 = num_import_int('L3_ST3:') 86 | L3_ST4 = num_import_int('L3_ST4:') 87 | L3_ST5 = num_import_int('L3_ST5:') 88 | L3_ST6 = num_import_int('L3_ST6:') 89 | L3_ST7 = num_import_int('L3_ST7:') 90 | L3_ST8 = num_import_int('L3_ST8:') 91 | L3_ST9 = num_import_int('L3_ST9:') 92 | L3_ST10 = num_import_int('L3_ST10:') 93 | #L4 94 | L4_MAX = num_import_int('L4_MAX:') 95 | L4_MIN = num_import_int('L4_MIN:') 96 | L4_ST1 = num_import_int('L4_ST1:') 97 | L4_ST2 = num_import_int('L4_ST2:') 98 | L4_ST3 = num_import_int('L4_ST3:') 99 | L4_ST4 = num_import_int('L4_ST4:') 100 | L4_ST5 = num_import_int('L4_ST5:') 101 | L4_ST6 = num_import_int('L4_ST6:') 102 | L4_ST7 = num_import_int('L4_ST7:') 103 | L4_ST8 = num_import_int('L4_ST8:') 104 | L4_ST9 = num_import_int('L4_ST9:') 105 | L4_ST10 = num_import_int('L4_ST10:') 106 | #L5 107 | L5_MAX = num_import_int('L5_MAX:') 108 | L5_MIN = num_import_int('L5_MIN:') 109 | L5_ST1 = num_import_int('L5_ST1:') 110 | L5_ST2 = num_import_int('L5_ST2:') 111 | L5_ST3 = num_import_int('L5_ST3:') 112 | L5_ST4 = num_import_int('L5_ST4:') 113 | L5_ST5 = num_import_int('L5_ST5:') 114 | L5_ST6 = num_import_int('L5_ST6:') 115 | L5_ST7 = num_import_int('L5_ST7:') 116 | L5_ST8 = num_import_int('L5_ST8:') 117 | L5_ST9 = num_import_int('L5_ST9:') 118 | L5_ST10 = num_import_int('L5_ST10:') 119 | #L6 120 | L6_MAX = num_import_int('L6_MAX:') 121 | L6_MIN = num_import_int('L6_MIN:') 122 | L6_ST1 = num_import_int('L6_ST1:') 123 | L6_ST2 = num_import_int('L6_ST2:') 124 | L6_ST3 = num_import_int('L6_ST3:') 125 | L6_ST4 = num_import_int('L6_ST4:') 126 | L6_ST5 = num_import_int('L6_ST5:') 127 | L6_ST6 = num_import_int('L6_ST6:') 128 | L6_ST7 = num_import_int('L6_ST7:') 129 | L6_ST8 = num_import_int('L6_ST8:') 130 | L6_ST9 = num_import_int('L6_ST9:') 131 | L6_ST10 = num_import_int('L6_ST10:') 132 | #L7 133 | L7_MAX = num_import_int('L7_MAX:') 134 | L7_MIN = num_import_int('L7_MIN:') 135 | L7_ST1 = num_import_int('L7_ST1:') 136 | L7_ST2 = num_import_int('L7_ST2:') 137 | L7_ST3 = num_import_int('L7_ST3:') 138 | L7_ST4 = num_import_int('L7_ST4:') 139 | L7_ST5 = num_import_int('L7_ST5:') 140 | L7_ST6 = num_import_int('L7_ST6:') 141 | L7_ST7 = num_import_int('L7_ST7:') 142 | L7_ST8 = num_import_int('L7_ST8:') 143 | L7_ST9 = num_import_int('L7_ST9:') 144 | L7_ST10 = num_import_int('L7_ST10:') 145 | #L8 146 | L8_MAX = num_import_int('L8_MAX:') 147 | L8_MIN = num_import_int('L8_MIN:') 148 | L8_ST1 = num_import_int('L8_ST1:') 149 | L8_ST2 = num_import_int('L8_ST2:') 150 | L8_ST3 = num_import_int('L8_ST3:') 151 | L8_ST4 = num_import_int('L8_ST4:') 152 | L8_ST5 = num_import_int('L8_ST5:') 153 | L8_ST6 = num_import_int('L8_ST6:') 154 | L8_ST7 = num_import_int('L8_ST7:') 155 | L8_ST8 = num_import_int('L8_ST8:') 156 | L8_ST9 = num_import_int('L8_ST9:') 157 | L8_ST10 = num_import_int('L8_ST10:') 158 | #L9 159 | L9_MAX = num_import_int('L9_MAX:') 160 | L9_MIN = num_import_int('L9_MIN:') 161 | L9_ST1 = num_import_int('L9_ST1:') 162 | L9_ST2 = num_import_int('L9_ST2:') 163 | L9_ST3 = num_import_int('L9_ST3:') 164 | L9_ST4 = num_import_int('L9_ST4:') 165 | L9_ST5 = num_import_int('L9_ST5:') 166 | L9_ST6 = num_import_int('L9_ST6:') 167 | L9_ST7 = num_import_int('L9_ST6:') 168 | L9_ST8 = num_import_int('L9_ST6:') 169 | L9_ST9 = num_import_int('L9_ST6:') 170 | L9_ST10 = num_import_int('L9_ST10:') 171 | #L10 172 | L10_MAX = num_import_int('L10_MAX:') 173 | L10_MIN = num_import_int('L10_MIN:') 174 | L10_ST1 = num_import_int('L10_ST1:') 175 | L10_ST2 = num_import_int('L10_ST2:') 176 | L10_ST3 = num_import_int('L10_ST3:') 177 | L10_ST4 = num_import_int('L10_ST4:') 178 | L10_ST5 = num_import_int('L10_ST5:') 179 | L10_ST6 = num_import_int('L10_ST6:') 180 | L10_ST7 = num_import_int('L10_ST7:') 181 | L10_ST8 = num_import_int('L10_ST8:') 182 | L10_ST9 = num_import_int('L10_ST9:') 183 | L10_ST10 = num_import_int('L10_ST10:') 184 | #L11 185 | L11_MAX = num_import_int('L11_MAX:') 186 | L11_MIN = num_import_int('L11_MIN:') 187 | L11_ST1 = num_import_int('L11_ST1:') 188 | L11_ST2 = num_import_int('L11_ST2:') 189 | L11_ST3 = num_import_int('L11_ST3:') 190 | L11_ST4 = num_import_int('L11_ST4:') 191 | L11_ST5 = num_import_int('L11_ST5:') 192 | L11_ST6 = num_import_int('L11_ST6:') 193 | L11_ST7 = num_import_int('L11_ST7:') 194 | L11_ST8 = num_import_int('L11_ST8:') 195 | L11_ST9 = num_import_int('L11_ST9:') 196 | L11_ST10 = num_import_int('L11_ST10:') 197 | #L12 198 | L12_MAX = num_import_int('L12_MAX:') 199 | L12_MIN = num_import_int('L12_MIN:') 200 | L12_ST1 = num_import_int('L12_ST1:') 201 | L12_ST2 = num_import_int('L12_ST2:') 202 | L12_ST3 = num_import_int('L12_ST3:') 203 | L12_ST4 = num_import_int('L12_ST4:') 204 | L12_ST5 = num_import_int('L12_ST5:') 205 | L12_ST6 = num_import_int('L12_ST6:') 206 | L12_ST7 = num_import_int('L12_ST7:') 207 | L12_ST8 = num_import_int('L12_ST8:') 208 | L12_ST9 = num_import_int('L12_ST9:') 209 | L12_ST10 = num_import_int('L12_ST10:') 210 | #L13 211 | L13_MAX = num_import_int('L13_MAX:') 212 | L13_MIN = num_import_int('L13_MIN:') 213 | L13_ST1 = num_import_int('L13_ST1:') 214 | L13_ST2 = num_import_int('L13_ST2:') 215 | L13_ST3 = num_import_int('L13_ST3:') 216 | L13_ST4 = num_import_int('L13_ST4:') 217 | L13_ST5 = num_import_int('L13_ST5:') 218 | L13_ST6 = num_import_int('L13_ST6:') 219 | L13_ST7 = num_import_int('L13_ST7:') 220 | L13_ST8 = num_import_int('L13_ST8:') 221 | L13_ST9 = num_import_int('L13_ST9:') 222 | L13_ST10 = num_import_int('L13_ST10:') 223 | #L14 224 | L14_MAX = num_import_int('L14_MAX:') 225 | L14_MIN = num_import_int('L14_MIN:') 226 | L14_ST1 = num_import_int('L14_ST1:') 227 | L14_ST2 = num_import_int('L14_ST2:') 228 | L14_ST3 = num_import_int('L14_ST3:') 229 | L14_ST4 = num_import_int('L14_ST4:') 230 | L14_ST5 = num_import_int('L14_ST5:') 231 | L14_ST6 = num_import_int('L14_ST6:') 232 | L14_ST7 = num_import_int('L14_ST7:') 233 | L14_ST8 = num_import_int('L14_ST8:') 234 | L14_ST9 = num_import_int('L14_ST9:') 235 | L14_ST10 = num_import_int('L14_ST10:') 236 | #L15 237 | L15_MAX = num_import_int('L15_MAX:') 238 | L15_MIN = num_import_int('L15_MIN:') 239 | L15_ST1 = num_import_int('L15_ST1:') 240 | L15_ST2 = num_import_int('L15_ST2:') 241 | L15_ST3 = num_import_int('L15_ST3:') 242 | L15_ST4 = num_import_int('L15_ST4:') 243 | L15_ST5 = num_import_int('L15_ST5:') 244 | L15_ST6 = num_import_int('L15_ST6:') 245 | L15_ST7 = num_import_int('L15_ST7:') 246 | L15_ST8 = num_import_int('L15_ST8:') 247 | L15_ST9 = num_import_int('L15_ST9:') 248 | L15_ST10 = num_import_int('L15_ST10:') 249 | 250 | 251 | ip_con = '' 252 | 253 | 254 | org=425 255 | 256 | set_L = 1 257 | set_ST = 1 258 | 259 | def destroy(): #Clean up 260 | connection.close() 261 | 262 | def run(): #Main loop 263 | global org,ip_con,set_L,set_ST,r 264 | while True: #Connection 265 | s =socket.socket(socket.AF_INET,socket.SOCK_DGRAM) 266 | s.connect(("1.1.1.1",80)) 267 | ipaddr_check=s.getsockname()[0] 268 | s.close() 269 | print(ipaddr_check) 270 | print('waiting for connection...') 271 | tcpCliSock, addr = tcpSerSock.accept()#Determine whether to connect 272 | print('...connected from :', addr) 273 | pwm.set_pwm(2, 0, 0) 274 | pwm.set_pwm(1, 0, 0) 275 | pwm.set_pwm(0, 0, 0) 276 | pwm.set_pwm(15, 0, 0) 277 | break 278 | 279 | while True: 280 | data = '' 281 | data = tcpCliSock.recv(BUFSIZ).decode() 282 | if not data: 283 | continue 284 | elif 'L0' == data: 285 | set_L = 0 286 | tcpCliSock.send(('L0').encode()) 287 | elif 'L1' == data: 288 | set_L = 1 289 | tcpCliSock.send(('L1').encode()) 290 | elif 'L2' == data: 291 | set_L = 2 292 | tcpCliSock.send(('L2').encode()) 293 | elif 'L3' == data: 294 | set_L = 3 295 | tcpCliSock.send(('L3').encode()) 296 | elif 'L4' == data: 297 | set_L = 4 298 | tcpCliSock.send(('L4').encode()) 299 | elif 'L5' == data: 300 | set_L = 5 301 | tcpCliSock.send(('L5').encode()) 302 | elif 'L6' == data: 303 | set_L = 6 304 | tcpCliSock.send(('L6').encode()) 305 | elif 'L7' == data: 306 | set_L = 7 307 | tcpCliSock.send(('L7').encode()) 308 | elif 'L8' == data: 309 | set_L = 8 310 | tcpCliSock.send(('L8').encode()) 311 | elif 'L9' == data: 312 | set_L = 9 313 | tcpCliSock.send(('L9').encode()) 314 | elif 'L10' == data: 315 | set_L = 10 316 | tcpCliSock.send(('L10').encode()) 317 | elif 'L11' == data: 318 | set_L = 11 319 | tcpCliSock.send(('L11').encode()) 320 | elif 'L12' == data: 321 | set_L = 12 322 | tcpCliSock.send(('L12').encode()) 323 | elif 'L13' == data: 324 | set_L = 13 325 | tcpCliSock.send(('L13').encode()) 326 | elif 'L14' == data: 327 | set_L = 14 328 | tcpCliSock.send(('L14').encode()) 329 | elif 'L15' == data: 330 | set_L = 15 331 | tcpCliSock.send(('L15').encode()) 332 | 333 | 334 | 335 | elif 'ST1' == data: 336 | set_ST = 'ST1' 337 | pwm.set_pwm(set_L, 0, num_import_int('L%d_%s:'%(set_L,set_ST))) 338 | tcpCliSock.send(('ST1').encode()) 339 | elif 'ST2' == data: 340 | set_ST = 'ST2' 341 | pwm.set_pwm(set_L, 0, num_import_int('L%d_%s:'%(set_L,set_ST))) 342 | tcpCliSock.send(('ST2').encode()) 343 | elif 'ST3' == data: 344 | set_ST = 'ST3' 345 | pwm.set_pwm(set_L, 0, num_import_int('L%d_%s:'%(set_L,set_ST))) 346 | tcpCliSock.send(('ST3').encode()) 347 | elif 'ST4' == data: 348 | set_ST = 'ST4' 349 | pwm.set_pwm(set_L, 0, num_import_int('L%d_%s:'%(set_L,set_ST))) 350 | tcpCliSock.send(('ST4').encode()) 351 | elif 'ST5' == data: 352 | set_ST = 'ST5' 353 | pwm.set_pwm(set_L, 0, num_import_int('L%d_%s:'%(set_L,set_ST))) 354 | tcpCliSock.send(('ST5').encode()) 355 | elif 'ST6' == data: 356 | set_ST = 'ST6' 357 | pwm.set_pwm(set_L, 0, num_import_int('L%d_%s:'%(set_L,set_ST))) 358 | tcpCliSock.send(('ST6').encode()) 359 | elif 'ST7' == data: 360 | set_ST = 'ST7' 361 | pwm.set_pwm(set_L, 0, num_import_int('L%d_%s:'%(set_L,set_ST))) 362 | tcpCliSock.send(('ST7').encode()) 363 | elif 'ST8' == data: 364 | set_ST = 'ST8' 365 | pwm.set_pwm(set_L, 0, num_import_int('L%d_%s:'%(set_L,set_ST))) 366 | tcpCliSock.send(('ST8').encode()) 367 | elif 'ST9' == data: 368 | set_ST = 'ST9' 369 | pwm.set_pwm(set_L, 0, num_import_int('L%d_%s:'%(set_L,set_ST))) 370 | tcpCliSock.send(('ST9').encode()) 371 | elif 'ST10' == data: 372 | set_ST = 'ST10' 373 | pwm.set_pwm(set_L, 0, num_import_int('L%d_%s:'%(set_L,set_ST))) 374 | tcpCliSock.send(('ST10').encode()) 375 | elif 'ST11' == data: 376 | set_ST = 'ST11' 377 | pwm.set_pwm(set_L, 0, num_import_int('L%d_%s:'%(set_L,set_ST))) 378 | tcpCliSock.send(('ST11').encode()) 379 | elif 'ST12' == data: 380 | set_ST = 'ST12' 381 | pwm.set_pwm(set_L, 0, num_import_int('L%d_%s:'%(set_L,set_ST))) 382 | tcpCliSock.send(('ST12').encode()) 383 | elif 'ST13' == data: 384 | set_ST = 'ST13' 385 | pwm.set_pwm(set_L, 0, num_import_int('L%d_%s:'%(set_L,set_ST))) 386 | tcpCliSock.send(('ST13').encode()) 387 | elif 'ST14' == data: 388 | set_ST = 'ST14' 389 | pwm.set_pwm(set_L, 0, num_import_int('L%d_%s:'%(set_L,set_ST))) 390 | tcpCliSock.send(('ST14').encode()) 391 | elif 'MIN' == data: 392 | set_ST = 'MIN' 393 | pwm.set_pwm(set_L, 0, num_import_int('L%d_%s:'%(set_L,set_ST))) 394 | tcpCliSock.send(('MIN').encode()) 395 | elif 'MAX' == data: 396 | set_ST = 'MAX' 397 | pwm.set_pwm(set_L, 0, num_import_int('L%d_%s:'%(set_L,set_ST))) 398 | tcpCliSock.send(('MAX').encode()) 399 | 400 | 401 | 402 | elif 'add' == data: 403 | org+=1 404 | pwm.set_pwm(set_L, 0, org) 405 | send_pwm=str(org) 406 | tcpCliSock.send(send_pwm.encode()) 407 | continue 408 | 409 | elif 'sub' == data: #Camera Adjustment 410 | org-=1 411 | pwm.set_pwm(set_L, 0, org) 412 | send_pwm=str(org) 413 | tcpCliSock.send(send_pwm.encode()) 414 | continue 415 | 416 | elif 'config' == data: 417 | replace_num(('L%d_%s:'%(set_L,set_ST)),org) 418 | 419 | elif 'reset' == data: 420 | replace_num(('L%d_%s:'%(set_L,set_ST)),org) 421 | 422 | elif 'save' == data: 423 | replace_num(('L%d_%s:'%(set_L,set_ST)),org) 424 | 425 | elif 'run' in data: 426 | set_list=data.split() 427 | try: 428 | setps = int(set_list[1]) 429 | time_get = round(float(set_list[2]),1) 430 | print(setps) 431 | print(time_get) 432 | for i in range (1,(setps+1)): 433 | pwm.set_pwm(set_L, 0, num_import_int('L%d_ST%d:'%(set_L,i))) 434 | time.sleep(time_get) 435 | except: 436 | print('wrong args') 437 | pass 438 | 439 | elif 'all' in data: 440 | try: 441 | set_list=data.split() 442 | setps = int(set_list[1]) 443 | time_get = round(float(set_list[2]),1) 444 | print(setps) 445 | print(time_get) 446 | for i in range (1,(setps+1)): 447 | for x in range (0,16): 448 | pwm.set_pwm(x, 0, num_import_int('L%d_ST%d:'%(x,i))) 449 | time.sleep(time_get) 450 | except: 451 | print('wrong args') 452 | pass 453 | 454 | elif 'frame' in data: 455 | try: 456 | for i in range (0,16): 457 | pwm.set_pwm(i, 0, num_import_int('L%d_%s:'%(i,set_ST))) 458 | except: 459 | print('wrong args') 460 | pass 461 | 462 | elif 'stop' in data: 463 | pwm.set_pwm(2, 0, 0) 464 | pwm.set_pwm(1, 0, 0) 465 | pwm.set_pwm(0, 0, 0) 466 | pwm.set_pwm(15, 0, 0) 467 | pwm.set_pwm(14, 0, 0) 468 | pwm.set_pwm(13, 0, 0) 469 | pwm.set_pwm(12, 0, 0) 470 | pwm.set_pwm(11, 0, 0) 471 | pwm.set_pwm(10, 0, 0) 472 | pwm.set_pwm(9, 0, 0) 473 | pwm.set_pwm(8, 0, 0) 474 | pwm.set_pwm(7, 0, 0) 475 | pwm.set_pwm(6, 0, 0) 476 | pwm.set_pwm(5, 0, 0) 477 | pwm.set_pwm(4, 0, 0) 478 | pwm.set_pwm(3, 0, 0) 479 | 480 | 481 | else: 482 | try: 483 | org = int(data) 484 | print(org) 485 | pwm.set_pwm(set_L, 0, org) 486 | except: 487 | pass 488 | 489 | 490 | 491 | 492 | 493 | if __name__ == '__main__': 494 | HOST = '' 495 | PORT = 10223 #Define port serial 496 | BUFSIZ = 1024 #Define buffer size 497 | ADDR = (HOST, PORT) 498 | 499 | tcpSerSock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 500 | tcpSerSock.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1) 501 | tcpSerSock.bind(ADDR) 502 | tcpSerSock.listen(5) 503 | #Start server,waiting for client 504 | try: 505 | run() 506 | 507 | except KeyboardInterrupt: 508 | pwm.set_pwm(2, 0, 0) 509 | pwm.set_pwm(1, 0, 0) 510 | pwm.set_pwm(0, 0, 0) 511 | pwm.set_pwm(15, 0, 0) 512 | pwm.set_pwm(14, 0, 0) 513 | pwm.set_pwm(13, 0, 0) 514 | pwm.set_pwm(12, 0, 0) 515 | pwm.set_pwm(11, 0, 0) 516 | pwm.set_pwm(10, 0, 0) 517 | pwm.set_pwm(9, 0, 0) 518 | pwm.set_pwm(8, 0, 0) 519 | pwm.set_pwm(7, 0, 0) 520 | pwm.set_pwm(6, 0, 0) 521 | pwm.set_pwm(5, 0, 0) 522 | pwm.set_pwm(4, 0, 0) 523 | pwm.set_pwm(3, 0, 0) 524 | 525 | destroy() 526 | -------------------------------------------------------------------------------- /server/robotLight.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # File name : robotLight.py 3 | # Website : www.adeept.com 4 | # Author : Adeept 5 | # Date : 2025/05/15 6 | import time 7 | import sys 8 | from gpiozero import PWMOutputDevice as PWM 9 | from rpi_ws281x import * 10 | import threading 11 | import spidev 12 | import numpy 13 | from numpy import sin, cos, pi 14 | def check_rpi_model(): 15 | _, result = run_command("cat /proc/device-tree/model |awk '{print $3}'") 16 | result = result.strip() 17 | if result == '3': 18 | return 3 19 | elif result == '4': 20 | return 4 21 | elif result == '5': 22 | return 5 23 | else: 24 | return None 25 | 26 | def run_command(cmd=""): 27 | import subprocess 28 | p = subprocess.Popen( 29 | cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) 30 | result = p.stdout.read().decode('utf-8') 31 | status = p.poll() 32 | return status, result 33 | 34 | 35 | def map(x, in_min, in_max, out_min, out_max): 36 | return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min 37 | 38 | 39 | class RobotWS2812(threading.Thread): 40 | def __init__(self, *args, **kwargs): 41 | self.LED_COUNT = 16 # Number of LED pixels. 42 | self.LED_PIN = 12 # GPIO pin connected to the pixels (18 uses PWM!). 43 | self.LED_FREQ_HZ = 800000 # LED signal frequency in hertz (usually 800khz) 44 | self.LED_DMA = 10 # DMA channel to use for generating signal (try 10) 45 | self.LED_BRIGHTNESS = 255 # Set to 0 for darkest and 255 for brightest 46 | self.LED_INVERT = False # True to invert the signal (when using NPN transistor level shift) 47 | self.LED_CHANNEL = 0 # set to '1' for GPIOs 13, 19, 41, 45 or 53 48 | 49 | self.colorBreathR = 0 50 | self.colorBreathG = 0 51 | self.colorBreathB = 0 52 | self.breathSteps = 10 53 | 54 | 55 | self.lightMode = 'none' #'none' 'police' 'breath' 56 | 57 | 58 | # Create NeoPixel object with appropriate configuration. 59 | self.strip = Adafruit_NeoPixel(self.LED_COUNT, self.LED_PIN, self.LED_FREQ_HZ, self.LED_DMA, self.LED_INVERT, self.LED_BRIGHTNESS, self.LED_CHANNEL) 60 | # Intialize the library (must be called once before other functions). 61 | self.strip.begin() 62 | 63 | super(RobotWS2812, self).__init__(*args, **kwargs) 64 | self.__flag = threading.Event() 65 | self.__flag.clear() 66 | 67 | # Define functions which animate LEDs in various ways. 68 | def set_all_led_color_data(self, R, G, B): 69 | """Wipe color across display a pixel at a time.""" 70 | color = Color(int(R),int(G),int(B)) 71 | for i in range(self.strip.numPixels()): 72 | self.strip.setPixelColor(i, color) 73 | self.strip.show() 74 | 75 | def setSomeColor(self, R, G, B, ID): 76 | color = Color(int(R),int(G),int(B)) 77 | for i in ID: 78 | self.strip.setPixelColor(i, color) 79 | self.strip.show() 80 | 81 | def pause(self): 82 | self.lightMode = 'none' 83 | self.set_all_led_color_data(0,0,0) 84 | self.__flag.clear() 85 | 86 | def resume(self): 87 | self.__flag.set() 88 | 89 | def led_close(self): 90 | self.lightMode = 'none' 91 | self.set_all_led_color_data(0,0,0) 92 | self.__flag.clear() 93 | def police(self): 94 | self.lightMode = 'police' 95 | self.resume() 96 | 97 | 98 | def policeProcessing(self): 99 | while self.lightMode == 'police': 100 | for i in range(0,3): 101 | self.setSomeColor(0,0,255,[0,1,2,3,4,5,6,7,8,9,10,11]) 102 | self.set_all_led_color_data(0,0,255) 103 | time.sleep(0.05) 104 | self.setSomeColor(0,0,0,[0,1,2,3,4,5,6,7,8,9,10,11]) 105 | self.set_all_led_color_data(0,0,0) 106 | time.sleep(0.05) 107 | if self.lightMode != 'police': 108 | break 109 | time.sleep(0.1) 110 | for i in range(0,3): 111 | self.setSomeColor(255,0,0,[0,1,2,3,4,5,6,7,8,9,10,11]) 112 | self.set_all_led_color_data(255,0,0) 113 | time.sleep(0.05) 114 | self.setSomeColor(0,0,0,[0,1,2,3,4,5,6,7,8,9,10,11]) 115 | self.set_all_led_color_data(0,0,0) 116 | time.sleep(0.05) 117 | time.sleep(0.1) 118 | 119 | 120 | def breath(self, R_input, G_input, B_input): 121 | self.lightMode = 'breath' 122 | self.colorBreathR = R_input 123 | self.colorBreathG = G_input 124 | self.colorBreathB = B_input 125 | self.resume() 126 | 127 | 128 | def breathProcessing(self): 129 | while self.lightMode == 'breath': 130 | for i in range(0,self.breathSteps): 131 | if self.lightMode != 'breath': 132 | break 133 | self.set_all_led_color_data(self.colorBreathR*i/self.breathSteps, self.colorBreathG*i/self.breathSteps, self.colorBreathB*i/self.breathSteps) 134 | time.sleep(0.03) 135 | for i in range(0,self.breathSteps): 136 | if self.lightMode != 'breath': 137 | break 138 | self.set_all_led_color_data(self.colorBreathR-(self.colorBreathR*i/self.breathSteps), self.colorBreathG-(self.colorBreathG*i/self.breathSteps), self.colorBreathB-(self.colorBreathB*i/self.breathSteps)) 139 | time.sleep(0.03) 140 | 141 | def lightChange(self): 142 | if self.lightMode == 'none': 143 | self.pause() 144 | elif self.lightMode == 'police': 145 | self.policeProcessing() 146 | elif self.lightMode == 'breath': 147 | self.breathProcessing() 148 | 149 | 150 | def run(self): 151 | while 1: 152 | self.__flag.wait() 153 | self.lightChange() 154 | pass 155 | 156 | 157 | 158 | 159 | 160 | class Adeept_SPI_LedPixel(threading.Thread): 161 | def __init__(self, count = 8, bright = 255, sequence='GRB', bus = 0, device = 0, *args, **kwargs): 162 | self.set_led_type(sequence) 163 | self.set_led_count(count) 164 | self.set_led_brightness(bright) 165 | self.led_begin(bus, device) 166 | self.lightMode = 'none' 167 | self.colorBreathR = 0 168 | self.colorBreathG = 0 169 | self.colorBreathB = 0 170 | self.breathSteps = 10 171 | 172 | 173 | self.rainbow_r = 0 174 | self.rainbow_g = 0 175 | self.rainbow_b = 00 176 | 177 | self.colorFlowingR = 0 178 | self.colorFlowingG = 0 179 | self.colorFlowingB = 0 180 | 181 | self.set_all_led_color(0,0,0) 182 | super(Adeept_SPI_LedPixel, self).__init__(*args, **kwargs) 183 | self.__flag = threading.Event() 184 | self.__flag.clear() 185 | def led_begin(self, bus = 0, device = 0): 186 | self.bus = bus 187 | self.device = device 188 | try: 189 | self.spi = spidev.SpiDev() 190 | self.spi.open(self.bus, self.device) 191 | self.spi.mode = 0 192 | self.led_init_state = 1 193 | except OSError: 194 | print("Please check the configuration in /boot/firmware/config.txt.") 195 | if self.bus == 0: 196 | print("You can turn on the 'SPI' in 'Interface Options' by using 'sudo raspi-config'.") 197 | print("Or make sure that 'dtparam=spi=on' is not commented, then reboot the Raspberry Pi. Otherwise spi0 will not be available.") 198 | else: 199 | print("Please add 'dtoverlay=spi{}-2cs' at the bottom of the /boot/firmware/config.txt, then reboot the Raspberry Pi. otherwise spi{} will not be available.".format(self.bus, self.bus)) 200 | self.led_init_state = 0 201 | 202 | def check_spi_state(self): 203 | return self.led_init_state 204 | 205 | def spi_gpio_info(self): 206 | if self.bus == 0: 207 | print("SPI0-MOSI: GPIO10(WS2812-PIN) SPI0-MISO: GPIO9 SPI0-SCLK: GPIO11 SPI0-CE0: GPIO8 SPI0-CE1: GPIO7") 208 | elif self.bus == 1: 209 | print("SPI1-MOSI: GPIO20(WS2812-PIN) SPI1-MISO: GPIO19 SPI1-SCLK: GPIO21 SPI1-CE0: GPIO18 SPI1-CE1: GPIO17 SPI0-CE1: GPIO16") 210 | elif self.bus == 2: 211 | print("SPI2-MOSI: GPIO41(WS2812-PIN) SPI2-MISO: GPIO40 SPI2-SCLK: GPIO42 SPI2-CE0: GPIO43 SPI2-CE1: GPIO44 SPI2-CE1: GPIO45") 212 | elif self.bus == 3: 213 | print("SPI3-MOSI: GPIO2(WS2812-PIN) SPI3-MISO: GPIO1 SPI3-SCLK: GPIO3 SPI3-CE0: GPIO0 SPI3-CE1: GPIO24") 214 | elif self.bus == 4: 215 | print("SPI4-MOSI: GPIO6(WS2812-PIN) SPI4-MISO: GPIO5 SPI4-SCLK: GPIO7 SPI4-CE0: GPIO4 SPI4-CE1: GPIO25") 216 | elif self.bus == 5: 217 | print("SPI5-MOSI: GPIO14(WS2812-PIN) SPI5-MISO: GPIO13 SPI5-SCLK: GPIO15 SPI5-CE0: GPIO12 SPI5-CE1: GPIO26") 218 | elif self.bus == 6: 219 | print("SPI6-MOSI: GPIO20(WS2812-PIN) SPI6-MISO: GPIO19 SPI6-SCLK: GPIO21 SPI6-CE0: GPIO18 SPI6-CE1: GPIO27") 220 | 221 | def led_close(self): 222 | self.set_all_led_rgb([0,0,0]) 223 | self.spi.close() 224 | 225 | def set_led_count(self, count): 226 | self.led_count = count 227 | self.led_color = [0,0,0] * self.led_count 228 | self.led_original_color = [0,0,0] * self.led_count 229 | 230 | def set_led_type(self, rgb_type): 231 | try: 232 | led_type = ['RGB','RBG','GRB','GBR','BRG','BGR'] 233 | led_type_offset = [0x06,0x09,0x12,0x21,0x18,0x24] 234 | index = led_type.index(rgb_type) 235 | self.led_red_offset = (led_type_offset[index]>>4) & 0x03 236 | self.led_green_offset = (led_type_offset[index]>>2) & 0x03 237 | self.led_blue_offset = (led_type_offset[index]>>0) & 0x03 238 | return index 239 | except ValueError: 240 | self.led_red_offset = 1 241 | self.led_green_offset = 0 242 | self.led_blue_offset = 2 243 | return -1 244 | 245 | def set_led_brightness(self, brightness): 246 | self.led_brightness = brightness 247 | for i in range(self.led_count): 248 | self.set_led_rgb_data(i, self.led_original_color) 249 | 250 | def set_ledpixel(self, index, r, g, b): 251 | p = [0,0,0] 252 | p[self.led_red_offset] = round(r * self.led_brightness / 255) 253 | p[self.led_green_offset] = round(g * self.led_brightness / 255) 254 | p[self.led_blue_offset] = round(b * self.led_brightness / 255) 255 | self.led_original_color[index*3+self.led_red_offset] = r 256 | self.led_original_color[index*3+self.led_green_offset] = g 257 | self.led_original_color[index*3+self.led_blue_offset] = b 258 | for i in range(3): 259 | self.led_color[index*3+i] = p[i] 260 | 261 | def set_led_color_data(self, index, r, g, b): 262 | self.set_ledpixel(index, r, g, b) 263 | 264 | def set_led_rgb_data(self, index, color): 265 | self.set_ledpixel(index, color[0], color[1], color[2]) 266 | 267 | def set_led_color(self, index, r, g, b): 268 | self.set_ledpixel(index, r, g, b) 269 | self.show() 270 | 271 | def set_led_rgb(self, index, color): 272 | self.set_led_rgb_data(index, color) 273 | self.show() 274 | 275 | def set_all_led_color_data(self, r, g, b): 276 | for i in range(self.led_count): 277 | self.set_led_color_data(i, r, g, b) 278 | 279 | def set_all_led_rgb_data(self, color): 280 | for i in range(self.led_count): 281 | self.set_led_rgb_data(i, color) 282 | 283 | def set_all_led_color(self, r, g, b): 284 | for i in range(self.led_count): 285 | self.set_led_color_data(i, r, g, b) 286 | self.show() 287 | 288 | def set_all_led_rgb(self, color): 289 | for i in range(self.led_count): 290 | self.set_led_rgb_data(i, color) 291 | self.show() 292 | 293 | 294 | def write_ws2812_numpy8(self): 295 | d = numpy.array(self.led_color).ravel() #Converts data into a one-dimensional array 296 | tx = numpy.zeros(len(d)*8, dtype=numpy.uint8) #Each RGB color has 8 bits, each represented by a uint8 type data 297 | for ibit in range(8): #Convert each bit of data to the data that the spi will send 298 | tx[7-ibit::8]=((d>>ibit)&1)*0x78 + 0x80 #T0H=1,T0L=7, T1H=5,T1L=3 #0b11111000 mean T1(0.78125us), 0b10000000 mean T0(0.15625us) 299 | if self.led_init_state != 0: 300 | if self.bus == 0: 301 | self.spi.xfer(tx.tolist(), int(8/1.25e-6)) #Send color data at a frequency of 6.4Mhz 302 | else: 303 | self.spi.xfer(tx.tolist(), int(8/1.0e-6)) #Send color data at a frequency of 8Mhz 304 | 305 | def write_ws2812_numpy4(self): 306 | d=numpy.array(self.led_color).ravel() 307 | tx=numpy.zeros(len(d)*4, dtype=numpy.uint8) 308 | for ibit in range(4): 309 | tx[3-ibit::4]=((d>>(2*ibit+1))&1)*0x60 + ((d>>(2*ibit+0))&1)*0x06 + 0x88 310 | if self.led_init_state != 0: 311 | if self.bus == 0: 312 | self.spi.xfer(tx.tolist(), int(4/1.25e-6)) 313 | else: 314 | self.spi.xfer(tx.tolist(), int(4/1.0e-6)) 315 | 316 | def show(self, mode = 1): 317 | if mode == 1: 318 | write_ws2812 = self.write_ws2812_numpy8 319 | else: 320 | write_ws2812 = self.write_ws2812_numpy4 321 | write_ws2812() 322 | 323 | def wheel(self, pos): 324 | if pos < 85: 325 | return [(255 - pos * 3), (pos * 3), 0] 326 | elif pos < 170: 327 | pos = pos - 85 328 | return [0, (255 - pos * 3), (pos * 3)] 329 | else: 330 | pos = pos - 170 331 | return [(pos * 3), 0, (255 - pos * 3)] 332 | 333 | def hsv2rgb(self, h, s, v): 334 | h = h % 360 335 | rgb_max = round(v * 2.55) 336 | rgb_min = round(rgb_max * (100 - s) / 100) 337 | i = round(h / 60) 338 | diff = round(h % 60) 339 | rgb_adj = round((rgb_max - rgb_min) * diff / 60) 340 | if i == 0: 341 | r = rgb_max 342 | g = rgb_min + rgb_adj 343 | b = rgb_min 344 | elif i == 1: 345 | r = rgb_max - rgb_adj 346 | g = rgb_max 347 | b = rgb_min 348 | elif i == 2: 349 | r = rgb_min 350 | g = rgb_max 351 | b = rgb_min + rgb_adj 352 | elif i == 3: 353 | r = rgb_min 354 | g = rgb_max - rgb_adj 355 | b = rgb_max 356 | elif i == 4: 357 | r = rgb_min + rgb_adj 358 | g = rgb_min 359 | b = rgb_max 360 | else: 361 | r = rgb_max 362 | g = rgb_min 363 | b = rgb_max - rgb_adj 364 | return [r, g, b] 365 | 366 | def police(self): 367 | self.lightMode = 'police' 368 | self.resume() 369 | 370 | def breath(self, R_input, G_input, B_input): 371 | self.lightMode = 'breath' 372 | self.colorBreathR = R_input 373 | self.colorBreathG = G_input 374 | self.colorBreathB = B_input 375 | self.resume() 376 | 377 | def rainbow(self, R_input, G_input, B_input): 378 | self.lightMode = 'rainbow' 379 | self.rainbow_r = R_input 380 | self.rainbow_g = G_input 381 | self.rainbow_b = B_input 382 | self.resume() 383 | 384 | def flowing(self, R_input, G_input, B_input): 385 | self.lightMode = 'flowing' 386 | self.colorFlowingR = R_input 387 | self.colorFlowingG = G_input 388 | self.colorFlowingB = B_input 389 | self.resume() 390 | 391 | def resume(self): 392 | self.__flag.set() 393 | 394 | 395 | 396 | def pause(self): 397 | self.lightMode = 'none' 398 | self.set_all_led_color_data(0,0,0) 399 | self.__flag.clear() 400 | 401 | def breathProcessing(self): 402 | while self.lightMode == 'breath': 403 | for i in range(0,self.breathSteps): 404 | if self.lightMode != 'breath': 405 | break 406 | self.set_all_led_color(self.colorBreathR*i/self.breathSteps, self.colorBreathG*i/self.breathSteps, self.colorBreathB*i/self.breathSteps) 407 | time.sleep(0.03) 408 | for i in range(0,self.breathSteps): 409 | if self.lightMode != 'breath': 410 | break 411 | self.set_all_led_color(self.colorBreathR-(self.colorBreathR*i/self.breathSteps), self.colorBreathG-(self.colorBreathG*i/self.breathSteps), self.colorBreathB-(self.colorBreathB*i/self.breathSteps)) 412 | time.sleep(0.03) 413 | 414 | def policeProcessing(self): 415 | while self.lightMode == 'police': 416 | for i in range(0,3): 417 | self.set_all_led_color_data(0,0,255) 418 | self.show() 419 | time.sleep(0.05) 420 | self.set_all_led_color_data(0,0,0) 421 | self.show() 422 | time.sleep(0.05) 423 | if self.lightMode != 'police': 424 | break 425 | time.sleep(0.1) 426 | for i in range(0,3): 427 | self.set_all_led_color_data(255,0,0) 428 | self.show() 429 | time.sleep(0.05) 430 | self.set_all_led_color_data(0,0,0) 431 | self.show() 432 | time.sleep(0.05) 433 | time.sleep(0.1) 434 | 435 | def rainbowProcessing(self): 436 | while self.lightMode == 'rainbow': 437 | for i in range(self.led_count): 438 | self.rainbow_r = self.rainbow_r + i * 10 439 | self.rainbow_g = self.rainbow_g + i * 10 440 | self.rainbow_b = self.rainbow_b + i * 10 441 | if self.rainbow_r > 255: 442 | self.rainbow_r -= 255 443 | if self.rainbow_g > 255: 444 | self.rainbow_g -= 255 445 | if self.rainbow_b > 255: 446 | self.rainbow_b -= 255 447 | self.set_led_color(i, self.rainbow_r + i * 10,self.rainbow_g,self.rainbow_b) 448 | self.show() 449 | self.lightMode = 'none' 450 | 451 | def flowingProcessing(self): 452 | while self.lightMode == 'flowing': 453 | self.set_all_led_rgb_data([0, 0, 0]) 454 | for i in range(self.led_count): 455 | self.set_led_color(i, self.colorFlowingR,self.rainbow_g,self.colorFlowingR) 456 | time.sleep(0.2) 457 | self.show() 458 | time.sleep(0.2) 459 | 460 | 461 | def lightChange(self): 462 | if self.lightMode == 'none': 463 | self.pause() 464 | elif self.lightMode == 'police': 465 | self.policeProcessing() 466 | elif self.lightMode == 'breath': 467 | self.breathProcessing() 468 | elif self.lightMode == 'rainbow': 469 | self.rainbowProcessing() 470 | elif self.lightMode == 'flowing': 471 | self.flowingProcessing() 472 | 473 | def run(self): 474 | while 1: 475 | self.__flag.wait() 476 | self.lightChange() 477 | pass 478 | 479 | 480 | 481 | if __name__ == '__main__': 482 | import time 483 | import os 484 | print("spidev version is ", spidev.__version__) 485 | print("spidev device as show:") 486 | 487 | led = Adeept_SPI_LedPixel(8, 255) # Use MOSI for /dev/spidev0 to drive the lights 488 | try: 489 | if led.check_spi_state() != 0: 490 | led.set_led_count(8) 491 | led.set_all_led_color_data(255, 0, 0) 492 | led.show() 493 | time.sleep(0.5) 494 | led.set_all_led_rgb_data([0, 255, 0]) 495 | led.show() 496 | time.sleep(0.5) 497 | led.set_all_led_color(0, 0, 255) 498 | time.sleep(0.5) 499 | led.set_all_led_rgb([0, 255, 255]) 500 | time.sleep(0.5) 501 | 502 | led.set_led_count(12) 503 | led.set_all_led_color_data(255, 255, 0) 504 | for i in range(255): 505 | led.set_led_brightness(i) 506 | led.show() 507 | time.sleep(0.005) 508 | for i in range(255): 509 | led.set_led_brightness(255-i) 510 | led.show() 511 | time.sleep(0.005) 512 | 513 | led.set_led_brightness(20) 514 | while True: 515 | for j in range(255): 516 | for i in range(led.led_count): 517 | led.set_led_rgb_data(i, led.wheel((round(i * 255 / led.led_count) + j)%256)) 518 | led.show() 519 | time.sleep(0.002) 520 | else: 521 | led.led_close() 522 | except KeyboardInterrupt: 523 | led.led_close() 524 | --------------------------------------------------------------------------------