From c30e47c260325f303098d0ea56aac5d75e94ddee Mon Sep 17 00:00:00 2001 From: Pavol Debnar Date: Tue, 16 May 2023 16:48:21 +0200 Subject: [PATCH] addition of camera scripts --- camera/raspberry/client.py | 36 ++++++ camera/raspberry/focus.sh | 1 + camera/raspberry/lights/Makefile | 40 ++++++ camera/raspberry/lights/build/LEDs.o | Bin 0 -> 2120 bytes camera/raspberry/lights/build/adxl345.o | Bin 0 -> 8808 bytes camera/raspberry/lights/build/demo.o | Bin 0 -> 2872 bytes camera/raspberry/lights/build/fan.o | Bin 0 -> 1824 bytes camera/raspberry/lights/build/sick_front.o | Bin 0 -> 4688 bytes camera/raspberry/lights/build/sick_side.o | Bin 0 -> 14616 bytes camera/raspberry/lights/lights | Bin 0 -> 31424 bytes camera/raspberry/lights/src/LEDs.cpp | 16 +++ camera/raspberry/lights/src/LEDs.hpp | 45 +++++++ camera/raspberry/lights/src/adxl345.cpp | 104 +++++++++++++++ camera/raspberry/lights/src/adxl345.hpp | 124 ++++++++++++++++++ camera/raspberry/lights/src/demo.cpp | 21 +++ camera/raspberry/lights/src/demo.hpp | 12 ++ camera/raspberry/lights/src/fan.cpp | 14 ++ camera/raspberry/lights/src/fan.hpp | 34 +++++ camera/raspberry/lights/src/sick_front.cpp | 61 +++++++++ camera/raspberry/lights/src/sick_front.hpp | 134 ++++++++++++++++++++ camera/raspberry/lights/src/sick_side.cpp | 103 +++++++++++++++ camera/raspberry/lights/src/sick_side.hpp | 119 +++++++++++++++++ camera/raspberry/makefile | 6 + camera/raspberry/sensors/Makefile | 40 ++++++ camera/raspberry/sensors/build/LEDs.o | Bin 0 -> 2120 bytes camera/raspberry/sensors/build/adxl345.o | Bin 0 -> 8808 bytes camera/raspberry/sensors/build/demo.o | Bin 0 -> 6976 bytes camera/raspberry/sensors/build/fan.o | Bin 0 -> 1824 bytes camera/raspberry/sensors/build/sick_front.o | Bin 0 -> 4688 bytes camera/raspberry/sensors/build/sick_side.o | Bin 0 -> 14616 bytes camera/raspberry/sensors/sensors | Bin 0 -> 31632 bytes camera/raspberry/sensors/src/LEDs.cpp | 16 +++ camera/raspberry/sensors/src/LEDs.hpp | 45 +++++++ camera/raspberry/sensors/src/adxl345.cpp | 104 +++++++++++++++ camera/raspberry/sensors/src/adxl345.hpp | 124 ++++++++++++++++++ camera/raspberry/sensors/src/demo.cpp | 43 +++++++ camera/raspberry/sensors/src/demo.hpp | 12 ++ camera/raspberry/sensors/src/fan.cpp | 14 ++ camera/raspberry/sensors/src/fan.hpp | 34 +++++ camera/raspberry/sensors/src/sick_front.cpp | 61 +++++++++ camera/raspberry/sensors/src/sick_front.hpp | 134 ++++++++++++++++++++ camera/raspberry/sensors/src/sick_side.cpp | 103 +++++++++++++++ camera/raspberry/sensors/src/sick_side.hpp | 119 +++++++++++++++++ camera/runThisOnRPI.txt | 3 + camera/server.py | 93 ++++++++++++++ camera/server2.py | 96 ++++++++++++++ 46 files changed, 1911 insertions(+) create mode 100644 camera/raspberry/client.py create mode 100644 camera/raspberry/focus.sh create mode 100644 camera/raspberry/lights/Makefile create mode 100644 camera/raspberry/lights/build/LEDs.o create mode 100644 camera/raspberry/lights/build/adxl345.o create mode 100644 camera/raspberry/lights/build/demo.o create mode 100644 camera/raspberry/lights/build/fan.o create mode 100644 camera/raspberry/lights/build/sick_front.o create mode 100644 camera/raspberry/lights/build/sick_side.o create mode 100644 camera/raspberry/lights/lights create mode 100644 camera/raspberry/lights/src/LEDs.cpp create mode 100644 camera/raspberry/lights/src/LEDs.hpp create mode 100644 camera/raspberry/lights/src/adxl345.cpp create mode 100644 camera/raspberry/lights/src/adxl345.hpp create mode 100644 camera/raspberry/lights/src/demo.cpp create mode 100644 camera/raspberry/lights/src/demo.hpp create mode 100644 camera/raspberry/lights/src/fan.cpp create mode 100644 camera/raspberry/lights/src/fan.hpp create mode 100644 camera/raspberry/lights/src/sick_front.cpp create mode 100644 camera/raspberry/lights/src/sick_front.hpp create mode 100644 camera/raspberry/lights/src/sick_side.cpp create mode 100644 camera/raspberry/lights/src/sick_side.hpp create mode 100644 camera/raspberry/makefile create mode 100644 camera/raspberry/sensors/Makefile create mode 100644 camera/raspberry/sensors/build/LEDs.o create mode 100644 camera/raspberry/sensors/build/adxl345.o create mode 100644 camera/raspberry/sensors/build/demo.o create mode 100644 camera/raspberry/sensors/build/fan.o create mode 100644 camera/raspberry/sensors/build/sick_front.o create mode 100644 camera/raspberry/sensors/build/sick_side.o create mode 100644 camera/raspberry/sensors/sensors create mode 100644 camera/raspberry/sensors/src/LEDs.cpp create mode 100644 camera/raspberry/sensors/src/LEDs.hpp create mode 100644 camera/raspberry/sensors/src/adxl345.cpp create mode 100644 camera/raspberry/sensors/src/adxl345.hpp create mode 100644 camera/raspberry/sensors/src/demo.cpp create mode 100644 camera/raspberry/sensors/src/demo.hpp create mode 100644 camera/raspberry/sensors/src/fan.cpp create mode 100644 camera/raspberry/sensors/src/fan.hpp create mode 100644 camera/raspberry/sensors/src/sick_front.cpp create mode 100644 camera/raspberry/sensors/src/sick_front.hpp create mode 100644 camera/raspberry/sensors/src/sick_side.cpp create mode 100644 camera/raspberry/sensors/src/sick_side.hpp create mode 100644 camera/runThisOnRPI.txt create mode 100644 camera/server.py create mode 100644 camera/server2.py diff --git a/camera/raspberry/client.py b/camera/raspberry/client.py new file mode 100644 index 0000000..1c84723 --- /dev/null +++ b/camera/raspberry/client.py @@ -0,0 +1,36 @@ +import socket +import subprocess +#from picamera2 import Picamera2 +import numpy +import time + +TCP_IP = '192.168.1.2' +TCP_PORT = 5001 + +sock = socket.socket() +sock.connect((TCP_IP, TCP_PORT)) + +#picam2 = PiCamera() + +#config = picam2.create_preview_configuration({"size": (640, 480)}) +#picam2.configure(config) +#picam2.start() +#array = picam2.capture_array("main") +while(True): + #array = picam2.capture_array("main") + + #ock.send( str(len(array)).ljust(16)) + #sock.send( array ) + #time.sleep(0.070) + command = sock.recv(1) + command = command.decode() + if command == "n": + p = subprocess.Popen("./sensors/sensors", stdout=subprocess.PIPE, shell=True) + (output, err) = p.communicate() + print(output) + print(len(output)) + sock.send(str(len(output)).encode()) + sock.send(output) + + +sock.close() diff --git a/camera/raspberry/focus.sh b/camera/raspberry/focus.sh new file mode 100644 index 0000000..879d5be --- /dev/null +++ b/camera/raspberry/focus.sh @@ -0,0 +1 @@ +python3 ~/Arducam-Pivariety-V4L2-Driver/focus/FocuserExample.py -d /dev/v4l-subdev1 --focus-step 10 diff --git a/camera/raspberry/lights/Makefile b/camera/raspberry/lights/Makefile new file mode 100644 index 0000000..4c082b0 --- /dev/null +++ b/camera/raspberry/lights/Makefile @@ -0,0 +1,40 @@ +CC = g++ + +OPT = -O3 +FLAGS = -std=c++20 -Wall -Wextra -pedantic +LIBS = -lwiringPi + +TARGET = bbx-test +SOURCEDIR = src +BUILDDIR = build + +SOURCES = $(wildcard $(SOURCEDIR)/*.cpp) +OBJECTS = $(patsubst $(SOURCEDIR)/%.cpp,$(BUILDDIR)/%.o,$(SOURCES)) + +.PHONY: all clean depend run + +all: $(TARGET) + +$(BUILDDIR): + @mkdir -p $(BUILDDIR) + +$(TARGET): $(OBJECTS) + $(CC) $(FLAGS) $(OPT) $^ -o $@ $(LIBS) + +$(OBJECTS): $(BUILDDIR)/%.o : $(SOURCEDIR)/%.cpp $(SOURCEDIR)/%.hpp | $(BUILDDIR) + $(CC) $(FLAGS) $(OPT) -c $< -o $@ $(LIBS) + +depend: .depend + +.depend: $(SOURCES) + rm -rf $(BUILDDIR)/.depend + $(CXX) $(FLAGS) -MM $^ -MF $(BUILDDIR)/.depend + +clean: + rm -rf $(BUILDDIR) + rm -f $(TARGET) + +run: $(TARGET) + sudo ./$(TARGET) + +-include $(BUILDDIR)/.depend diff --git a/camera/raspberry/lights/build/LEDs.o b/camera/raspberry/lights/build/LEDs.o new file mode 100644 index 0000000000000000000000000000000000000000..3dc0ebafa196fd055c95ba34706a12a5cdeaf905 GIT binary patch literal 2120 zcmbu9PfyfP5Wr`*3!?l{kwgLtJrILYn(d0l7^5Y-D;!orRt?0Muw^N1Bl{=26;KZ9 zH_+(8i^iiG58jlEF@6PO;zh$(FnHmx(V2E$`|NfvI!WKm{NBv;_08+MpUqu~$6_EP z2Ja#81O@2o2yDYO4d{g)Xl{Lcjq#6~3OrW9Xzq5y-mU^~FrPao7 z=@aKpvZbbyDLtv{NjOBYD6xBaNNkS8hI>XqMSqYW$_x!ted_bX3nlX;p8N6rOCKT1 zyGRB~kEdKV$F^YXwkX=e1pNHnGJ!ye++pHMR5;Q^3qRnJs7_HGsac%a>*`icSb=>U z6(}#h3kCw@TMBgfwrnWSDZ8#s``9miue;yKj^iVG;|B6@strHWhF?Y=RX@i(+^<`0 z>R23KKuzNJH%{k>vm;z&c0?jcWO|xD_5(_7SuM% z2-0iS;_V<@$8eE5nX^`$>W)e_Cn+41BEwpiX(v96I2KgRLH$i3cq zU|izv!DfH54bLzi!a4`pCbb~(eu5{PO)|#m~)}{m6vgw$hEj1dT)vM%a#fEbpv|_bfwkjAR-L0ng$IhYo7AQ@Yx^68S1&=M|j3Fz7jq$r~jVbBmO{fkDXv1 zzCqq{URY5LSx%!vHUBkV$6Tr@pAB^39StaAy`C5Nf?vW3%1?>_)*o1phqze3(9<|C zY&mpCb|gC-OZNgX`K(g-4h<*;cMJxxZb9bJi0a=0|Hv~ONd2Q+kuUle^=?Wrc%eJ2 myOGfy5YFF^EZjRppfX%1M-ndQlf!65<-g?h)14$sIR6hpIFsW5 literal 0 HcmV?d00001 diff --git a/camera/raspberry/lights/build/adxl345.o b/camera/raspberry/lights/build/adxl345.o new file mode 100644 index 0000000000000000000000000000000000000000..248fede477a44877c0db7b55d80629904241e5e5 GIT binary patch literal 8808 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 literal 0 HcmV?d00001 diff --git a/camera/raspberry/lights/build/demo.o b/camera/raspberry/lights/build/demo.o new file mode 100644 index 0000000000000000000000000000000000000000..a95b1af7b3758d232e58123251d44578be958c88 GIT binary patch literal 2872 zcmbW3&u<$=6vv;vPFmXHhB|@LpyEi82ohb{iGc_qvH8^~lGUK39N@ro9j}Q+ybj(C zavLN-;!dI(iA$>-kZ2-~NN}hCK@S`_RBEZzL#qOR0g7_)!IbxQ-`K-s_rjCB^PSJU z_hx2icE%si70)LV36Pe6@1R$c6rg#er>#I*a1zqc*}S>iF<|>31MP!fVEd6Vw70*U z*hQCCp#OsH!Mj^aVLh`~fSm?u7%U)poP_oH=gh&%N>@tL%7gJfF+wb1=Z}i7QKxYMxCDpLiZd zk)3AVqH-#2T|0XH$n+PfnXCP+zIPu!`2Eh^G-R>K!XMe|^q5L#ucfXV(^r!V4aK;g4U`v!4*n@7z0&ti=i9Ct^!F*8%^Wk6v`dRggkwC`r z!{ecMno!26?ok7t=p|+q=0Bz^XwSufa27ohDg%z{2%bZ7N_h`*eiO*$+N(it#PDJa ze>;X(WB8RA{%H*VJcfTA!+#_mu}yx9@rSZgtD7t9>oD2`F<)Gqo+=9AZIr}LD>_)sW==S9}UpH}!Kg{yhi6t3p^ zNa4@0recS62J@?5^HbC{%(Cs)h#)yF@;anc`M0+V%F(m5a1|Mxs0*$?$k zNXAM2CNk>S{&72w#_(e$>nOOKMWoa{Ln0{S-C-+dO|c zFPcBywlZGMpN6UTjRLE- z6C8|$0_cf@*a|`mQjmoH&X;#n+HR?@!Sh}c_Inz<$NW8%ye!A9y(!o&^^(?pf9Km< zWM=>djN(aM`$6LvYJ#~!KEI&PTz4w2?dfLL$QkC`rCE;jTsCKBO*4y9fRn*5Ke__n=|NKS{|Kjd%f-YL)Cn-UdJgkIY$}XiX;KHi|o%LAHEZ^ z%OOs^6kFzi^kIIE`55xJh|yaLmww$=xah#>JZ|`Q1-;)M_$`Ur&bDp%PS*#cX8Sf6 zl}-nYYO~RBJY-(ecZ|a7ow<&0SMP%n$epc?dfRR|yxe~~9V_4`MozAUjBI7#hQI2W zqVq?$#2P9FL7J~rnK|7XTIVQ_W&bWPS8w1m)~SwagpKx_YW{0J-3O{E`-ov+vi^(! z_OibC1>_Qkr60qCP^@Z;oF6`8B>&7gW%lBve=?@~Ija9%ZpbnVssHqEBl*&QdLMOd pN=fsJzG8nI89iz~)m3|s2tII8^`NTXf9jC@uUzyl6$_b~{}&N5doBO~ literal 0 HcmV?d00001 diff --git a/camera/raspberry/lights/build/sick_front.o b/camera/raspberry/lights/build/sick_front.o new file mode 100644 index 0000000000000000000000000000000000000000..e05040dcc8da2fd634ea2c849f6e3687ebc3dab7 GIT binary patch literal 4688 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 literal 0 HcmV?d00001 diff --git a/camera/raspberry/lights/lights b/camera/raspberry/lights/lights new file mode 100644 index 0000000000000000000000000000000000000000..65c5e168a094bb0237c1520fc8a4c58f799ac4e2 GIT binary patch literal 31424 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 literal 0 HcmV?d00001 diff --git a/camera/raspberry/lights/src/LEDs.cpp b/camera/raspberry/lights/src/LEDs.cpp new file mode 100644 index 0000000..de803b1 --- /dev/null +++ b/camera/raspberry/lights/src/LEDs.cpp @@ -0,0 +1,16 @@ +#include "LEDs.hpp" + +LEDs::LEDs(){ + wiringPiSetup(); + pinMode(GPIO_LED_left, PWM_OUTPUT); + pinMode(GPIO_LED_right, PWM_OUTPUT); + pwmSetClock(4000); // Clock prescaller for PWM generator +} + +void LEDs::Left(float power){ + pwmWrite(GPIO_LED_left, power * 1024); +} + +void LEDs::Right(float power){ + pwmWrite(GPIO_LED_right, power * 1024); +} diff --git a/camera/raspberry/lights/src/LEDs.hpp b/camera/raspberry/lights/src/LEDs.hpp new file mode 100644 index 0000000..cc9693e --- /dev/null +++ b/camera/raspberry/lights/src/LEDs.hpp @@ -0,0 +1,45 @@ +#pragma once + +#include + +using namespace std; + +/** + * @brief LEDs strips controlled by AL8861Y + * Dimmable by PWM on channel PWM0 and PWM1 + */ +class LEDs{ + /** + * @brief WiringPi GPIO number of pin which controls left channel + */ + int GPIO_LED_left = 23; + + /** + * @brief WiringPi GPIO number of pin which controls left channel + */ + int GPIO_LED_right = 26; + +public: + /** + * @brief Construct a new LEDs object + * Configure GPIo and sets up frequency of PWM + * Closes possible frequency reachable by Rpi is around 7 kHz + */ + LEDs(); + + /** + * @brief Set power for right LED strip + * Right channel is connected to pin 33 on header, GPIO13 (wiring pin 26) + * + * @param power Power of LED strip in range from 0.0 to 1.0 + */ + void Right(float power = 0); + + /** + * @brief Set power for left LED strip + * Left channel is connected to pin 32 on header, GPIO12 (wiring pin 23) + * + * @param power Power of LED strip in range from 0.0 to 1.0 + */ + void Left(float power = 0); +}; diff --git a/camera/raspberry/lights/src/adxl345.cpp b/camera/raspberry/lights/src/adxl345.cpp new file mode 100644 index 0000000..1d7cf6d --- /dev/null +++ b/camera/raspberry/lights/src/adxl345.cpp @@ -0,0 +1,104 @@ +#include "adxl345.hpp" + +ADXL345::ADXL345(bool channel):channel(channel){ + // SPI Mode 3 - CPOL = 1, CPHA = 1 + wiringPiSPISetupMode(channel, 500000, 3); + // Power-up + Write(registers::POWER_CTL, 0b00001000); + // Maximal data output rate + Write(registers::BW_RATE, 0b00001010); + + // Check connection by reading constant value of chip ID + if(ID() != 0xe5){ + cout << "Cannot establish connection to accelerometer" << endl; + } +} + +uint8_t ADXL345::ID(){ + return Read(registers::DEVID); +} + +array ADXL345::Trim_offsets(){ + // Zero offset + Write(registers::OFSX, 0); + Write(registers::OFSY, 0); + Write(registers::OFSZ, 0); + + // Acquire current values + usleep(100*1000); + auto axis_values = Raw_values(); + + // Calculate trims, Only acceleration of 1g should be on Z axis + int X_trim = -(round(axis_values[0]/4.0)); + int Y_trim = -(round(axis_values[1]/4.0)); + int Z_trim = -(round((axis_values[2]-255)/4.0)); + + // Write new trim values to registers + Write(registers::OFSX, X_trim); + Write(registers::OFSY, Y_trim); + Write(registers::OFSZ, Z_trim); + + // Wait for propagation + usleep(100*1000); + + return {X_trim, Y_trim, Z_trim}; +} + +void ADXL345::Trim_offsets(array axis_offsets){ + Write(registers::OFSX, axis_offsets[0]); + Write(registers::OFSY, axis_offsets[1]); + Write(registers::OFSZ, axis_offsets[2]); + + // Wait for propagation + usleep(100*1000); +} + +uint8_t ADXL345::Read(registers address){ + // 0x80 is read command + vector transfer_data = {static_cast(static_cast(address) | 0x80), dummy_packet}; + wiringPiSPIDataRW(channel, transfer_data.data(), 2); + return transfer_data[1]; +} + +vector ADXL345::Read_sequence(registers address, short length){ + vector transfer_data( length + 1, dummy_packet); + // Insert address to first position in data transfer, rest if filled with dummy bytes + transfer_data[0] = static_cast(address) | 0xc0; + wiringPiSPIDataRW(channel, transfer_data.data(), length + 1); + // Remove first byte (address) from data + transfer_data.erase(transfer_data.begin()); + return transfer_data; +} + +void ADXL345::Write(registers address, uint8_t data){ + vector transfer_data = {static_cast(address), data}; + wiringPiSPIDataRW(channel, transfer_data.data(), 2); +} + +array ADXL345::Raw_values(){ + vector register_values = Read_sequence(registers::DATAX0, 6); + array axis_values; + // Lower register represents LSB of value + axis_values[0] = register_values[0] | (register_values[1] << 8); + axis_values[1] = register_values[2] | (register_values[3] << 8); + axis_values[2] = register_values[4] | (register_values[5] << 8); + return axis_values; +} + +double ADXL345::Inclination(){ + auto axis_values = Raw_values(); + // Resulting value is angle of IC package to horizontal plane + double angle = atan(static_cast(axis_values[1])/axis_values[2]) * (180 / numbers::pi); + // Calculate absolute tilt based on quadrants from sensor values + if((axis_values[1] < 0) and (axis_values[2] >= 0)){ + angle *= -1; + } else if ((axis_values[1] < 0) and (axis_values[2] < 0)){ + angle = 180 - angle; + } else if ((axis_values[1] >= 0) and (axis_values[2] < 0)){ + angle = -angle + 180; + } else if ((axis_values[1] > 0) and (axis_values[2] >= 0)){ + angle = 360 - angle; + } + // Calculate inverse angle to corespond with clockwise rotation + return - angle + 360; +} diff --git a/camera/raspberry/lights/src/adxl345.hpp b/camera/raspberry/lights/src/adxl345.hpp new file mode 100644 index 0000000..de862cf --- /dev/null +++ b/camera/raspberry/lights/src/adxl345.hpp @@ -0,0 +1,124 @@ +#pragma once + +#include +#include +#include +#include +#include + +#include + +#include + +using namespace std; + +/** + * @brief Accelerometer AXDL345 + * Datasheet: https://www.analog.com/media/en/technical-documentation/data-sheets/ADXL345.pdf + */ +class ADXL345{ + /** + * @brief Channel on which is accelerometer connected + */ + bool channel; + + /** + * @brief Some of ADXL345 regsisters + */ + enum class registers: uint8_t{ + DEVID = 0x00, + OFSX = 0x1e, + OFSY = 0x1f, + OFSZ = 0x20, + BW_RATE = 0x2c, + POWER_CTL = 0x2d, + DATA_FORMAT = 0x31, + DATAX0 = 0x32, + DATAX1 = 0x33, + DATAY0 = 0x34, + DATAY1 = 0x35, + DATAZ0 = 0x36, + DATAZ1 = 0x37 + }; + + /** + * @brief Dummy packet, is not interpreted as any command by ADXL + Is used as padding for SPI transfer + */ + uint8_t dummy_packet = 0xaa; + +public: + + /** + * @brief Construct a new ADXL345 object + * + * @param channel SPI channel of Rpi, has only two channels, 0 or 1 + */ + ADXL345(bool channel = 0); + + /** + * @brief Reads ID from accelerometer + * Value is read only + * Suitable for testing of connection + * + * @return uint8_t Always should returns 0xe5 if communications is working + */ + uint8_t ID(); + + /** + * @brief Calculates roll angle of sensor based on value from X and Z values of acceleration + * + * @return double Roll angle of sensor (around X axis of IC), From 0 to 360°, clockwise rotation + */ + double Inclination(); + + /** + * @brief Trims offsets of accelerometer based on current values !! + * During this calibration process accelerometer should be position in base position (0 degrees) + + * @return array Values which was used as trimming values for coresponding axis [X,Y,Z] + */ + array Trim_offsets(); + + /** + * @brief Trims offsets of accelerometer with defined values + * + * @param axis_offsets Trim values for all accelerometer axis [X,Y,Z] + * Value is multiplied by 4 and added to resulting acceleration of respective axis + */ + void Trim_offsets(array axis_offsets); + + +private: + /** + * @brief Reads raw values of acceleration for all axis + * + * @return array Acceleration values from sensor for each axis [X,Y,Z] + */ + array Raw_values(); + + /** + * @brief Read one byte of data from ADXL memory + * + * @param address Address in ADXL memory from which are data read + * @return uint8_t Data from memory + */ + uint8_t Read(registers address); + + /** + * @brief Reads sequence of data from ADXL memory + * + * @param address Address in ADXL memory from which reading starts + * @param length Amount of bytes to read + * @return vector Readout data + */ + vector Read_sequence(registers address, short length); + + /** + * @brief Write one byte of data into ADXL memory + * + * @param address Address to which will be writing performed + * @param data Data to write + */ + void Write(registers address, uint8_t data); +}; diff --git a/camera/raspberry/lights/src/demo.cpp b/camera/raspberry/lights/src/demo.cpp new file mode 100644 index 0000000..9fca721 --- /dev/null +++ b/camera/raspberry/lights/src/demo.cpp @@ -0,0 +1,21 @@ +#include "demo.hpp" + +using namespace std; + +int main(){ + + // ----- Fan ----- + auto fan = Fan(); + fan.On(); + + // ----- LEDS ----- + auto led = LEDs(); + for(int i = 0; i < 100000; i++){ + led.Left(1.0); + led.Right(1.0); + usleep(10000); + led.Left(0.0); + led.Right(0.0); + } + fan.Off(); +} diff --git a/camera/raspberry/lights/src/demo.hpp b/camera/raspberry/lights/src/demo.hpp new file mode 100644 index 0000000..5b8c9ba --- /dev/null +++ b/camera/raspberry/lights/src/demo.hpp @@ -0,0 +1,12 @@ +#pragma once + +#include +#include + +#include + +#include "adxl345.hpp" +#include "fan.hpp" +#include "LEDs.hpp" +#include "sick_side.hpp" +#include "sick_front.hpp" diff --git a/camera/raspberry/lights/src/fan.cpp b/camera/raspberry/lights/src/fan.cpp new file mode 100644 index 0000000..9a11b78 --- /dev/null +++ b/camera/raspberry/lights/src/fan.cpp @@ -0,0 +1,14 @@ +#include "fan.hpp" + +Fan::Fan(){ + wiringPiSetup(); + pinMode(GPIO_fan, OUTPUT); +} + +void Fan::On(){ + digitalWrite(GPIO_fan, 1); +} + +void Fan::Off(){ + digitalWrite(GPIO_fan, 0); +} diff --git a/camera/raspberry/lights/src/fan.hpp b/camera/raspberry/lights/src/fan.hpp new file mode 100644 index 0000000..0e64d35 --- /dev/null +++ b/camera/raspberry/lights/src/fan.hpp @@ -0,0 +1,34 @@ +#pragma once + +#include +#include + +using namespace std; + +/** + * @brief PWM controlled fan without RPM detection + */ +class Fan{ + /** + * @brief WiringPi GPIO number of pin which controls fan + */ + int GPIO_fan = 25; + +public: + /** + * @brief Construct a new Fan object + * Create soft-PWM thread for fan control signal + */ + Fan(); + + /** + * @brief Enable cooling fan + */ + void On(); + + /** + * @brief Disable cooling fan + */ + void Off(); + +}; diff --git a/camera/raspberry/lights/src/sick_front.cpp b/camera/raspberry/lights/src/sick_front.cpp new file mode 100644 index 0000000..ae0e0f0 --- /dev/null +++ b/camera/raspberry/lights/src/sick_front.cpp @@ -0,0 +1,61 @@ +#include "sick_front.hpp" + +Sick_front::Sick_front(bool channel):channel(channel){ + wiringPiSPISetupMode(channel, 500000, 3); + wiringPiSetup(); + pinMode(GPIO_conversion_start, OUTPUT); + pinMode(GPIO_laser_enable, OUTPUT); +} + +optional Sick_front::Distance_avg(unsigned int measurement_count){ + unsigned int sum = 0; + unsigned int successful_measurements = 0; + for(unsigned int i = 0; i < measurement_count; i++){ + auto distance = Distance(); + if(distance){ + sum += *distance; + successful_measurements++; + } + } + if(sum == 0){ + return {}; + } + return sum/successful_measurements; +} + +optional Sick_front::Distance(){ + auto raw = Conversion_raw(); + float differential_raw = static_cast(static_cast(raw)); + // Calculation of true voltage from reference voltage and ADC value + double voltage = differential_raw / (1 << 16) * reference_voltage; + //cout << "Voltage: " << hex << raw << dec << " : " < voltage_far)){ + return {}; + } + + double range_percentage = (voltage-voltage_min)/(voltage_max-voltage_min); + double distance = round((range_max-range_min)*range_percentage+range_min); + return distance; +} + +uint16_t Sick_front::Conversion_raw(){ + // Start conversion + digitalWrite(GPIO_conversion_start, 1); + array received_data = {0x00, 0x00}; + wiringPiSPIDataRW(channel, received_data.data(), 2); + // Start conversion + digitalWrite(GPIO_conversion_start, 0); + return ((received_data[0]<<8) | received_data[1]); +} + +void Sick_front::Laser(bool state){ + if(state){ + // ON + pinMode(GPIO_laser_enable, INPUT); + } else { + // OFF + pinMode(GPIO_laser_enable, OUTPUT); + digitalWrite(GPIO_laser_enable, 0); + } +} diff --git a/camera/raspberry/lights/src/sick_front.hpp b/camera/raspberry/lights/src/sick_front.hpp new file mode 100644 index 0000000..18b6f95 --- /dev/null +++ b/camera/raspberry/lights/src/sick_front.hpp @@ -0,0 +1,134 @@ +#pragma once + +#include +#include +#include +#include +#include + +#include + +#include +#include + +using namespace std; + +/** +Type: DT50-N2113 +**/ +class Sick_front{ + /** + * @brief Channel on which is ADC for front distance sensor connected + */ + bool channel; + + /** + * @brief WiringPi GPIO number of pin which start conversion by change 0->1 + */ + const int GPIO_conversion_start = 5; + + /** + * @brief WiringPi GPIO number of pin which turn ON/OFF laser of sensor + */ + const int GPIO_laser_enable = 4; + + /** + * @brief Minimal configured distance of sensor + */ + const int range_min = 200; + + /** + * @brief Maximal configured distance of sensor + */ + const int range_max = 10000; + + /** + * @brief Value of sense resistor in ohms used for current loop + */ + const int sense_resistor = 150; + + /** + * @brief Current coresponding to minimal distance, configured in "range_min" + */ + const float current_loop_min = 0.004; + + /** + * @brief Current coresponding to maximal distance, configured in "range_max" + */ + const float current_loop_max = 0.020; + + /** + * @brief Current coresponding to state when minimal distance is exceeded + */ + const float current_loop_close = 0.0035; + + /** + * @brief Current coresponding to state when maximal distance is exceeded + */ + const float current_loop_far = 0.0205; + + /** + * @brief Voltage coresponding to maximal distance + */ + const float voltage_max = current_loop_max*sense_resistor; + + /** + * @brief Voltage coresponding to minimal distance + */ + const float voltage_min = current_loop_min*sense_resistor; + + /** + * @brief Voltage coresponding to state when maximal distance is exceeded + */ + const float voltage_close = current_loop_close*sense_resistor; + + /** + * @brief Voltage coresponding to state when minimal distance is exceeded + */ + const float voltage_far = current_loop_far*sense_resistor; + + /** + * @brief Reference voltage of ADC + */ + const float reference_voltage = 3.308f; + +public: + /** + * @brief Construct a new Sick_front object + * Configure GPIO and SPI interface + * + * @param channel Channel on which is sensor connected + */ + Sick_front(bool channel = 1); + + /** + * @brief Calculate distance measurted by distance sensor + * + * @return optional True and value in mm if in range, False otherwise + */ + optional Distance(); + + /** + * @brief Average multiple measurements of distance sensor output + * + * @param measurement_count Amount of measurents to average + * @return optional Same as Distance() + */ + optional Distance_avg(unsigned int measurement_count = 8); + + /** + * @brief Turn ON or OFF laser of sensor + * + * @param state New state of laser + */ + void Laser(bool state); + +private: + /** + * @brief Read raw ADC data from ADC + * + * @return uint16_t raw ADc data in 2's complement format + */ + uint16_t Conversion_raw(); + +}; diff --git a/camera/raspberry/lights/src/sick_side.cpp b/camera/raspberry/lights/src/sick_side.cpp new file mode 100644 index 0000000..c689c45 --- /dev/null +++ b/camera/raspberry/lights/src/sick_side.cpp @@ -0,0 +1,103 @@ +#include "sick_side.hpp" + +Sick_side::Sick_side(){ + serial_descriptor = serialOpen("/dev/ttyS0", 9600); + if(serial_descriptor == -1){ + cout << "Cannot open serial line for communication with side distance sensor" << endl; + } +} + +uint8_t Sick_side::ID(){ + Send_data({static_cast(commands::Read), 0x01, 0x00}); + //while(Data_available() < 12); + // Readout data which are in buffer from transmittion + //Receive(); + // Read real received data from sensor + if(auto responce = Receive()){ + return (*responce)[2]; + } else { + return 0x00; + } +} + +void Sick_side::Laser(bool state){ + if(state){ + // ON + Send_data({static_cast(commands::Command), 0xa0, 0x03}); + } else { + // OFF + Send_data({static_cast(commands::Command), 0xa0, 0x02}); + } + + //Read responce to clear buffer + Receive(); +} + +optional Sick_side::Distance(){ + auto distance_data = Distance_data(); + if(distance_data == 0x7fff){ + // Out of measuring range + return {}; + } else { + // Convert to 2'complement and then to mm + return static_cast(distance_data)/100.0; + } +} + +uint16_t Sick_side::Distance_data(){ + Send_data({static_cast(commands::Command), 0xb0, 0x01}); + if(auto responce = Receive()){ + return (((*responce)[1]<<8) | (*responce)[2]); + } else { + return 0x7fff; + } +} + +void Sick_side::Send_data(array data){ + array packet = {static_cast(signs::STX), data[0], data[1], data[2], static_cast(signs::ETX), 0x00}; + packet[5] = Calculate_BCC(packet); + Transmit(packet); +} + +void Sick_side::Transmit(array data){ + for(int i = 0; i < 6; i++){ + serialPutchar(serial_descriptor, data[i]); + } +} + +uint8_t Sick_side::Calculate_BCC(array data){ + uint8_t BCC = 0; + // BCC is calculated only from bytes on positions 1,2,3 + for(int byte_index = 1; byte_index < 4; byte_index++){ + BCC ^= data[byte_index]; + } + return BCC; +} + +optional> Sick_side::Receive(){ + while(Data_available() < 12); + // Readout data which are in buffer from transmittion + for(int i = 0; i < 6; i++){ + serialGetchar(serial_descriptor); + } + // Receive true data + array received_data; + for(int i = 0; i < 6; i++){ + received_data[i] = serialGetchar(serial_descriptor); + } + // Check for communication errors + if(static_cast(received_data[1]) == signs::NAK){ + cout << error_codes[received_data[2]] << endl; + return {}; + } + if(received_data[5] != Calculate_BCC(received_data)){ + cout << "Received BCC is invalid" << endl; + return {}; + } + + return array({received_data[1], received_data[2], received_data[3]}); +} + +unsigned int Sick_side::Data_available(){ + return serialDataAvail(serial_descriptor); +} diff --git a/camera/raspberry/lights/src/sick_side.hpp b/camera/raspberry/lights/src/sick_side.hpp new file mode 100644 index 0000000..f77d016 --- /dev/null +++ b/camera/raspberry/lights/src/sick_side.hpp @@ -0,0 +1,119 @@ +#pragma once + +#include +#include +#include +#include +#include + +#include + +using namespace std; + +/** +Type: OD1-B100C50A15 +**/ +class Sick_side{ + + int serial_descriptor = 0; + + enum class signs: uint8_t{ + STX = 0x02, + ETX = 0x03, + ACK = 0x06, + NAK = 0x15, + }; + + map error_codes{ + {0x02, "Address is invalid"}, + {0x04, "BCC values is invalid"}, + {0x05, "Invalid command"}, + {0x06, "Invalid setting value (out of spec)"}, + {0x07, "Invalid setting value (out of range)"} + }; + + enum class commands: uint8_t{ + Command = 0x43, // Also used for reading out measured values + Write = 0x57, + Read = 0x52, + }; + +public: + /** + * @brief Construct a new Sick_side object + * Opens serial line and save file descriptor + */ + Sick_side(); + + /** + * @brief Read sensor ID from memory of sensor + * Used for connection check + * + * @return uint8_t Value 0x64, 0x00 if communication fails + */ + uint8_t ID(); + + /** + * @brief Turn ON or OFF laser of sensor + * + * @param state New state of laser + */ + void Laser(bool state); + + /** + * @brief Read and calculate distance from distance sensor + * Distance is relative to sensors zero point + * + * @return optional And and relative distance from zero point, false otherwise (Out of Range) + */ + optional Distance(); + +private: + + /** + * @brief Reads distance data from sensor register + * + * @return uint16_t Distance in 2's complement, range -5000 to 5000, coresponds to -50 mm to +50 mm + */ + uint16_t Distance_data(); + + /** + * @brief Transmit given data over serial to RS485 transmitter + * + * @param data Data to send via serial line, header and footer are added + */ + void Send_data(array data); + + /** + * @brief Calculates BCC for given packet of data + * BCC is XOR of bytes on index 1,2,3, remaning bytes are ignored + * + * @param data Packet used for calculation + * @return uint8_t Values of BCC + */ + uint8_t Calculate_BCC(array data); + + /** + * @brief Transmits data over UART to RS485 transmitter + * Data are also copied to input buffer due to half-duplex connection + * + * @param data Data to transmit + */ + void Transmit(array data); + + /** + * @brief Data received from sensor + * Only usefull data are returned, without STX, ACK/NACK, BCC + * + * @return optional> True and value if communication is valid, False otherwise + */ + optional> Receive(); + + /** + * @brief Reads amopunt of data in input buffer + * + * @return unsigned int Number of bytes in input buffer + */ + unsigned int Data_available(); + +}; diff --git a/camera/raspberry/makefile b/camera/raspberry/makefile new file mode 100644 index 0000000..661a29d --- /dev/null +++ b/camera/raspberry/makefile @@ -0,0 +1,6 @@ +all: + make -C lights/ + mv lights/bbx-test lights/lights + make -C sensors/ + mv sensors/bbx-test sensors/sensors + diff --git a/camera/raspberry/sensors/Makefile b/camera/raspberry/sensors/Makefile new file mode 100644 index 0000000..4c082b0 --- /dev/null +++ b/camera/raspberry/sensors/Makefile @@ -0,0 +1,40 @@ +CC = g++ + +OPT = -O3 +FLAGS = -std=c++20 -Wall -Wextra -pedantic +LIBS = -lwiringPi + +TARGET = bbx-test +SOURCEDIR = src +BUILDDIR = build + +SOURCES = $(wildcard $(SOURCEDIR)/*.cpp) +OBJECTS = $(patsubst $(SOURCEDIR)/%.cpp,$(BUILDDIR)/%.o,$(SOURCES)) + +.PHONY: all clean depend run + +all: $(TARGET) + +$(BUILDDIR): + @mkdir -p $(BUILDDIR) + +$(TARGET): $(OBJECTS) + $(CC) $(FLAGS) $(OPT) $^ -o $@ $(LIBS) + +$(OBJECTS): $(BUILDDIR)/%.o : $(SOURCEDIR)/%.cpp $(SOURCEDIR)/%.hpp | $(BUILDDIR) + $(CC) $(FLAGS) $(OPT) -c $< -o $@ $(LIBS) + +depend: .depend + +.depend: $(SOURCES) + rm -rf $(BUILDDIR)/.depend + $(CXX) $(FLAGS) -MM $^ -MF $(BUILDDIR)/.depend + +clean: + rm -rf $(BUILDDIR) + rm -f $(TARGET) + +run: $(TARGET) + sudo ./$(TARGET) + +-include $(BUILDDIR)/.depend diff --git a/camera/raspberry/sensors/build/LEDs.o b/camera/raspberry/sensors/build/LEDs.o new file mode 100644 index 0000000000000000000000000000000000000000..3dc0ebafa196fd055c95ba34706a12a5cdeaf905 GIT binary patch literal 2120 zcmbu9PfyfP5Wr`*3!?l{kwgLtJrILYn(d0l7^5Y-D;!orRt?0Muw^N1Bl{=26;KZ9 zH_+(8i^iiG58jlEF@6PO;zh$(FnHmx(V2E$`|NfvI!WKm{NBv;_08+MpUqu~$6_EP z2Ja#81O@2o2yDYO4d{g)Xl{Lcjq#6~3OrW9Xzq5y-mU^~FrPao7 z=@aKpvZbbyDLtv{NjOBYD6xBaNNkS8hI>XqMSqYW$_x!ted_bX3nlX;p8N6rOCKT1 zyGRB~kEdKV$F^YXwkX=e1pNHnGJ!ye++pHMR5;Q^3qRnJs7_HGsac%a>*`icSb=>U z6(}#h3kCw@TMBgfwrnWSDZ8#s``9miue;yKj^iVG;|B6@strHWhF?Y=RX@i(+^<`0 z>R23KKuzNJH%{k>vm;z&c0?jcWO|xD_5(_7SuM% z2-0iS;_V<@$8eE5nX^`$>W)e_Cn+41BEwpiX(v96I2KgRLH$i3cq zU|izv!DfH54bLzi!a4`pCbb~(eu5{PO)|#m~)}{m6vgw$hEj1dT)vM%a#fEbpv|_bfwkjAR-L0ng$IhYo7AQ@Yx^68S1&=M|j3Fz7jq$r~jVbBmO{fkDXv1 zzCqq{URY5LSx%!vHUBkV$6Tr@pAB^39StaAy`C5Nf?vW3%1?>_)*o1phqze3(9<|C zY&mpCb|gC-OZNgX`K(g-4h<*;cMJxxZb9bJi0a=0|Hv~ONd2Q+kuUle^=?Wrc%eJ2 myOGfy5YFF^EZjRppfX%1M-ndQlf!65<-g?h)14$sIR6hpIFsW5 literal 0 HcmV?d00001 diff --git a/camera/raspberry/sensors/build/adxl345.o b/camera/raspberry/sensors/build/adxl345.o new file mode 100644 index 0000000000000000000000000000000000000000..248fede477a44877c0db7b55d80629904241e5e5 GIT binary patch literal 8808 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 literal 0 HcmV?d00001 diff --git a/camera/raspberry/sensors/build/demo.o b/camera/raspberry/sensors/build/demo.o new file mode 100644 index 0000000000000000000000000000000000000000..326b58e73a4c4080bdd18fe7dc5e7d8aac296385 GIT binary patch literal 6976 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 S)%>?Mp$Z{4t?Kc&)BoQSwa$Y8 literal 0 HcmV?d00001 diff --git a/camera/raspberry/sensors/build/fan.o b/camera/raspberry/sensors/build/fan.o new file mode 100644 index 0000000000000000000000000000000000000000..0ce7f2d872bd29caefef7bd23ec811a96b035654 GIT binary patch literal 1824 zcmbu9&ubG=5XUFk)T#;f2OfeEyM-bx*d?2SNKsgcZHm;UM5XAZ*(95GvDt)V)o2g) z5AY&-@SLE- z6C8|$0_cf@*a|`mQjmoH&X;#n+HR?@!Sh}c_Inz<$NW8%ye!A9y(!o&^^(?pf9Km< zWM=>djN(aM`$6LvYJ#~!KEI&PTz4w2?dfLL$QkC`rCE;jTsCKBO*4y9fRn*5Ke__n=|NKS{|Kjd%f-YL)Cn-UdJgkIY$}XiX;KHi|o%LAHEZ^ z%OOs^6kFzi^kIIE`55xJh|yaLmww$=xah#>JZ|`Q1-;)M_$`Ur&bDp%PS*#cX8Sf6 zl}-nYYO~RBJY-(ecZ|a7ow<&0SMP%n$epc?dfRR|yxe~~9V_4`MozAUjBI7#hQI2W zqVq?$#2P9FL7J~rnK|7XTIVQ_W&bWPS8w1m)~SwagpKx_YW{0J-3O{E`-ov+vi^(! z_OibC1>_Qkr60qCP^@Z;oF6`8B>&7gW%lBve=?@~Ija9%ZpbnVssHqEBl*&QdLMOd pN=fsJzG8nI89iz~)m3|s2tII8^`NTXf9jC@uUzyl6$_b~{}&N5doBO~ literal 0 HcmV?d00001 diff --git a/camera/raspberry/sensors/build/sick_front.o b/camera/raspberry/sensors/build/sick_front.o new file mode 100644 index 0000000000000000000000000000000000000000..e05040dcc8da2fd634ea2c849f6e3687ebc3dab7 GIT binary patch literal 4688 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 literal 0 HcmV?d00001 diff --git a/camera/raspberry/sensors/sensors b/camera/raspberry/sensors/sensors new file mode 100644 index 0000000000000000000000000000000000000000..8eb780d06944ba7a1d58f58b820bb234fecb3ac0 GIT binary patch literal 31632 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 jjPhTtesUh`sOllhl^ET7kad?Bh39>GY=R+!A literal 0 HcmV?d00001 diff --git a/camera/raspberry/sensors/src/LEDs.cpp b/camera/raspberry/sensors/src/LEDs.cpp new file mode 100644 index 0000000..de803b1 --- /dev/null +++ b/camera/raspberry/sensors/src/LEDs.cpp @@ -0,0 +1,16 @@ +#include "LEDs.hpp" + +LEDs::LEDs(){ + wiringPiSetup(); + pinMode(GPIO_LED_left, PWM_OUTPUT); + pinMode(GPIO_LED_right, PWM_OUTPUT); + pwmSetClock(4000); // Clock prescaller for PWM generator +} + +void LEDs::Left(float power){ + pwmWrite(GPIO_LED_left, power * 1024); +} + +void LEDs::Right(float power){ + pwmWrite(GPIO_LED_right, power * 1024); +} diff --git a/camera/raspberry/sensors/src/LEDs.hpp b/camera/raspberry/sensors/src/LEDs.hpp new file mode 100644 index 0000000..cc9693e --- /dev/null +++ b/camera/raspberry/sensors/src/LEDs.hpp @@ -0,0 +1,45 @@ +#pragma once + +#include + +using namespace std; + +/** + * @brief LEDs strips controlled by AL8861Y + * Dimmable by PWM on channel PWM0 and PWM1 + */ +class LEDs{ + /** + * @brief WiringPi GPIO number of pin which controls left channel + */ + int GPIO_LED_left = 23; + + /** + * @brief WiringPi GPIO number of pin which controls left channel + */ + int GPIO_LED_right = 26; + +public: + /** + * @brief Construct a new LEDs object + * Configure GPIo and sets up frequency of PWM + * Closes possible frequency reachable by Rpi is around 7 kHz + */ + LEDs(); + + /** + * @brief Set power for right LED strip + * Right channel is connected to pin 33 on header, GPIO13 (wiring pin 26) + * + * @param power Power of LED strip in range from 0.0 to 1.0 + */ + void Right(float power = 0); + + /** + * @brief Set power for left LED strip + * Left channel is connected to pin 32 on header, GPIO12 (wiring pin 23) + * + * @param power Power of LED strip in range from 0.0 to 1.0 + */ + void Left(float power = 0); +}; diff --git a/camera/raspberry/sensors/src/adxl345.cpp b/camera/raspberry/sensors/src/adxl345.cpp new file mode 100644 index 0000000..1d7cf6d --- /dev/null +++ b/camera/raspberry/sensors/src/adxl345.cpp @@ -0,0 +1,104 @@ +#include "adxl345.hpp" + +ADXL345::ADXL345(bool channel):channel(channel){ + // SPI Mode 3 - CPOL = 1, CPHA = 1 + wiringPiSPISetupMode(channel, 500000, 3); + // Power-up + Write(registers::POWER_CTL, 0b00001000); + // Maximal data output rate + Write(registers::BW_RATE, 0b00001010); + + // Check connection by reading constant value of chip ID + if(ID() != 0xe5){ + cout << "Cannot establish connection to accelerometer" << endl; + } +} + +uint8_t ADXL345::ID(){ + return Read(registers::DEVID); +} + +array ADXL345::Trim_offsets(){ + // Zero offset + Write(registers::OFSX, 0); + Write(registers::OFSY, 0); + Write(registers::OFSZ, 0); + + // Acquire current values + usleep(100*1000); + auto axis_values = Raw_values(); + + // Calculate trims, Only acceleration of 1g should be on Z axis + int X_trim = -(round(axis_values[0]/4.0)); + int Y_trim = -(round(axis_values[1]/4.0)); + int Z_trim = -(round((axis_values[2]-255)/4.0)); + + // Write new trim values to registers + Write(registers::OFSX, X_trim); + Write(registers::OFSY, Y_trim); + Write(registers::OFSZ, Z_trim); + + // Wait for propagation + usleep(100*1000); + + return {X_trim, Y_trim, Z_trim}; +} + +void ADXL345::Trim_offsets(array axis_offsets){ + Write(registers::OFSX, axis_offsets[0]); + Write(registers::OFSY, axis_offsets[1]); + Write(registers::OFSZ, axis_offsets[2]); + + // Wait for propagation + usleep(100*1000); +} + +uint8_t ADXL345::Read(registers address){ + // 0x80 is read command + vector transfer_data = {static_cast(static_cast(address) | 0x80), dummy_packet}; + wiringPiSPIDataRW(channel, transfer_data.data(), 2); + return transfer_data[1]; +} + +vector ADXL345::Read_sequence(registers address, short length){ + vector transfer_data( length + 1, dummy_packet); + // Insert address to first position in data transfer, rest if filled with dummy bytes + transfer_data[0] = static_cast(address) | 0xc0; + wiringPiSPIDataRW(channel, transfer_data.data(), length + 1); + // Remove first byte (address) from data + transfer_data.erase(transfer_data.begin()); + return transfer_data; +} + +void ADXL345::Write(registers address, uint8_t data){ + vector transfer_data = {static_cast(address), data}; + wiringPiSPIDataRW(channel, transfer_data.data(), 2); +} + +array ADXL345::Raw_values(){ + vector register_values = Read_sequence(registers::DATAX0, 6); + array axis_values; + // Lower register represents LSB of value + axis_values[0] = register_values[0] | (register_values[1] << 8); + axis_values[1] = register_values[2] | (register_values[3] << 8); + axis_values[2] = register_values[4] | (register_values[5] << 8); + return axis_values; +} + +double ADXL345::Inclination(){ + auto axis_values = Raw_values(); + // Resulting value is angle of IC package to horizontal plane + double angle = atan(static_cast(axis_values[1])/axis_values[2]) * (180 / numbers::pi); + // Calculate absolute tilt based on quadrants from sensor values + if((axis_values[1] < 0) and (axis_values[2] >= 0)){ + angle *= -1; + } else if ((axis_values[1] < 0) and (axis_values[2] < 0)){ + angle = 180 - angle; + } else if ((axis_values[1] >= 0) and (axis_values[2] < 0)){ + angle = -angle + 180; + } else if ((axis_values[1] > 0) and (axis_values[2] >= 0)){ + angle = 360 - angle; + } + // Calculate inverse angle to corespond with clockwise rotation + return - angle + 360; +} diff --git a/camera/raspberry/sensors/src/adxl345.hpp b/camera/raspberry/sensors/src/adxl345.hpp new file mode 100644 index 0000000..de862cf --- /dev/null +++ b/camera/raspberry/sensors/src/adxl345.hpp @@ -0,0 +1,124 @@ +#pragma once + +#include +#include +#include +#include +#include + +#include + +#include + +using namespace std; + +/** + * @brief Accelerometer AXDL345 + * Datasheet: https://www.analog.com/media/en/technical-documentation/data-sheets/ADXL345.pdf + */ +class ADXL345{ + /** + * @brief Channel on which is accelerometer connected + */ + bool channel; + + /** + * @brief Some of ADXL345 regsisters + */ + enum class registers: uint8_t{ + DEVID = 0x00, + OFSX = 0x1e, + OFSY = 0x1f, + OFSZ = 0x20, + BW_RATE = 0x2c, + POWER_CTL = 0x2d, + DATA_FORMAT = 0x31, + DATAX0 = 0x32, + DATAX1 = 0x33, + DATAY0 = 0x34, + DATAY1 = 0x35, + DATAZ0 = 0x36, + DATAZ1 = 0x37 + }; + + /** + * @brief Dummy packet, is not interpreted as any command by ADXL + Is used as padding for SPI transfer + */ + uint8_t dummy_packet = 0xaa; + +public: + + /** + * @brief Construct a new ADXL345 object + * + * @param channel SPI channel of Rpi, has only two channels, 0 or 1 + */ + ADXL345(bool channel = 0); + + /** + * @brief Reads ID from accelerometer + * Value is read only + * Suitable for testing of connection + * + * @return uint8_t Always should returns 0xe5 if communications is working + */ + uint8_t ID(); + + /** + * @brief Calculates roll angle of sensor based on value from X and Z values of acceleration + * + * @return double Roll angle of sensor (around X axis of IC), From 0 to 360°, clockwise rotation + */ + double Inclination(); + + /** + * @brief Trims offsets of accelerometer based on current values !! + * During this calibration process accelerometer should be position in base position (0 degrees) + + * @return array Values which was used as trimming values for coresponding axis [X,Y,Z] + */ + array Trim_offsets(); + + /** + * @brief Trims offsets of accelerometer with defined values + * + * @param axis_offsets Trim values for all accelerometer axis [X,Y,Z] + * Value is multiplied by 4 and added to resulting acceleration of respective axis + */ + void Trim_offsets(array axis_offsets); + + +private: + /** + * @brief Reads raw values of acceleration for all axis + * + * @return array Acceleration values from sensor for each axis [X,Y,Z] + */ + array Raw_values(); + + /** + * @brief Read one byte of data from ADXL memory + * + * @param address Address in ADXL memory from which are data read + * @return uint8_t Data from memory + */ + uint8_t Read(registers address); + + /** + * @brief Reads sequence of data from ADXL memory + * + * @param address Address in ADXL memory from which reading starts + * @param length Amount of bytes to read + * @return vector Readout data + */ + vector Read_sequence(registers address, short length); + + /** + * @brief Write one byte of data into ADXL memory + * + * @param address Address to which will be writing performed + * @param data Data to write + */ + void Write(registers address, uint8_t data); +}; diff --git a/camera/raspberry/sensors/src/demo.cpp b/camera/raspberry/sensors/src/demo.cpp new file mode 100644 index 0000000..97a5b82 --- /dev/null +++ b/camera/raspberry/sensors/src/demo.cpp @@ -0,0 +1,43 @@ +#include "demo.hpp" + +using namespace std; + +int main(){ + + // ----- Accelerometer ----- + auto accelerometer = ADXL345(); + // "HOT" trimming with current values of tilt + // This emthod is not expected to be used in production + //accelerometer.Trim_offsets(); + // Trimming with predefined values, based on previous measuments + // Data for command below can be taken from command above + accelerometer.Trim_offsets({0,0,0}); + + // ----- Side laser ----- + auto side = Sick_side(); + // Enable laser of for measuring + side.Laser(false); + + // ----- Front laser ----- + auto front = Sick_front(); + front.Laser(true); + + // ----- Test loop ----- + // Read inclination from accelerometer and distance from both sensors in loop and print it + while(true){ + + if(auto distance = front.Distance_avg()) { + setprecision(1); + cout << "{ \n \"depthPos\" :\n {\"x\" : " << accelerometer.Inclination() << ",\n \"y\" : " << *distance << "\n},\n \"rectangle\" : \n {\n \"h\" : 50.0, \n \"w\" : 60.0 \n}} " < +#include + +#include + +#include "adxl345.hpp" +#include "fan.hpp" +#include "LEDs.hpp" +#include "sick_side.hpp" +#include "sick_front.hpp" diff --git a/camera/raspberry/sensors/src/fan.cpp b/camera/raspberry/sensors/src/fan.cpp new file mode 100644 index 0000000..9a11b78 --- /dev/null +++ b/camera/raspberry/sensors/src/fan.cpp @@ -0,0 +1,14 @@ +#include "fan.hpp" + +Fan::Fan(){ + wiringPiSetup(); + pinMode(GPIO_fan, OUTPUT); +} + +void Fan::On(){ + digitalWrite(GPIO_fan, 1); +} + +void Fan::Off(){ + digitalWrite(GPIO_fan, 0); +} diff --git a/camera/raspberry/sensors/src/fan.hpp b/camera/raspberry/sensors/src/fan.hpp new file mode 100644 index 0000000..0e64d35 --- /dev/null +++ b/camera/raspberry/sensors/src/fan.hpp @@ -0,0 +1,34 @@ +#pragma once + +#include +#include + +using namespace std; + +/** + * @brief PWM controlled fan without RPM detection + */ +class Fan{ + /** + * @brief WiringPi GPIO number of pin which controls fan + */ + int GPIO_fan = 25; + +public: + /** + * @brief Construct a new Fan object + * Create soft-PWM thread for fan control signal + */ + Fan(); + + /** + * @brief Enable cooling fan + */ + void On(); + + /** + * @brief Disable cooling fan + */ + void Off(); + +}; diff --git a/camera/raspberry/sensors/src/sick_front.cpp b/camera/raspberry/sensors/src/sick_front.cpp new file mode 100644 index 0000000..ae0e0f0 --- /dev/null +++ b/camera/raspberry/sensors/src/sick_front.cpp @@ -0,0 +1,61 @@ +#include "sick_front.hpp" + +Sick_front::Sick_front(bool channel):channel(channel){ + wiringPiSPISetupMode(channel, 500000, 3); + wiringPiSetup(); + pinMode(GPIO_conversion_start, OUTPUT); + pinMode(GPIO_laser_enable, OUTPUT); +} + +optional Sick_front::Distance_avg(unsigned int measurement_count){ + unsigned int sum = 0; + unsigned int successful_measurements = 0; + for(unsigned int i = 0; i < measurement_count; i++){ + auto distance = Distance(); + if(distance){ + sum += *distance; + successful_measurements++; + } + } + if(sum == 0){ + return {}; + } + return sum/successful_measurements; +} + +optional Sick_front::Distance(){ + auto raw = Conversion_raw(); + float differential_raw = static_cast(static_cast(raw)); + // Calculation of true voltage from reference voltage and ADC value + double voltage = differential_raw / (1 << 16) * reference_voltage; + //cout << "Voltage: " << hex << raw << dec << " : " < voltage_far)){ + return {}; + } + + double range_percentage = (voltage-voltage_min)/(voltage_max-voltage_min); + double distance = round((range_max-range_min)*range_percentage+range_min); + return distance; +} + +uint16_t Sick_front::Conversion_raw(){ + // Start conversion + digitalWrite(GPIO_conversion_start, 1); + array received_data = {0x00, 0x00}; + wiringPiSPIDataRW(channel, received_data.data(), 2); + // Start conversion + digitalWrite(GPIO_conversion_start, 0); + return ((received_data[0]<<8) | received_data[1]); +} + +void Sick_front::Laser(bool state){ + if(state){ + // ON + pinMode(GPIO_laser_enable, INPUT); + } else { + // OFF + pinMode(GPIO_laser_enable, OUTPUT); + digitalWrite(GPIO_laser_enable, 0); + } +} diff --git a/camera/raspberry/sensors/src/sick_front.hpp b/camera/raspberry/sensors/src/sick_front.hpp new file mode 100644 index 0000000..18b6f95 --- /dev/null +++ b/camera/raspberry/sensors/src/sick_front.hpp @@ -0,0 +1,134 @@ +#pragma once + +#include +#include +#include +#include +#include + +#include + +#include +#include + +using namespace std; + +/** +Type: DT50-N2113 +**/ +class Sick_front{ + /** + * @brief Channel on which is ADC for front distance sensor connected + */ + bool channel; + + /** + * @brief WiringPi GPIO number of pin which start conversion by change 0->1 + */ + const int GPIO_conversion_start = 5; + + /** + * @brief WiringPi GPIO number of pin which turn ON/OFF laser of sensor + */ + const int GPIO_laser_enable = 4; + + /** + * @brief Minimal configured distance of sensor + */ + const int range_min = 200; + + /** + * @brief Maximal configured distance of sensor + */ + const int range_max = 10000; + + /** + * @brief Value of sense resistor in ohms used for current loop + */ + const int sense_resistor = 150; + + /** + * @brief Current coresponding to minimal distance, configured in "range_min" + */ + const float current_loop_min = 0.004; + + /** + * @brief Current coresponding to maximal distance, configured in "range_max" + */ + const float current_loop_max = 0.020; + + /** + * @brief Current coresponding to state when minimal distance is exceeded + */ + const float current_loop_close = 0.0035; + + /** + * @brief Current coresponding to state when maximal distance is exceeded + */ + const float current_loop_far = 0.0205; + + /** + * @brief Voltage coresponding to maximal distance + */ + const float voltage_max = current_loop_max*sense_resistor; + + /** + * @brief Voltage coresponding to minimal distance + */ + const float voltage_min = current_loop_min*sense_resistor; + + /** + * @brief Voltage coresponding to state when maximal distance is exceeded + */ + const float voltage_close = current_loop_close*sense_resistor; + + /** + * @brief Voltage coresponding to state when minimal distance is exceeded + */ + const float voltage_far = current_loop_far*sense_resistor; + + /** + * @brief Reference voltage of ADC + */ + const float reference_voltage = 3.308f; + +public: + /** + * @brief Construct a new Sick_front object + * Configure GPIO and SPI interface + * + * @param channel Channel on which is sensor connected + */ + Sick_front(bool channel = 1); + + /** + * @brief Calculate distance measurted by distance sensor + * + * @return optional True and value in mm if in range, False otherwise + */ + optional Distance(); + + /** + * @brief Average multiple measurements of distance sensor output + * + * @param measurement_count Amount of measurents to average + * @return optional Same as Distance() + */ + optional Distance_avg(unsigned int measurement_count = 8); + + /** + * @brief Turn ON or OFF laser of sensor + * + * @param state New state of laser + */ + void Laser(bool state); + +private: + /** + * @brief Read raw ADC data from ADC + * + * @return uint16_t raw ADc data in 2's complement format + */ + uint16_t Conversion_raw(); + +}; diff --git a/camera/raspberry/sensors/src/sick_side.cpp b/camera/raspberry/sensors/src/sick_side.cpp new file mode 100644 index 0000000..c689c45 --- /dev/null +++ b/camera/raspberry/sensors/src/sick_side.cpp @@ -0,0 +1,103 @@ +#include "sick_side.hpp" + +Sick_side::Sick_side(){ + serial_descriptor = serialOpen("/dev/ttyS0", 9600); + if(serial_descriptor == -1){ + cout << "Cannot open serial line for communication with side distance sensor" << endl; + } +} + +uint8_t Sick_side::ID(){ + Send_data({static_cast(commands::Read), 0x01, 0x00}); + //while(Data_available() < 12); + // Readout data which are in buffer from transmittion + //Receive(); + // Read real received data from sensor + if(auto responce = Receive()){ + return (*responce)[2]; + } else { + return 0x00; + } +} + +void Sick_side::Laser(bool state){ + if(state){ + // ON + Send_data({static_cast(commands::Command), 0xa0, 0x03}); + } else { + // OFF + Send_data({static_cast(commands::Command), 0xa0, 0x02}); + } + + //Read responce to clear buffer + Receive(); +} + +optional Sick_side::Distance(){ + auto distance_data = Distance_data(); + if(distance_data == 0x7fff){ + // Out of measuring range + return {}; + } else { + // Convert to 2'complement and then to mm + return static_cast(distance_data)/100.0; + } +} + +uint16_t Sick_side::Distance_data(){ + Send_data({static_cast(commands::Command), 0xb0, 0x01}); + if(auto responce = Receive()){ + return (((*responce)[1]<<8) | (*responce)[2]); + } else { + return 0x7fff; + } +} + +void Sick_side::Send_data(array data){ + array packet = {static_cast(signs::STX), data[0], data[1], data[2], static_cast(signs::ETX), 0x00}; + packet[5] = Calculate_BCC(packet); + Transmit(packet); +} + +void Sick_side::Transmit(array data){ + for(int i = 0; i < 6; i++){ + serialPutchar(serial_descriptor, data[i]); + } +} + +uint8_t Sick_side::Calculate_BCC(array data){ + uint8_t BCC = 0; + // BCC is calculated only from bytes on positions 1,2,3 + for(int byte_index = 1; byte_index < 4; byte_index++){ + BCC ^= data[byte_index]; + } + return BCC; +} + +optional> Sick_side::Receive(){ + while(Data_available() < 12); + // Readout data which are in buffer from transmittion + for(int i = 0; i < 6; i++){ + serialGetchar(serial_descriptor); + } + // Receive true data + array received_data; + for(int i = 0; i < 6; i++){ + received_data[i] = serialGetchar(serial_descriptor); + } + // Check for communication errors + if(static_cast(received_data[1]) == signs::NAK){ + cout << error_codes[received_data[2]] << endl; + return {}; + } + if(received_data[5] != Calculate_BCC(received_data)){ + cout << "Received BCC is invalid" << endl; + return {}; + } + + return array({received_data[1], received_data[2], received_data[3]}); +} + +unsigned int Sick_side::Data_available(){ + return serialDataAvail(serial_descriptor); +} diff --git a/camera/raspberry/sensors/src/sick_side.hpp b/camera/raspberry/sensors/src/sick_side.hpp new file mode 100644 index 0000000..f77d016 --- /dev/null +++ b/camera/raspberry/sensors/src/sick_side.hpp @@ -0,0 +1,119 @@ +#pragma once + +#include +#include +#include +#include +#include + +#include + +using namespace std; + +/** +Type: OD1-B100C50A15 +**/ +class Sick_side{ + + int serial_descriptor = 0; + + enum class signs: uint8_t{ + STX = 0x02, + ETX = 0x03, + ACK = 0x06, + NAK = 0x15, + }; + + map error_codes{ + {0x02, "Address is invalid"}, + {0x04, "BCC values is invalid"}, + {0x05, "Invalid command"}, + {0x06, "Invalid setting value (out of spec)"}, + {0x07, "Invalid setting value (out of range)"} + }; + + enum class commands: uint8_t{ + Command = 0x43, // Also used for reading out measured values + Write = 0x57, + Read = 0x52, + }; + +public: + /** + * @brief Construct a new Sick_side object + * Opens serial line and save file descriptor + */ + Sick_side(); + + /** + * @brief Read sensor ID from memory of sensor + * Used for connection check + * + * @return uint8_t Value 0x64, 0x00 if communication fails + */ + uint8_t ID(); + + /** + * @brief Turn ON or OFF laser of sensor + * + * @param state New state of laser + */ + void Laser(bool state); + + /** + * @brief Read and calculate distance from distance sensor + * Distance is relative to sensors zero point + * + * @return optional And and relative distance from zero point, false otherwise (Out of Range) + */ + optional Distance(); + +private: + + /** + * @brief Reads distance data from sensor register + * + * @return uint16_t Distance in 2's complement, range -5000 to 5000, coresponds to -50 mm to +50 mm + */ + uint16_t Distance_data(); + + /** + * @brief Transmit given data over serial to RS485 transmitter + * + * @param data Data to send via serial line, header and footer are added + */ + void Send_data(array data); + + /** + * @brief Calculates BCC for given packet of data + * BCC is XOR of bytes on index 1,2,3, remaning bytes are ignored + * + * @param data Packet used for calculation + * @return uint8_t Values of BCC + */ + uint8_t Calculate_BCC(array data); + + /** + * @brief Transmits data over UART to RS485 transmitter + * Data are also copied to input buffer due to half-duplex connection + * + * @param data Data to transmit + */ + void Transmit(array data); + + /** + * @brief Data received from sensor + * Only usefull data are returned, without STX, ACK/NACK, BCC + * + * @return optional> True and value if communication is valid, False otherwise + */ + optional> Receive(); + + /** + * @brief Reads amopunt of data in input buffer + * + * @return unsigned int Number of bytes in input buffer + */ + unsigned int Data_available(); + +}; diff --git a/camera/runThisOnRPI.txt b/camera/runThisOnRPI.txt new file mode 100644 index 0000000..c3cf388 --- /dev/null +++ b/camera/runThisOnRPI.txt @@ -0,0 +1,3 @@ + +gst-launch-1.0 libcamerasrc ! videoscale method=0 add-borders=false ! video/x-raw, colorimetry=bt709, format=NV12, width=720, height=1280, framerate=30/1 ! videoflip method=clockwise ! jpegenc ! tcpserversink host=0.0.0.0 port=5000 + diff --git a/camera/server.py b/camera/server.py new file mode 100644 index 0000000..4606330 --- /dev/null +++ b/camera/server.py @@ -0,0 +1,93 @@ +import socket +import cv2 +import numpy as np +import os + + +def variance_of_laplacian(image): + return cv2.Laplacian(image, cv2.CV_64F).var() + + + +os.environ["OPENCV_FFMPEG_CAPTURE_OPTIONS"]="rtsp_transport;tcp" + +gstreamerstr = "tcpclientsrc host=192.168.1.110 port=5000 ! jpegdec ! videoconvert ! appsink" + +def recvall(sock, count): + buf = b'' + while count: + newbuf = sock.recv(count) + if not newbuf: return None + buf += newbuf + count -= len(newbuf) + return buf + +TCP_IP = '192.168.1.2' +TCP_PORT = 5001 + +s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) +s.bind(('192.168.1.2', TCP_PORT)) +s.listen(True) +conn, addr = s.accept() + + +#if not capture.isOpened() : print("CANNOT OPEN STREAM") +#capture = cv2.VideoCapture("vid.mp4") +keypressNo = 1 +while(True): + capture = cv2.VideoCapture(gstreamerstr,cv2.CAP_GSTREAMER) + ret, frame = capture.read() + if not ret: + print('fail') + break + + frame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) + variance = variance_of_laplacian(frame) + + cv2.putText(frame, "{}: {:.2f}".format("Variance:", variance), (10, 30), + cv2.FONT_HERSHEY_SIMPLEX, 0.8, (0, 0, 255), 3) + cv2.imshow('frame',frame) + #cv2.waitKey(0) + + if cv2.waitKey(70) == ord('v'): + conn.send("n".encode()) + + length = conn.recv(3) + stringData = recvall(conn, int(length)) + stringData=stringData.decode() + print(stringData) + + frames=[] + maxVarIdx = 0 + maxVar = 0 + for i in range(30): + ret, frame = capture.read() + frame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) + frames.append(frame) + var = variance_of_laplacian(frame) + if var > maxVar: + maxVar = var + maxVarIdx = i + + conn.send("n".encode()) + length = conn.recv(3) + stringData = recvall(conn, int(length)) + stringData=stringData.decode() + print(stringData) + + cv2.waitKey(40) + #test to see if the image with the highest variance gets picked + #cv2.putText(frame, "{}: {:.2f}".format("Variance:", var), (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 0.8, (0, 0, 255), 3) + #writeString="imgtest"+str(keypressNo)+"-"+str(i)+".jpg" + #cv2.imwrite(writeString, frames[i]) + writeString="/home/palko/Documents/Documents/Diplomka/src/online/img"+str(keypressNo)+".png" + fileString = "/home/palko/Documents/Documents/Diplomka/src/online/img" + str(keypressNo) + ".json" + myfile = open(fileString, "w") + a=myfile.write(stringData) + myfile.close() + cv2.imwrite(writeString, frames[maxVarIdx]) + keypressNo=keypressNo+1 + + +capture.release() +cv2.destroyAllWindows() diff --git a/camera/server2.py b/camera/server2.py new file mode 100644 index 0000000..459f51f --- /dev/null +++ b/camera/server2.py @@ -0,0 +1,96 @@ +import socket +import cv2 +import numpy as np +import os + + +def variance_of_laplacian(image): + return cv2.Laplacian(image, cv2.CV_64F).var() + + + +os.environ["OPENCV_FFMPEG_CAPTURE_OPTIONS"]="rtsp_transport;tcp" + +gstreamerstr = "tcpclientsrc host=192.168.1.110 port=5000 ! jpegdec ! videoconvert ! appsink" + +def recvall(sock, count): + buf = b'' + while count: + newbuf = sock.recv(count) + if not newbuf: return None + buf += newbuf + count -= len(newbuf) + return buf + +TCP_IP = '192.168.1.2' +TCP_PORT = 5001 + +s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) +s.bind(('192.168.1.2', TCP_PORT)) +s.listen(True) +conn, addr = s.accept() + + +#if not capture.isOpened() : print("CANNOT OPEN STREAM") +#capture = cv2.VideoCapture("vid.mp4") +keypressNo = 1 +while(True): + capture = cv2.VideoCapture(gstreamerstr,cv2.CAP_GSTREAMER) + ret, frame = capture.read() + if not ret: + print('fail') + break + + frame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) + variance = variance_of_laplacian(frame) + + cv2.putText(frame, "{}: {:.2f}".format("Variance:", variance), (10, 30), + cv2.FONT_HERSHEY_SIMPLEX, 0.8, (0, 0, 255), 3) + cv2.imshow('frame',frame) + #cv2.waitKey(0) + + + + while(True): + frames=[] + maxVarIdx = 0 + maxVar = 0 + conn.send("n".encode()) + length = conn.recv(3) + stringData = recvall(conn, int(length)) + stringData=stringData.decode() + print(stringData) + maxVar=0 + var=0 + for i in range(30): + ret, frame = capture.read() + frame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) + frames.append(frame) + cv2.imshow("frame",frame) + var = variance_of_laplacian(frame) + if var > maxVar: + maxVar = var + maxVarIdx = i + + conn.send("n".encode()) + length = conn.recv(3) + stringData = recvall(conn, int(length)) + stringData=stringData.decode() + print(stringData) + + cv2.waitKey(40) + #test to see if the image with the highest variance gets picked + #cv2.putText(frame, "{}: {:.2f}".format("Variance:", var), (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 0.8, (0, 0, 255), 3) + #writeString="imgtest"+str(keypressNo)+"-"+str(i)+".jpg" + #cv2.imwrite(writeString, frames[i]) + writeString="/home/palko/Documents/Documents/Diplomka/src/online/img"+str(keypressNo)+".png" + fileString = "/home/palko/Documents/Documents/Diplomka/src/online/img" + str(keypressNo) + ".json" + myfile = open(fileString, "w") + a=myfile.write(stringData) + myfile.close() + cv2.imwrite(writeString, frames[maxVarIdx]) + keypressNo=keypressNo+1 + + +capture.release() +cv2.destroyAllWindows()