WIP: kw1fox-2/software #13
|
@ -10,3 +10,6 @@ __pycache__
|
|||
*.jpg
|
||||
*.wav
|
||||
*.pdf
|
||||
|
||||
# Dev
|
||||
.vscode
|
||||
|
|
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
After Width: | Height: | Size: 21 KiB |
Binary file not shown.
After Width: | Height: | Size: 27 KiB |
Binary file not shown.
After Width: | Height: | Size: 194 KiB |
Binary file not shown.
|
@ -1,70 +0,0 @@
|
|||
### DISCLAIMER
|
||||
### This is an example Makefile and it MUST be configured to suit your needs.
|
||||
### For detailed explanations about all the available options,
|
||||
### please refer to https://github.com/sudar/Arduino-Makefile/blob/master/arduino-mk-vars.md
|
||||
|
||||
### PROJECT_DIR
|
||||
### This is the path to where you have created/cloned your project
|
||||
PROJECT_DIR = $(shell dirname $(shell pwd))
|
||||
|
||||
### ARDMK_DIR
|
||||
### Path to the Arduino-Makefile directory.
|
||||
ARDMK_DIR = $(PROJECT_DIR)/Arduino-Makefile
|
||||
|
||||
### ARDUINO_DIR
|
||||
### Path to the Arduino application and resources directory.
|
||||
ARDUINO_DIR = /usr/share/arduino
|
||||
|
||||
### USER_LIB_PATH
|
||||
### Path to where the your project's libraries are stored.
|
||||
USER_LIB_PATH := $(realpath $(PROJECT_DIR)/lib)
|
||||
|
||||
### BOARD_TAG & BOARD_SUB
|
||||
### For Arduino IDE 1.0.x
|
||||
### Only BOARD_TAG is needed. It must be set to the board you are currently using. (i.e uno, mega2560, etc.)
|
||||
# BOARD_TAG = mega2560
|
||||
### For Arduino IDE 1.6.x
|
||||
### Both BOARD_TAG and BOARD_SUB are needed. They must be set to the board you are currently using. (i.e BOARD_TAG = uno, mega, etc. & BOARD_SUB = atmega2560, etc.)
|
||||
### Note: for the Arduino Uno, only BOARD_TAG is mandatory and BOARD_SUB can be equal to anything
|
||||
BOARD_TAG = mega
|
||||
BOARD_SUB = atmega2560
|
||||
|
||||
### MONITOR_PORT
|
||||
### The port your board is connected to. Using an '*' tries all the ports and finds the right one. Choose one of the two.
|
||||
MONITOR_PORT = /dev/ttyUSB*
|
||||
# MONITOR_PORT = /dev/ttyACM*
|
||||
|
||||
### MONITOR_BAUDRATE
|
||||
### It must be set to Serial baudrate value you are using.
|
||||
MONITOR_BAUDRATE = 115200
|
||||
|
||||
### AVR_TOOLS_DIR
|
||||
### Path to the AVR tools directory such as avr-gcc, avr-g++, etc.
|
||||
AVR_TOOLS_DIR = /usr
|
||||
|
||||
### AVRDUDE
|
||||
### Path to avrdude directory.
|
||||
AVRDUDE = /usr/bin/avrdude
|
||||
|
||||
### CFLAGS_STD
|
||||
CFLAGS_STD = -std=gnu11
|
||||
|
||||
### CXXFLAGS_STD
|
||||
### You can choose wich ever you like
|
||||
# CXXFLAGS_STD = -std=gnu++11
|
||||
CXXFLAGS_STD = -std=gnu++17
|
||||
|
||||
|
||||
### CPPFLAGS
|
||||
### Flags you might want to set for debugging purpose. Comment to stop.
|
||||
CXXFLAGS += -pedantic -Wall -Wextra
|
||||
LDFLAGS += -fdiagnostics-color
|
||||
|
||||
### OBJDIR
|
||||
### Don't touch this!
|
||||
### This is were you put the binaries you just compile using 'make'
|
||||
CURRENT_DIR = $(shell basename $(CURDIR))
|
||||
OBJDIR = $(PROJECT_DIR)/build/$(CURRENT_DIR)/$(BOARD_TAG)
|
||||
|
||||
### path to Arduino.mk, inside the ARDMK_DIR, don't touch.
|
||||
include $(ARDMK_DIR)/Arduino.mk
|
|
@ -1,63 +0,0 @@
|
|||
/* Crawler Slave
|
||||
*
|
||||
* This code runs on the crawler i2c network
|
||||
* and provides a cleaner, less CPU intensive control over PWM devices.
|
||||
*/
|
||||
|
||||
#include <Wire.h>
|
||||
#include <Servo.h>
|
||||
|
||||
// This servo is used to wipe and clean the camera lens
|
||||
Servo windowWiperServo;
|
||||
|
||||
// Variables populated over i2c from master
|
||||
int id;
|
||||
int val;
|
||||
|
||||
void setup() {
|
||||
// For debugging
|
||||
//Serial.begin(115200);
|
||||
|
||||
// Attach the wiper servo to pin 9
|
||||
windowWiperServo.attach(9);
|
||||
|
||||
// This is the address the pi will speak to us at
|
||||
Wire.begin(0x4);
|
||||
|
||||
// Call receiveEvent when data received
|
||||
Wire.onReceive(receiveEvent);
|
||||
|
||||
// Setup LED
|
||||
pinMode(LED_BUILTIN, OUTPUT);
|
||||
digitalWrite(LED_BUILTIN, LOW);
|
||||
|
||||
//Serial.println("Started");
|
||||
}
|
||||
|
||||
// Just loop to keep the running code alive, and wait for events to happen.
|
||||
void loop() {
|
||||
delay(50);
|
||||
}
|
||||
|
||||
// This method runs when we receive a message
|
||||
void receiveEvent(int n) {
|
||||
Wire.read(); // Remove smbus trash
|
||||
if (true) { // Dont do anything if this is not true
|
||||
id = Wire.read(); // ID of the servo/device to access
|
||||
val = Wire.read(); // Value to assign
|
||||
|
||||
//Serial.println(id);
|
||||
//Serial.println(val);
|
||||
|
||||
switch(id) {
|
||||
case 1:
|
||||
windowWiperServo.write(val);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Prevents a bug where if bytes are left in buffer, arduino crashes.
|
||||
while (Wire.available()) {
|
||||
Wire.read();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
# Joe wrote this
|
||||
|
||||
install:
|
||||
sudo cp qsstv.service /etc/systemd/system/qsstv.service
|
||||
sudo cp robotstreamer.service /etc/systemd/system/robotstreamer.service
|
||||
sudo systemctl daemon-reload
|
||||
sudo systemctl enable qsstv.service
|
||||
sudo systemctl enable robotstreamer.service
|
|
@ -0,0 +1,12 @@
|
|||
[[source]]
|
||||
url = "https://pypi.org/simple"
|
||||
verify_ssl = true
|
||||
name = "pypi"
|
||||
|
||||
[packages]
|
||||
xlib = "*"
|
||||
pillow = "*"
|
||||
|
||||
[dev-packages]
|
||||
|
||||
[requires]
|
|
@ -0,0 +1,78 @@
|
|||
{
|
||||
"_meta": {
|
||||
"hash": {
|
||||
"sha256": "d38f5cc73695023ab5e5dc66a552a8d0bb9d3842a276ca547364ce1d6baaf5b9"
|
||||
},
|
||||
"pipfile-spec": 6,
|
||||
"requires": {},
|
||||
"sources": [
|
||||
{
|
||||
"name": "pypi",
|
||||
"url": "https://pypi.org/simple",
|
||||
"verify_ssl": true
|
||||
}
|
||||
]
|
||||
},
|
||||
"default": {
|
||||
"pillow": {
|
||||
"hashes": [
|
||||
"sha256:01ce45deec9df310cbbee11104bae1a2a43308dd9c317f99235b6d3080ddd66e",
|
||||
"sha256:0c51cb9edac8a5abd069fd0758ac0a8bfe52c261ee0e330f363548aca6893595",
|
||||
"sha256:17869489de2fce6c36690a0c721bd3db176194af5f39249c1ac56d0bb0fcc512",
|
||||
"sha256:21dee8466b42912335151d24c1665fcf44dc2ee47e021d233a40c3ca5adae59c",
|
||||
"sha256:25023a6209a4d7c42154073144608c9a71d3512b648a2f5d4465182cb93d3477",
|
||||
"sha256:255c9d69754a4c90b0ee484967fc8818c7ff8311c6dddcc43a4340e10cd1636a",
|
||||
"sha256:35be4a9f65441d9982240e6966c1eaa1c654c4e5e931eaf580130409e31804d4",
|
||||
"sha256:3f42364485bfdab19c1373b5cd62f7c5ab7cc052e19644862ec8f15bb8af289e",
|
||||
"sha256:3fddcdb619ba04491e8f771636583a7cc5a5051cd193ff1aa1ee8616d2a692c5",
|
||||
"sha256:463acf531f5d0925ca55904fa668bb3461c3ef6bc779e1d6d8a488092bdee378",
|
||||
"sha256:4fe29a070de394e449fd88ebe1624d1e2d7ddeed4c12e0b31624561b58948d9a",
|
||||
"sha256:55dd1cf09a1fd7c7b78425967aacae9b0d70125f7d3ab973fadc7b5abc3de652",
|
||||
"sha256:5a3ecc026ea0e14d0ad7cd990ea7f48bfcb3eb4271034657dc9d06933c6629a7",
|
||||
"sha256:5cfca31ab4c13552a0f354c87fbd7f162a4fafd25e6b521bba93a57fe6a3700a",
|
||||
"sha256:66822d01e82506a19407d1afc104c3fcea3b81d5eb11485e593ad6b8492f995a",
|
||||
"sha256:69e5ddc609230d4408277af135c5b5c8fe7a54b2bdb8ad7c5100b86b3aab04c6",
|
||||
"sha256:6b6d4050b208c8ff886fd3db6690bf04f9a48749d78b41b7a5bf24c236ab0165",
|
||||
"sha256:7a053bd4d65a3294b153bdd7724dce864a1d548416a5ef61f6d03bf149205160",
|
||||
"sha256:82283af99c1c3a5ba1da44c67296d5aad19f11c535b551a5ae55328a317ce331",
|
||||
"sha256:8782189c796eff29dbb37dd87afa4ad4d40fc90b2742704f94812851b725964b",
|
||||
"sha256:8d79c6f468215d1a8415aa53d9868a6b40c4682165b8cb62a221b1baa47db458",
|
||||
"sha256:97bda660702a856c2c9e12ec26fc6d187631ddfd896ff685814ab21ef0597033",
|
||||
"sha256:a325ac71914c5c043fa50441b36606e64a10cd262de12f7a179620f579752ff8",
|
||||
"sha256:a336a4f74baf67e26f3acc4d61c913e378e931817cd1e2ef4dfb79d3e051b481",
|
||||
"sha256:a598d8830f6ef5501002ae85c7dbfcd9c27cc4efc02a1989369303ba85573e58",
|
||||
"sha256:a5eaf3b42df2bcda61c53a742ee2c6e63f777d0e085bbc6b2ab7ed57deb13db7",
|
||||
"sha256:aea7ce61328e15943d7b9eaca87e81f7c62ff90f669116f857262e9da4057ba3",
|
||||
"sha256:af79d3fde1fc2e33561166d62e3b63f0cc3e47b5a3a2e5fea40d4917754734ea",
|
||||
"sha256:c24f718f9dd73bb2b31a6201e6db5ea4a61fdd1d1c200f43ee585fc6dcd21b34",
|
||||
"sha256:c5b0ff59785d93b3437c3703e3c64c178aabada51dea2a7f2c5eccf1bcf565a3",
|
||||
"sha256:c7110ec1701b0bf8df569a7592a196c9d07c764a0a74f65471ea56816f10e2c8",
|
||||
"sha256:c870193cce4b76713a2b29be5d8327c8ccbe0d4a49bc22968aa1e680930f5581",
|
||||
"sha256:c9efef876c21788366ea1f50ecb39d5d6f65febe25ad1d4c0b8dff98843ac244",
|
||||
"sha256:de344bcf6e2463bb25179d74d6e7989e375f906bcec8cb86edb8b12acbc7dfef",
|
||||
"sha256:eb1b89b11256b5b6cad5e7593f9061ac4624f7651f7a8eb4dfa37caa1dfaa4d0",
|
||||
"sha256:ed742214068efa95e9844c2d9129e209ed63f61baa4d54dbf4cf8b5e2d30ccf2",
|
||||
"sha256:f401ed2bbb155e1ade150ccc63db1a4f6c1909d3d378f7d1235a44e90d75fb97",
|
||||
"sha256:fb89397013cf302f282f0fc998bb7abf11d49dcff72c8ecb320f76ea6e2c5717"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==9.1.0"
|
||||
},
|
||||
"six": {
|
||||
"hashes": [
|
||||
"sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926",
|
||||
"sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"
|
||||
],
|
||||
"version": "==1.16.0"
|
||||
},
|
||||
"xlib": {
|
||||
"hashes": [
|
||||
"sha256:60b7cd5d90f5d5922d9ce27b61589c07d970796558d417461db7b66e366bc401",
|
||||
"sha256:8eee67dad83ef4b82bbbfa85d51eeb20c79d12b119fe25aa1d27bd602ff82212"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==0.21"
|
||||
}
|
||||
},
|
||||
"develop": {}
|
||||
}
|
|
@ -0,0 +1,148 @@
|
|||
import time
|
||||
import subprocess as sp
|
||||
|
||||
from Xlib import display, X
|
||||
from PIL import Image, ImageFont, ImageDraw
|
||||
|
||||
|
||||
class Streamer:
|
||||
def __init__(self):
|
||||
self.x1, self.y1 = 580, 620
|
||||
|
||||
# Create display
|
||||
self.dsp = display.Display(":0")
|
||||
|
||||
# This is the root of the screen
|
||||
self.root = self.dsp.screen().root
|
||||
|
||||
# ffmpeg command
|
||||
|
||||
# ffmpeg --stream_loop -1 -re -i ~/INPUT_FILE -vcodec libx264 -profile:v main -preset:v medium -r 20 -g 60 -keyint_min 60 -sc_threshold 0 -b:v 2500k -maxrate 2500k -bufsize 2500k -sws_flags lanczos+accurate_rnd -acodec aac -b:a 96k -ar 48000 -ac 2 -f flv rtmp://rtmp.robotstreamer.com/live/123?key=123"
|
||||
cmd_out = [
|
||||
"ffmpeg",
|
||||
"-f",
|
||||
"image2pipe",
|
||||
"-vcodec",
|
||||
"png",
|
||||
"-r",
|
||||
"5", # FPS
|
||||
"-i",
|
||||
"-", # Indicated input comes from pipe
|
||||
"-vcodec",
|
||||
"libx264",
|
||||
"-profile:v",
|
||||
"main",
|
||||
"-pix_fmt",
|
||||
"yuv420p",
|
||||
"-preset:v",
|
||||
"medium",
|
||||
"-r",
|
||||
"30",
|
||||
"-g",
|
||||
"60",
|
||||
"-keyint_min",
|
||||
"60",
|
||||
"-sc_threshold",
|
||||
"0",
|
||||
"-b:v",
|
||||
"2500k",
|
||||
"-maxrate",
|
||||
"1500k",
|
||||
"-bufsize",
|
||||
"1500k",
|
||||
"-sws_flags",
|
||||
"lanczos+accurate_rnd",
|
||||
"-acodec",
|
||||
"aac",
|
||||
"-b:a",
|
||||
"96k",
|
||||
"-r",
|
||||
"6",
|
||||
"-ar",
|
||||
"48000",
|
||||
"-ac",
|
||||
"2",
|
||||
"-f",
|
||||
"flv",
|
||||
"rtmp://rtmp.robotstreamer.com/live/topkek",
|
||||
]
|
||||
|
||||
# This is the ffmpeg pipe streamer!
|
||||
self.pipe = sp.Popen(cmd_out, stdin=sp.PIPE)
|
||||
|
||||
# Graphics and resources
|
||||
self.font = ImageFont.truetype(r"../../Resources/RadioFont.ttf", 20)
|
||||
|
||||
def getFrame(self):
|
||||
"""
|
||||
Returns a single cropped sstv video frame
|
||||
"""
|
||||
|
||||
raw = self.root.get_image(0, 0, self.x1, self.y1, X.ZPixmap, 0xFFFFFFFF)
|
||||
image = Image.frombytes("RGB", (self.x1, self.y1), raw.data, "raw", "BGRX")
|
||||
|
||||
image = image.crop((0, 182, self.x1, self.y1))
|
||||
|
||||
return image
|
||||
|
||||
def drawGraphics(self, image: Image):
|
||||
"""
|
||||
Draws graphics and sprites over
|
||||
a frame
|
||||
"""
|
||||
|
||||
frame = Image.new(mode="RGB", size=(1280, 720))
|
||||
|
||||
# Scale and paste
|
||||
image = image.resize((960, 720), Image.ANTIALIAS)
|
||||
frame.paste(image)
|
||||
|
||||
# Populate text, normally this should poll or use shared vars!
|
||||
info = f"""
|
||||
KW1FOX-1
|
||||
Online!
|
||||
Volt: N/A
|
||||
Last comm: {int(time.time())}
|
||||
|
||||
KW1FOX-2
|
||||
Offline.
|
||||
Volt: N/A
|
||||
Last comm: N/A
|
||||
|
||||
KW1FOX-3
|
||||
Offline.
|
||||
Volt: N/A
|
||||
Last comm: N/A
|
||||
|
||||
Currently Showing:
|
||||
KW1FOX-1
|
||||
NOCOM
|
||||
NOMETA
|
||||
"""
|
||||
|
||||
# Draw text
|
||||
draw = ImageDraw.Draw(frame)
|
||||
draw.text((960 + 10, 10), info, font=self.font, align="left")
|
||||
|
||||
return frame
|
||||
|
||||
def stream(self):
|
||||
"""
|
||||
Actually streams!
|
||||
"""
|
||||
|
||||
while True:
|
||||
self.drawGraphics(self.getFrame()).save(self.pipe.stdin, "PNG")
|
||||
|
||||
def __del__(self):
|
||||
self.dsp.close()
|
||||
|
||||
self.pipe.stdin.close()
|
||||
self.pipe.wait()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
myStreamer = Streamer()
|
||||
|
||||
# myStreamer.drawGraphics(Image.open("../../Resources/KW1FOX-1_320x240.png")).show()
|
||||
myStreamer.stream()
|
|
@ -0,0 +1,13 @@
|
|||
# Notes
|
||||
|
||||
Taking some inspiration from this repo: https://github.com/xssfox/sstv-skimmer/blob/main/Dockerfile
|
||||
|
||||
## Installing qsstv and pulseaudio on server
|
||||
|
||||
Requires `houston` user
|
||||
|
||||
as well as qsstv (obvio)
|
||||
|
||||
and i should prolly install `pulseaudio` as well
|
||||
|
||||
Also, i edited the xorg.conf so it never times out.
|
|
@ -0,0 +1,8 @@
|
|||
[Unit]
|
||||
Description=Runs a qsstv instance as houston with houston's config
|
||||
|
||||
[Service]
|
||||
ExecStart=sudo su -l houston -c "/opt/radio/lewis-crawler/Software/houston/sstv.sh"
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
|
@ -0,0 +1,199 @@
|
|||
[CW]
|
||||
cwWPM=12
|
||||
cwtext=
|
||||
cwtone=800
|
||||
|
||||
[DIRECTORIES]
|
||||
audioPath=/home/parallels/qsstv/audio/
|
||||
docURL=http://users.telenet.be/on4qz/qsstv/manual
|
||||
rxDRMImagesPath=/tmp/rx_images
|
||||
rxSSTVImagesPath=/tmp/rx_images
|
||||
saveTXimages=false
|
||||
templatesPath=/home/parallels/qsstv/templates/
|
||||
txDRMImagesPath=/home/parallels/qsstv/tx_drm/
|
||||
txSSTVImagesPath=/home/parallels/qsstv/tx_sstv/
|
||||
txStockImagesPath=/home/parallels/qsstv/tx_stock/
|
||||
|
||||
[DRMPROFILE]
|
||||
drmPF1Bandwidth=0
|
||||
drmPF1Interleave=0
|
||||
drmPF1Mode=0
|
||||
drmPF1Name=Profile 1
|
||||
drmPF1Protection=0
|
||||
drmPF1QAM=0
|
||||
drmPF1ReedSolomon=0
|
||||
drmPF2Bandwidth=0
|
||||
drmPF2Interleave=0
|
||||
drmPF2Mode=0
|
||||
drmPF2Name=Profile 2
|
||||
drmPF2Protection=0
|
||||
drmPF2QAM=0
|
||||
drmPF2ReedSolomon=0
|
||||
drmPF3Bandwidth=0
|
||||
drmPF3Interleave=0
|
||||
drmPF3Mode=0
|
||||
drmPF3Name=Profile 3
|
||||
drmPF3Protection=0
|
||||
drmPF3QAM=0
|
||||
drmPF3ReedSolomon=0
|
||||
|
||||
[FREQSELECT]
|
||||
additionalCommand=
|
||||
additionalCommandHex=false
|
||||
frequencyList=@Invalid()
|
||||
modeList=@Invalid()
|
||||
passBandList=@Invalid()
|
||||
sbModeList=@Invalid()
|
||||
|
||||
[FTPCONFIG]
|
||||
addExtension=false
|
||||
enableFTP=false
|
||||
ftpDefaultImageFormat=png
|
||||
ftpLogin=
|
||||
ftpNumImages=30
|
||||
ftpPassword=
|
||||
ftpPort=21
|
||||
ftpRemoteDRMDirectory=
|
||||
ftpRemoteHost=
|
||||
ftpRemoteSSTVDirectory=
|
||||
ftpSaveFormat=0
|
||||
|
||||
[GUI]
|
||||
backGroundColor=@Variant(\0\0\0\x43\x1\xff\xff\0\0VV\xe6\xe6\0\0)
|
||||
confirmClose=true
|
||||
confirmDeletion=true
|
||||
galleryColumns=4
|
||||
galleryRows=4
|
||||
imageBackGroundColor=@Variant(\0\0\0\x43\x1\xff\xff\x80\x80\x80\x80\x80\x80\0\0)
|
||||
imageStretch=true
|
||||
lowRes=false
|
||||
slowCPU=false
|
||||
|
||||
[HYBRID]
|
||||
enableHybridNotify=true
|
||||
enableHybridRx=true
|
||||
hybridFtpHybridFilesDirectory=HybridFiles1
|
||||
hybridFtpLogin=
|
||||
hybridFtpPassword=
|
||||
hybridFtpPort=21
|
||||
hybridFtpRemoteDirectory=
|
||||
hybridFtpRemoteHost=
|
||||
hybridNotifyDir=RxOkNotifications1
|
||||
onlineStatusDir=OnlineCallsigns1
|
||||
|
||||
[MAIN]
|
||||
transmissionModeIndex=0
|
||||
windowHeight=768
|
||||
windowWidth=1024
|
||||
windowX=0
|
||||
windowY=0
|
||||
|
||||
[PERSONAL]
|
||||
callsign=NOCALL
|
||||
firstname=NOFIRSTNAME
|
||||
lastname=NONAME
|
||||
locator=NOLOCATOR
|
||||
onlinestatusenabled=true
|
||||
onlinestatustext=
|
||||
qth=NOWHERE
|
||||
|
||||
[REPEATER]
|
||||
repeaterAcknowledge=
|
||||
repeaterEnabled=false
|
||||
repeaterIdleTemplate=
|
||||
repeaterIdleTxMode=0
|
||||
repeaterImage1=
|
||||
repeaterImage2=
|
||||
repeaterImage3=
|
||||
repeaterImage4=
|
||||
repeaterImageInterval=10
|
||||
repeaterImageSize=10
|
||||
repeaterTemplate=
|
||||
repeaterTxDelay=5
|
||||
repeaterTxMode=0
|
||||
|
||||
[RX]
|
||||
autoSave=true
|
||||
autoSlantAdjust=true
|
||||
defaultImageFormat=png
|
||||
minCompletion=50
|
||||
sensitivity=2
|
||||
sstvModeIndexRx=10
|
||||
|
||||
[SOUND]
|
||||
alsaSelected=false
|
||||
inputAudioDevice=default -- Playback/recording through the PulseAudio sound server
|
||||
outputAudioDevice=default -- Playback/recording through the PulseAudio sound server
|
||||
pttToneOtherChannel=false
|
||||
pulseSelected=true
|
||||
recordingSize=100
|
||||
rxclock=48000
|
||||
soundRoutingInput=0
|
||||
soundRoutingOutput=0
|
||||
swapChannel=false
|
||||
txclock=48000
|
||||
|
||||
[SPECTRUM]
|
||||
avg=0.9
|
||||
maxdb=-25
|
||||
range=35
|
||||
|
||||
[TX]
|
||||
compressedSize=5000
|
||||
drmBandWith=0
|
||||
drmInterLeaver=0
|
||||
drmProtection=0
|
||||
drmQAM=0
|
||||
drmReedSolomon=0
|
||||
drmRobMode=0
|
||||
sstvModeIndexTx=0
|
||||
templateIndex=-1
|
||||
useCW=false
|
||||
useHybrid=false
|
||||
useTemplate=false
|
||||
useVOX=false
|
||||
|
||||
[WATERFALL]
|
||||
bsrWF=BSR
|
||||
endBinWF=END BIN
|
||||
endPicWF=END PIC
|
||||
endRepeaterWF=END RPT
|
||||
fixWF=FIX
|
||||
sampleString=Sample Text
|
||||
startBinWF=START BIN
|
||||
startPicWF=START PIC
|
||||
startRepeaterWF=START RPT
|
||||
wfBold=false
|
||||
wfFont=Aharoni CLM
|
||||
wfFontSize=12
|
||||
|
||||
[Waterfall]
|
||||
text1=rest
|
||||
text2=
|
||||
text3=
|
||||
text4=
|
||||
|
||||
[logging]
|
||||
deduplicate=true
|
||||
maskBA="@Variant(\0\0\0\r\0\0\0,\0\0\0\0\0\0)"
|
||||
|
||||
[radio1]
|
||||
XMLRPCPort=7362
|
||||
activeDTR=false
|
||||
activeRTS=true
|
||||
baudrate=9600
|
||||
civAddress=
|
||||
databits=8
|
||||
enableCAT=false
|
||||
enableSerialPTT=false
|
||||
enableXMLRPC=false
|
||||
handshake=None
|
||||
nactiveDTR=false
|
||||
nactiveRTS=false
|
||||
parity=None
|
||||
pttSerialPort=/dev/ttyS0
|
||||
pttType=1
|
||||
radioModel="29001 ADAT www.adat.ch,ADT-200A"
|
||||
serialPort=/dev/ttyS0
|
||||
stopbits=1
|
||||
txOnDelay=0
|
|
@ -0,0 +1,9 @@
|
|||
[Unit]
|
||||
Description=Runs the robotstreamer stream
|
||||
|
||||
[Service]
|
||||
ExecStart=sudo su -l houston -c "/opt/radio/lewis-crawler/Software/houston/stream.sh"
|
||||
Restart=on-failure
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
|
@ -0,0 +1,12 @@
|
|||
#!/bin/bash
|
||||
|
||||
# Runs all the required fluff for spawning qsstv with notifing and stuff.
|
||||
|
||||
# Make tempdirs
|
||||
mkdir -p /tmp/sstv_images
|
||||
|
||||
# Copy config file
|
||||
cp /opt/radio/lewis-crawler/Software/houston/qsstv_9.0.conf ~/.config/ON4QZ/qsstv_9.0.conf
|
||||
|
||||
# Spawn qsstv
|
||||
xinit -geometry =1280x960+0+0 -fn 8x13 -j -fg white -bg black qsstv -- -nocursor
|
|
@ -0,0 +1,5 @@
|
|||
#!/bin/bash
|
||||
|
||||
# Runs the robotstream
|
||||
cd /opt/radio/lewis-crawler/Software/houston/ && pipenv run python RobotStreamer.py
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
[[source]]
|
||||
url = "https://pypi.org/simple"
|
||||
verify_ssl = true
|
||||
name = "pypi"
|
||||
|
||||
[packages]
|
||||
pysstv = "*"
|
||||
pillow = "*"
|
||||
pyaudio = "*"
|
||||
pi-ina219 = "*"
|
||||
|
||||
[dev-packages]
|
||||
|
||||
[requires]
|
||||
python_version = "3.10"
|
|
@ -0,0 +1,121 @@
|
|||
{
|
||||
"_meta": {
|
||||
"hash": {
|
||||
"sha256": "377233137977bb1db670b363317a6a2619ddd8544f91531a5224826022fa3e23"
|
||||
},
|
||||
"pipfile-spec": 6,
|
||||
"requires": {
|
||||
"python_version": "3.10"
|
||||
},
|
||||
"sources": [
|
||||
{
|
||||
"name": "pypi",
|
||||
"url": "https://pypi.org/simple",
|
||||
"verify_ssl": true
|
||||
}
|
||||
]
|
||||
},
|
||||
"default": {
|
||||
"adafruit-gpio": {
|
||||
"hashes": [
|
||||
"sha256:d6465b92c866c51ca8f3bc1e8f2ec36f5ccdb46d0fd54101c1109756d4a2dcd0"
|
||||
],
|
||||
"version": "==1.0.3"
|
||||
},
|
||||
"adafruit-pureio": {
|
||||
"hashes": [
|
||||
"sha256:2caf22fb07c7f771d83267f331a76cde314723f884a9570ea6f768730c87a879"
|
||||
],
|
||||
"markers": "python_full_version >= '3.5.0'",
|
||||
"version": "==1.1.9"
|
||||
},
|
||||
"mock": {
|
||||
"hashes": [
|
||||
"sha256:122fcb64ee37cfad5b3f48d7a7d51875d7031aaf3d8be7c42e2bee25044eee62",
|
||||
"sha256:7d3fbbde18228f4ff2f1f119a45cdffa458b4c0dee32eb4d2bb2f82554bac7bc"
|
||||
],
|
||||
"markers": "python_version >= '3.6'",
|
||||
"version": "==4.0.3"
|
||||
},
|
||||
"pi-ina219": {
|
||||
"hashes": [
|
||||
"sha256:29524cc308c56a5c483f551187923d3e167f2d39a29dc64c731ba7a8e04d022b"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==1.4.0"
|
||||
},
|
||||
"pillow": {
|
||||
"hashes": [
|
||||
"sha256:01ce45deec9df310cbbee11104bae1a2a43308dd9c317f99235b6d3080ddd66e",
|
||||
"sha256:0c51cb9edac8a5abd069fd0758ac0a8bfe52c261ee0e330f363548aca6893595",
|
||||
"sha256:17869489de2fce6c36690a0c721bd3db176194af5f39249c1ac56d0bb0fcc512",
|
||||
"sha256:21dee8466b42912335151d24c1665fcf44dc2ee47e021d233a40c3ca5adae59c",
|
||||
"sha256:25023a6209a4d7c42154073144608c9a71d3512b648a2f5d4465182cb93d3477",
|
||||
"sha256:255c9d69754a4c90b0ee484967fc8818c7ff8311c6dddcc43a4340e10cd1636a",
|
||||
"sha256:35be4a9f65441d9982240e6966c1eaa1c654c4e5e931eaf580130409e31804d4",
|
||||
"sha256:3f42364485bfdab19c1373b5cd62f7c5ab7cc052e19644862ec8f15bb8af289e",
|
||||
"sha256:3fddcdb619ba04491e8f771636583a7cc5a5051cd193ff1aa1ee8616d2a692c5",
|
||||
"sha256:463acf531f5d0925ca55904fa668bb3461c3ef6bc779e1d6d8a488092bdee378",
|
||||
"sha256:4fe29a070de394e449fd88ebe1624d1e2d7ddeed4c12e0b31624561b58948d9a",
|
||||
"sha256:55dd1cf09a1fd7c7b78425967aacae9b0d70125f7d3ab973fadc7b5abc3de652",
|
||||
"sha256:5a3ecc026ea0e14d0ad7cd990ea7f48bfcb3eb4271034657dc9d06933c6629a7",
|
||||
"sha256:5cfca31ab4c13552a0f354c87fbd7f162a4fafd25e6b521bba93a57fe6a3700a",
|
||||
"sha256:66822d01e82506a19407d1afc104c3fcea3b81d5eb11485e593ad6b8492f995a",
|
||||
"sha256:69e5ddc609230d4408277af135c5b5c8fe7a54b2bdb8ad7c5100b86b3aab04c6",
|
||||
"sha256:6b6d4050b208c8ff886fd3db6690bf04f9a48749d78b41b7a5bf24c236ab0165",
|
||||
"sha256:7a053bd4d65a3294b153bdd7724dce864a1d548416a5ef61f6d03bf149205160",
|
||||
"sha256:82283af99c1c3a5ba1da44c67296d5aad19f11c535b551a5ae55328a317ce331",
|
||||
"sha256:8782189c796eff29dbb37dd87afa4ad4d40fc90b2742704f94812851b725964b",
|
||||
"sha256:8d79c6f468215d1a8415aa53d9868a6b40c4682165b8cb62a221b1baa47db458",
|
||||
"sha256:97bda660702a856c2c9e12ec26fc6d187631ddfd896ff685814ab21ef0597033",
|
||||
"sha256:a325ac71914c5c043fa50441b36606e64a10cd262de12f7a179620f579752ff8",
|
||||
"sha256:a336a4f74baf67e26f3acc4d61c913e378e931817cd1e2ef4dfb79d3e051b481",
|
||||
"sha256:a598d8830f6ef5501002ae85c7dbfcd9c27cc4efc02a1989369303ba85573e58",
|
||||
"sha256:a5eaf3b42df2bcda61c53a742ee2c6e63f777d0e085bbc6b2ab7ed57deb13db7",
|
||||
"sha256:aea7ce61328e15943d7b9eaca87e81f7c62ff90f669116f857262e9da4057ba3",
|
||||
"sha256:af79d3fde1fc2e33561166d62e3b63f0cc3e47b5a3a2e5fea40d4917754734ea",
|
||||
"sha256:c24f718f9dd73bb2b31a6201e6db5ea4a61fdd1d1c200f43ee585fc6dcd21b34",
|
||||
"sha256:c5b0ff59785d93b3437c3703e3c64c178aabada51dea2a7f2c5eccf1bcf565a3",
|
||||
"sha256:c7110ec1701b0bf8df569a7592a196c9d07c764a0a74f65471ea56816f10e2c8",
|
||||
"sha256:c870193cce4b76713a2b29be5d8327c8ccbe0d4a49bc22968aa1e680930f5581",
|
||||
"sha256:c9efef876c21788366ea1f50ecb39d5d6f65febe25ad1d4c0b8dff98843ac244",
|
||||
"sha256:de344bcf6e2463bb25179d74d6e7989e375f906bcec8cb86edb8b12acbc7dfef",
|
||||
"sha256:eb1b89b11256b5b6cad5e7593f9061ac4624f7651f7a8eb4dfa37caa1dfaa4d0",
|
||||
"sha256:ed742214068efa95e9844c2d9129e209ed63f61baa4d54dbf4cf8b5e2d30ccf2",
|
||||
"sha256:f401ed2bbb155e1ade150ccc63db1a4f6c1909d3d378f7d1235a44e90d75fb97",
|
||||
"sha256:fb89397013cf302f282f0fc998bb7abf11d49dcff72c8ecb320f76ea6e2c5717"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==9.1.0"
|
||||
},
|
||||
"pyaudio": {
|
||||
"hashes": [
|
||||
"sha256:0d92f6a294565260a282f7c9a0b0d309fc8cc988b5ee5b50645634ab9e2da7f7",
|
||||
"sha256:259bb9c1363be895b4f9a97e320a6017dd06bc540728c1a04eb4a7b6fe75035b",
|
||||
"sha256:2a19bdb8ec1445b4f3e4b7b109e0e4cec1fd1f1ce588592aeb6db0b58d4fb3b0",
|
||||
"sha256:51b558d1b28c68437b53218279110db44f69f3f5dd3d81859f569a4a96962bdc",
|
||||
"sha256:589bfad2c615dd4b5d3757e763019c42ab82f06fba5cae64ec02fd7f5ae407ed",
|
||||
"sha256:8f89075b4844ea94dde0c951c2937581c989fabd4df09bfd3f075035f50955df",
|
||||
"sha256:93bfde30e0b64e63a46f2fd77e85c41fd51182a4a3413d9edfaf9ffaa26efb74",
|
||||
"sha256:cf1543ba50bd44ac0d0ab5c035bb9c3127eb76047ff12235149d9adf86f532b6",
|
||||
"sha256:f78d543a98b730e64621ebf7f3e2868a79ade0a373882ef51c0293455ffa8e6e"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==0.2.11"
|
||||
},
|
||||
"pysstv": {
|
||||
"hashes": [
|
||||
"sha256:a0306ff80bb25f28c4455c9dd75dd8cebbb3fa7d77b87af18e6cf2b86ade6b47"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==0.5.4"
|
||||
},
|
||||
"spidev": {
|
||||
"hashes": [
|
||||
"sha256:8a7f5c289f161ea2ac4697fa8a10918232c990678dd0053084b3c43b1363910d"
|
||||
],
|
||||
"version": "==3.5"
|
||||
}
|
||||
},
|
||||
"develop": {}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
# KW1FOX-2 Software
|
||||
|
||||
This is the software for KW1FOX-2, the APRS/SSTV relay station.
|
|
@ -0,0 +1,29 @@
|
|||
from PIL import Image
|
||||
|
||||
from pysstv.color import Robot36
|
||||
|
||||
from tools.pyaudio import PyAudioSSTV
|
||||
|
||||
|
||||
class kw1fox2:
|
||||
def __init__(self, sim=False):
|
||||
# Lets us automate more testing locally by having a program-wide sim mode.
|
||||
self.sim = sim
|
||||
|
||||
img = Image.open("../../Resources/KW1FOX-1_320x240.png")
|
||||
self.sstv = Robot36(img, 44100, 16)
|
||||
self.sstv.vox_enabled = True
|
||||
|
||||
self.sstv.write_wav("Mysstv.wav")
|
||||
|
||||
def run(self):
|
||||
PyAudioSSTV(self.sstv).execute()
|
||||
|
||||
def take_snapshot(self):
|
||||
if not self.sim:
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
station = kw1fox2()
|
||||
station.run()
|
|
@ -0,0 +1,43 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
"""
|
||||
Example code from here: https://github.com/dnet/pySSTV/blob/master/pysstv/examples/pyaudio_sstv.py
|
||||
"""
|
||||
|
||||
|
||||
from __future__ import division
|
||||
from pysstv.sstv import SSTV
|
||||
from time import sleep
|
||||
from itertools import islice
|
||||
import struct, pyaudio
|
||||
|
||||
|
||||
class PyAudioSSTV(object):
|
||||
def __init__(self, sstv):
|
||||
self.pa = pyaudio.PyAudio()
|
||||
self.sstv = sstv
|
||||
self.fmt = "<" + SSTV.BITS_TO_STRUCT[sstv.bits]
|
||||
|
||||
def __del__(self):
|
||||
self.pa.terminate()
|
||||
|
||||
def execute(self):
|
||||
self.sampler = self.sstv.gen_samples()
|
||||
stream = self.pa.open(
|
||||
format=self.pa.get_format_from_width(self.sstv.bits // 8),
|
||||
channels=1,
|
||||
rate=self.sstv.samples_per_sec,
|
||||
output=True,
|
||||
stream_callback=self.callback,
|
||||
)
|
||||
stream.start_stream()
|
||||
while stream.is_active():
|
||||
sleep(0.5)
|
||||
stream.stop_stream()
|
||||
stream.close()
|
||||
|
||||
def callback(self, in_data, frame_count, time_info, status):
|
||||
frames = "".join(
|
||||
struct.pack(self.fmt, b) for b in islice(self.sampler, frame_count)
|
||||
)
|
||||
return frames, pyaudio.paContinue
|
|
@ -1,5 +0,0 @@
|
|||
wiper_servo:
|
||||
pin: 17
|
||||
min_pulse: 0.000544
|
||||
max_pulse: 0.0024
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
[Unit]
|
||||
Description=Crawler service overseer, manages running main crawler software
|
||||
After=multi-user.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
Restart=always
|
||||
ExecStart=/usr/bin/python /srv/crawler/crawler.py
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
|
@ -1,2 +0,0 @@
|
|||
PySSTV
|
||||
picamera
|
|
@ -1,87 +0,0 @@
|
|||
from shutil import copyfile
|
||||
from PIL import Image, ImageFont, ImageDraw
|
||||
from pysstv import color
|
||||
|
||||
import logging as log
|
||||
|
||||
try:
|
||||
from picamera import PiCamera
|
||||
except ModuleNotFoundError:
|
||||
log.info("Running in simulator mode")
|
||||
|
||||
|
||||
def take_photo():
|
||||
# This def is meant to take a photograph from the robot,
|
||||
# it should include all steps and error checking to raise the mast
|
||||
# Take the photo, and put the mast down.
|
||||
|
||||
# Copy in the test pattern png (if photo process errors out, this will be used instead)
|
||||
log.debug('Copying test pattern.')
|
||||
copyfile('photos/TEST_PATTERN.jpg', 'working/working.jpg')
|
||||
|
||||
# Software to take the photo should be here
|
||||
#copyfile('photos/camera_latest.jpg', 'working/working.jpg')
|
||||
log.debug('Initalizing camera.')
|
||||
try:
|
||||
camera = PiCamera()
|
||||
log.info('Saving photo.')
|
||||
camera.capture('working/working.jpg')
|
||||
except NameError:
|
||||
log.info("Running in simulator mode, not replacing test pattern")
|
||||
|
||||
def mark_photo():
|
||||
log.info('Opening photo for viewing.')
|
||||
raw_img = Image.open("working/working.jpg") # Open the current working image
|
||||
log.info('Resizing image.')
|
||||
img = raw_img.resize((320, 240), Image.ANTIALIAS) # resize it for the radio
|
||||
|
||||
log.info('Drawing on image.')
|
||||
if False:
|
||||
TINT_COLOR = (255, 255, 255) # White text bg
|
||||
TEXT_COLOR = (0,0,0)
|
||||
else:
|
||||
TINT_COLOR = (0, 0, 0) # Black text bg
|
||||
TEXT_COLOR = (255,255,255)
|
||||
TRANSPARENCY = .25 # Degree of transparency, 0-100%
|
||||
OPACITY = int(255 * TRANSPARENCY)
|
||||
overlay = Image.new('RGBA', img.size, TINT_COLOR+(0,))
|
||||
|
||||
draw = ImageDraw.Draw(overlay)
|
||||
#bigfont = ImageFont.truetype(r'C:\Users\System-Pc\Desktop\arial.ttf', 20)
|
||||
#smallfont = ImageFont.truetype(r'C:\Users\System-Pc\Desktop\arial.ttf', 17)
|
||||
|
||||
draw.rectangle(((0, 0), (90, 20)), fill=TINT_COLOR+(OPACITY,))
|
||||
#draw.text((0, 0),"KW1FOX",TEXT_COLOR,font=bigfont) # Draw KW1FOX in the top left
|
||||
|
||||
draw.rectangle(((0, 40), (83, 80)), fill=TINT_COLOR+(OPACITY,))
|
||||
#draw.text((0, 40),"day: 25.2",TEXT_COLOR,font=smallfont)
|
||||
#draw.text((0, 60),"Volt: 13.8",TEXT_COLOR,font=smallfont)
|
||||
#draw.text((0, 80),"Miles: 1.02",TEXT_COLOR,font=smallfont)
|
||||
|
||||
log.info('Converting image color.')
|
||||
img = img.convert("RGBA")
|
||||
img = Image.alpha_composite(img, overlay)
|
||||
img = img.convert("RGB")
|
||||
img.save('working/working.jpg') # Save the working image
|
||||
return img
|
||||
|
||||
if __name__ == "__main__":
|
||||
log.basicConfig(level=log.DEBUG)
|
||||
|
||||
# Take photograph.
|
||||
log.info('Taking Photograph')
|
||||
take_photo() # Saves a photograph to the working/working.jpg location
|
||||
log.info('Done taking photo.')
|
||||
|
||||
# Draw neccicary text on photo
|
||||
log.info('Drawing on photo.')
|
||||
radio_photo = mark_photo() # draws text on working/working.jpg and returns a PIL image
|
||||
log.info('Done drawing on photo.')
|
||||
|
||||
log.info('Creating slowscan.')
|
||||
slowscan = color.Robot36(radio_photo, 48000, 16) # Image, rate, bits
|
||||
#slowscan = color.MartinM1(radio_photo, 48000, 16) # Image, rate, bits
|
||||
log.info('Saving out slowscan.')
|
||||
slowscan.write_wav('working/working.wav')
|
||||
|
||||
#sstv('working/working.png', 'working/radio.wav', mode='Robot36')
|
|
@ -1,73 +0,0 @@
|
|||
from discord_webhook import DiscordWebhook
|
||||
from picamera import PiCamera
|
||||
from time import sleep
|
||||
from gps import *
|
||||
from smbus import SMBus
|
||||
import time
|
||||
|
||||
addr = 0x4 # bus address
|
||||
bus = SMBus(1) # indicates /dev/ic2-1
|
||||
|
||||
numb = 1
|
||||
|
||||
def writeData(value):
|
||||
byteValue = StringToBytes(value)
|
||||
bus.write_i2c_block_data(addr,0x00,byteValue) #first byte is 0=command byte.. just is.
|
||||
return -1
|
||||
|
||||
|
||||
def StringToBytes(val):
|
||||
retVal = []
|
||||
for c in val:
|
||||
retVal.append(ord(c))
|
||||
return retVal
|
||||
|
||||
try:
|
||||
for _x in range (0, 2):
|
||||
for i in range(78, 130):
|
||||
writeData("WIPE-" + str(i))
|
||||
time.sleep(0.02)
|
||||
for i in range(130, 78, -1):
|
||||
writeData("WIPE-" + str(i))
|
||||
time.sleep(0.02)
|
||||
except OSError:
|
||||
print("Could not speak to ardujmemo")
|
||||
|
||||
def get_uptime():
|
||||
with open('/proc/uptime', 'r') as f:
|
||||
uptime_seconds = float(f.readline().split()[0])
|
||||
|
||||
return uptime_seconds
|
||||
|
||||
def getPositionData(gps):
|
||||
location = [None]
|
||||
while(location[0] == None):
|
||||
print("Trying again")
|
||||
nx = gpsd.next()
|
||||
# For a list of all supported classes and fields refer to:
|
||||
# https://gpsd.gitlab.io/gpsd/gpsd_json.html
|
||||
if nx['class'] == 'TPV':
|
||||
latitude = getattr(nx,'lat', "Unknown")
|
||||
longitude = getattr(nx,'lon', "Unknown")
|
||||
#print "Your position: lon = " + str(longitude) + ", lat = " + str(latitude)
|
||||
location = [latitude, longitude]
|
||||
return location
|
||||
|
||||
gpsd = gps(mode=WATCH_ENABLE|WATCH_NEWSTYLE)
|
||||
|
||||
loc = getPositionData(gpsd)
|
||||
|
||||
webhookURL = "https://discord.com/api/webhooks/856609966404534272/TR9tnLq2sIGZoOeADNswmGRNlzBcqM5aKihfU6snVTP9WhSSoVVvi7nT6i-ZfZS7Hcqm"
|
||||
|
||||
print(loc[0])
|
||||
print(loc[1])
|
||||
webhook = DiscordWebhook(url=webhookURL, content="Uptime: " + str( round( ((get_uptime() / 60) / 60 ), 2 )) + " hours. Lat is " + str(loc[0]) + ", long is " + str(loc[1]))
|
||||
|
||||
camera = PiCamera()
|
||||
sleep(3) # let iso settle out
|
||||
camera.capture('still.jpg')
|
||||
|
||||
with open("still.jpg", "rb") as f:
|
||||
webhook.add_file(file=f.read(), filename='still.jpg')
|
||||
response = webhook.execute() # Hit send
|
||||
|
|
@ -1,19 +0,0 @@
|
|||
import RPi.GPIO as GPIO
|
||||
import time
|
||||
|
||||
servoPIN = 17
|
||||
GPIO.setmode(GPIO.BCM)
|
||||
GPIO.setup(servoPIN, GPIO.OUT)
|
||||
|
||||
p = GPIO.PWM(servoPIN, 50) # GPIO 17 for PWM with 50Hz
|
||||
p.start(2.5) # Initialization
|
||||
try:
|
||||
while True:
|
||||
p.ChangeDutyCycle(10)
|
||||
time.sleep(2)
|
||||
p.ChangeDutyCycle(2.5)
|
||||
time.sleep(2)
|
||||
except KeyboardInterrupt:
|
||||
p.stop()
|
||||
GPIO.cleanup()
|
||||
|
|
@ -1,20 +0,0 @@
|
|||
import smbus
|
||||
import time
|
||||
import struct
|
||||
|
||||
# for RPI version 1, use bus = smbus.SMBus(0)
|
||||
bus = smbus.SMBus(1)
|
||||
|
||||
# This is the address we setup in the Arduino Program
|
||||
address = 0x04
|
||||
|
||||
try:
|
||||
for _x in range (0, 2):
|
||||
for i in range(78, 130):
|
||||
bus.write_i2c_block_data(address, 0, [1, i])
|
||||
time.sleep(0.02)
|
||||
for i in range(130, 78, -1):
|
||||
bus.write_i2c_block_data(address, 0, [1, i])
|
||||
time.sleep(0.02)
|
||||
except OSError:
|
||||
print("Could not speak to ardujmemo")
|
|
@ -1,35 +0,0 @@
|
|||
# Raspberry Pi Master for Arduino Slave
|
||||
# i2c_master_pi.py
|
||||
# Connects to Arduino via I2C
|
||||
|
||||
# DroneBot Workshop 2019
|
||||
# https://dronebotworkshop.com
|
||||
|
||||
from smbus import SMBus
|
||||
import time
|
||||
|
||||
addr = 0x8 # bus address
|
||||
bus = SMBus(1) # indicates /dev/ic2-1
|
||||
|
||||
numb = 1
|
||||
|
||||
print ("Enter num")
|
||||
|
||||
for _x in range (0, 4):
|
||||
for i in range(76, 130):
|
||||
bus.write_byte(addr, i)
|
||||
time.sleep(0.02)
|
||||
for i in range(130, 76, -1):
|
||||
bus.write_byte(addr, i)
|
||||
time.sleep(0.02)
|
||||
|
||||
#while numb == 1:
|
||||
#
|
||||
# ledstate = input(">>>> ")
|
||||
#
|
||||
# if ledstate == "1":
|
||||
# bus.write_byte(addr, 0x1) # switch it on
|
||||
# elif ledstate == "0":
|
||||
# bus.write_byte(addr, 0x0) # switch it on
|
||||
# else:
|
||||
# numb = 0
|
|
@ -1,12 +0,0 @@
|
|||
import RPi.GPIO as GPIO # Import Raspberry Pi GPIO library
|
||||
from time import sleep # Import the sleep function from the time module
|
||||
|
||||
GPIO.setwarnings(False) # Ignore warning for now
|
||||
GPIO.setmode(GPIO.BOARD) # Use physical pin numbering
|
||||
GPIO.setup(12, GPIO.OUT, initial=GPIO.LOW) # Set pin 8 to be an output pin and set initial value to low (off)
|
||||
|
||||
while True: # Run forever
|
||||
GPIO.output(12, GPIO.HIGH) # Turn on
|
||||
sleep(1) # Sleep for 1 second
|
||||
GPIO.output(12, GPIO.LOW) # Turn off
|
||||
sleep(1) # Sleep for 1 second
|
Loading…
Reference in New Issue