From f22a562bca7c6db5f7728d320a59a28fbdc7e38a Mon Sep 17 00:00:00 2001 From: cody Date: Sun, 22 Sep 2019 19:11:12 +0200 Subject: [PATCH 1/9] Add libcopter for ESP32/Arduino. Untested. --- libcopter-arduino/.gitignore | 5 ++ libcopter-arduino/.travis.yml | 67 ++++++++++++++++++ libcopter-arduino/README.md | 14 ++++ libcopter-arduino/include/README | 39 +++++++++++ libcopter-arduino/include/sg500.hpp | 25 +++++++ libcopter-arduino/lib/README | 46 +++++++++++++ libcopter-arduino/platformio.ini | 15 ++++ libcopter-arduino/src/main.cpp | 52 ++++++++++++++ libcopter-arduino/src/sg500.cpp | 103 ++++++++++++++++++++++++++++ libcopter-arduino/test/README | 11 +++ 10 files changed, 377 insertions(+) create mode 100644 libcopter-arduino/.gitignore create mode 100644 libcopter-arduino/.travis.yml create mode 100644 libcopter-arduino/README.md create mode 100644 libcopter-arduino/include/README create mode 100644 libcopter-arduino/include/sg500.hpp create mode 100644 libcopter-arduino/lib/README create mode 100644 libcopter-arduino/platformio.ini create mode 100644 libcopter-arduino/src/main.cpp create mode 100644 libcopter-arduino/src/sg500.cpp create mode 100644 libcopter-arduino/test/README diff --git a/libcopter-arduino/.gitignore b/libcopter-arduino/.gitignore new file mode 100644 index 0000000..89cc49c --- /dev/null +++ b/libcopter-arduino/.gitignore @@ -0,0 +1,5 @@ +.pio +.vscode/.browse.c_cpp.db* +.vscode/c_cpp_properties.json +.vscode/launch.json +.vscode/ipch diff --git a/libcopter-arduino/.travis.yml b/libcopter-arduino/.travis.yml new file mode 100644 index 0000000..7c486f1 --- /dev/null +++ b/libcopter-arduino/.travis.yml @@ -0,0 +1,67 @@ +# Continuous Integration (CI) is the practice, in software +# engineering, of merging all developer working copies with a shared mainline +# several times a day < https://docs.platformio.org/page/ci/index.html > +# +# Documentation: +# +# * Travis CI Embedded Builds with PlatformIO +# < https://docs.travis-ci.com/user/integration/platformio/ > +# +# * PlatformIO integration with Travis CI +# < https://docs.platformio.org/page/ci/travis.html > +# +# * User Guide for `platformio ci` command +# < https://docs.platformio.org/page/userguide/cmd_ci.html > +# +# +# Please choose one of the following templates (proposed below) and uncomment +# it (remove "# " before each line) or use own configuration according to the +# Travis CI documentation (see above). +# + + +# +# Template #1: General project. Test it using existing `platformio.ini`. +# + +# language: python +# python: +# - "2.7" +# +# sudo: false +# cache: +# directories: +# - "~/.platformio" +# +# install: +# - pip install -U platformio +# - platformio update +# +# script: +# - platformio run + + +# +# Template #2: The project is intended to be used as a library with examples. +# + +# language: python +# python: +# - "2.7" +# +# sudo: false +# cache: +# directories: +# - "~/.platformio" +# +# env: +# - PLATFORMIO_CI_SRC=path/to/test/file.c +# - PLATFORMIO_CI_SRC=examples/file.ino +# - PLATFORMIO_CI_SRC=path/to/test/directory +# +# install: +# - pip install -U platformio +# - platformio update +# +# script: +# - platformio ci --lib="." --board=ID_1 --board=ID_2 --board=ID_N diff --git a/libcopter-arduino/README.md b/libcopter-arduino/README.md new file mode 100644 index 0000000..aae9dab --- /dev/null +++ b/libcopter-arduino/README.md @@ -0,0 +1,14 @@ +# libcopter for ESP32 + +# Connections + +| ESP32 Pin | Function | Input | +|---|---|---|---|---| +| GPIO36 | ADC1_CH0 | Throttle | +| GPIO39 | ADC1_CH3 | Pitch | +| GPIO34 | ADC1_CH6 | Yaw | +| GPIO35 | ADC1_CH7 | Roll | +| GPIO25 | Digital Input | Takeoff | +| GPIO26 | Digital Input | Land | +| GPIO27 | Digital Input | Panic | +| GPIO14 | Digital Input | Calibrate | diff --git a/libcopter-arduino/include/README b/libcopter-arduino/include/README new file mode 100644 index 0000000..194dcd4 --- /dev/null +++ b/libcopter-arduino/include/README @@ -0,0 +1,39 @@ + +This directory is intended for project header files. + +A header file is a file containing C declarations and macro definitions +to be shared between several project source files. You request the use of a +header file in your project source file (C, C++, etc) located in `src` folder +by including it, with the C preprocessing directive `#include'. + +```src/main.c + +#include "header.h" + +int main (void) +{ + ... +} +``` + +Including a header file produces the same results as copying the header file +into each source file that needs it. Such copying would be time-consuming +and error-prone. With a header file, the related declarations appear +in only one place. If they need to be changed, they can be changed in one +place, and programs that include the header file will automatically use the +new version when next recompiled. The header file eliminates the labor of +finding and changing all the copies as well as the risk that a failure to +find one copy will result in inconsistencies within a program. + +In C, the usual convention is to give header files names that end with `.h'. +It is most portable to use only letters, digits, dashes, and underscores in +header file names, and at most one dot. + +Read more about using header files in official GCC documentation: + +* Include Syntax +* Include Operation +* Once-Only Headers +* Computed Includes + +https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html diff --git a/libcopter-arduino/include/sg500.hpp b/libcopter-arduino/include/sg500.hpp new file mode 100644 index 0000000..5895d1e --- /dev/null +++ b/libcopter-arduino/include/sg500.hpp @@ -0,0 +1,25 @@ +#include +#include +#include + +class SG500 +{ + WiFiUDP udp; + const char *udpAddress = "172.16.10.1"; + const int udpPort = 8080; + const char *ssid = "TODO"; + const char *pwd = NULL; + + public: + SG500(); + + void init(); + + void command(float roll, float pitch, float yaw, float height, bool launch = false, bool panic = false, bool land = false, bool recalibrate = false); + + protected: + void makeCommand(byte *command, byte height, byte yaw, byte pitch, byte roll, bool launch, bool panic, bool land, bool recalibrate, bool auto_altitude = true, + byte yaw_trim = 0x10, byte pitch_trim = 0x10, byte roll_trim = 0x10, bool compass = false, byte percent_raw = 0); + + void request(const byte *data, int length); +}; diff --git a/libcopter-arduino/lib/README b/libcopter-arduino/lib/README new file mode 100644 index 0000000..6debab1 --- /dev/null +++ b/libcopter-arduino/lib/README @@ -0,0 +1,46 @@ + +This directory is intended for project specific (private) libraries. +PlatformIO will compile them to static libraries and link into executable file. + +The source code of each library should be placed in a an own separate directory +("lib/your_library_name/[here are source files]"). + +For example, see a structure of the following two libraries `Foo` and `Bar`: + +|--lib +| | +| |--Bar +| | |--docs +| | |--examples +| | |--src +| | |- Bar.c +| | |- Bar.h +| | |- library.json (optional, custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html +| | +| |--Foo +| | |- Foo.c +| | |- Foo.h +| | +| |- README --> THIS FILE +| +|- platformio.ini +|--src + |- main.c + +and a contents of `src/main.c`: +``` +#include +#include + +int main (void) +{ + ... +} + +``` + +PlatformIO Library Dependency Finder will find automatically dependent +libraries scanning project source files. + +More information about PlatformIO Library Dependency Finder +- https://docs.platformio.org/page/librarymanager/ldf.html diff --git a/libcopter-arduino/platformio.ini b/libcopter-arduino/platformio.ini new file mode 100644 index 0000000..6795b90 --- /dev/null +++ b/libcopter-arduino/platformio.ini @@ -0,0 +1,15 @@ +;PlatformIO Project Configuration File +; +; Build options: build flags, source filter +; Upload options: custom upload port, speed and extra flags +; Library options: dependencies, extra library storages +; Advanced options: extra scripting +; +; Please visit documentation for the other options and examples +; https://docs.platformio.org/page/projectconf.html + +[env:esp32dev] +platform = espressif32 +board = esp32dev +framework = arduino + diff --git a/libcopter-arduino/src/main.cpp b/libcopter-arduino/src/main.cpp new file mode 100644 index 0000000..cf8043e --- /dev/null +++ b/libcopter-arduino/src/main.cpp @@ -0,0 +1,52 @@ +#include +#include +#include +#include + +uint16_t throttle_raw; +uint16_t pitch_raw; +uint16_t yaw_raw; +uint16_t roll_raw; + +float throttle; +float pitch; +float yaw; +float roll; + +int takeoff; +int land; +int panic; +int calibrate; + +SG500 copter; + +float convertAnalog(uint16_t value) +{ + return ((((float)value) / 4096) - 0.5f) * 2.0f; +} + +void setup() { + Serial.begin(115200); + copter.init(); +} + +void loop() { + throttle_raw = analogRead(36); + pitch_raw = analogRead(39); + yaw_raw = analogRead(34); + roll_raw = analogRead(35); + + throttle = convertAnalog(throttle_raw); + pitch = convertAnalog(pitch_raw); + yaw = convertAnalog(yaw_raw); + roll = convertAnalog(roll_raw); + + takeoff = digitalRead(25); + land = digitalRead(26); + panic = digitalRead(27); + calibrate = digitalRead(14); + + copter.command(roll, pitch, yaw, throttle, takeoff, panic, land, calibrate); + + delay(20); +} diff --git a/libcopter-arduino/src/sg500.cpp b/libcopter-arduino/src/sg500.cpp new file mode 100644 index 0000000..0a1f2d4 --- /dev/null +++ b/libcopter-arduino/src/sg500.cpp @@ -0,0 +1,103 @@ +#include + +SG500::SG500() +{ + +} + +void SG500::init() +{ + byte buffer[1]; + + WiFi.begin(ssid, pwd); + + while (WiFi.status() != WL_CONNECTED) { + delay(500); + Serial.print("."); + } + + Serial.println(""); + Serial.print("Connected to "); + Serial.println(ssid); + Serial.print("IP address: "); + Serial.println(WiFi.localIP()); + + udp.begin(udpPort); + + buffer[0] = 0x28; + request(buffer, 1); + buffer[0] = 0x42; + request(buffer, 1); +} + +void SG500::command(float roll, float pitch, float yaw, float height, bool launch, bool panic, bool land, bool recalibrate) +{ + byte buffer[11]; + + height = constrain(height, -1, 1); + yaw = constrain(yaw, -1, 1); + pitch = constrain(pitch, -1, 1); + roll = constrain(roll, -1, 1); + + makeCommand( + buffer, + (byte)(height * 0x7E + 0x7E), + (byte)(yaw * 0x3F + 0x3F), + (byte)(pitch * 0x3F + 0x40), + (byte)(roll * 0x3F + 0x3F), + launch, panic, land, recalibrate + ); + + udp.beginPacket(udpAddress, udpPort); + udp.write(buffer, sizeof(buffer)); + udp.endPacket(); +} + +void SG500::makeCommand(byte *command, byte height, byte yaw, byte pitch, byte roll, bool launch, bool panic, bool land, bool recalibrate, bool auto_altitude, + byte yaw_trim, byte pitch_trim, byte roll_trim, bool compass, byte percent_raw) +{ + command[0] = 0xFF; + command[1] = 0x08; + command[2] = (byte)(height & 0xFF); + command[3] = (byte)(yaw & 0x7F); + command[4] = (byte)(pitch & 0x7F); + command[5] = (byte)(roll & 0x7F); + + if (auto_altitude) command[6] |= 0x80; + if (recalibrate) command[6] |= 0x40; + + command[6] |= (byte)(yaw_trim & 0x3F); + command[7] = (byte)(pitch_trim & 0x3F); + command[8] = (byte)(roll_trim & 0x3F); + + if (launch) command[9] |= 0x40; + if (panic) command[9] |= 0x20; + if (land) command[9] |= 0x80; + if (compass) command[9] |= 0x10; + + command[9] |= (byte)(percent_raw & 0x03); + + byte sum = 0; + for (int i = 1; i < 10; i++) sum += command[i]; + command[10] = (byte)(0xFF - sum); +} + + +void SG500::request(const byte *data, int length) +{ + byte buffer[64]; + + udp.beginPacket(udpAddress, udpPort); + udp.write(data, length); + udp.endPacket(); + + for(int i=0;i<10;++i) + { + delay(10); + udp.parsePacket(); + if(udp.read(buffer, sizeof(buffer)) > 0){ + Serial.print("Server to client: "); + Serial.println((char *)buffer); + } + } +} diff --git a/libcopter-arduino/test/README b/libcopter-arduino/test/README new file mode 100644 index 0000000..df5066e --- /dev/null +++ b/libcopter-arduino/test/README @@ -0,0 +1,11 @@ + +This directory is intended for PIO Unit Testing and project tests. + +Unit Testing is a software testing method by which individual units of +source code, sets of one or more MCU program modules together with associated +control data, usage procedures, and operating procedures, are tested to +determine whether they are fit for use. Unit testing finds problems early +in the development cycle. + +More information about PIO Unit Testing: +- https://docs.platformio.org/page/plus/unit-testing.html From 7346ceabb06e7d780608187490cea36578ddcf85 Mon Sep 17 00:00:00 2001 From: cody Date: Tue, 8 Oct 2019 00:44:02 +0200 Subject: [PATCH 2/9] Works now. --- libcopter-arduino/include/sg500.hpp | 4 +- libcopter-arduino/platformio.ini | 2 +- libcopter-arduino/src/main.cpp | 38 ++++++++++++- libcopter-arduino/src/sg500.cpp | 88 ++++++++++++++++++----------- 4 files changed, 94 insertions(+), 38 deletions(-) diff --git a/libcopter-arduino/include/sg500.hpp b/libcopter-arduino/include/sg500.hpp index 5895d1e..36bb3bc 100644 --- a/libcopter-arduino/include/sg500.hpp +++ b/libcopter-arduino/include/sg500.hpp @@ -7,7 +7,7 @@ class SG500 WiFiUDP udp; const char *udpAddress = "172.16.10.1"; const int udpPort = 8080; - const char *ssid = "TODO"; + const char *ssid = "JJRC-0df227"; const char *pwd = NULL; public: @@ -21,5 +21,5 @@ class SG500 void makeCommand(byte *command, byte height, byte yaw, byte pitch, byte roll, bool launch, bool panic, bool land, bool recalibrate, bool auto_altitude = true, byte yaw_trim = 0x10, byte pitch_trim = 0x10, byte roll_trim = 0x10, bool compass = false, byte percent_raw = 0); - void request(const byte *data, int length); + boolean request(const byte *data, int length); }; diff --git a/libcopter-arduino/platformio.ini b/libcopter-arduino/platformio.ini index 6795b90..fdf7796 100644 --- a/libcopter-arduino/platformio.ini +++ b/libcopter-arduino/platformio.ini @@ -12,4 +12,4 @@ platform = espressif32 board = esp32dev framework = arduino - +monitor_speed = 115200 diff --git a/libcopter-arduino/src/main.cpp b/libcopter-arduino/src/main.cpp index cf8043e..dbd3a0a 100644 --- a/libcopter-arduino/src/main.cpp +++ b/libcopter-arduino/src/main.cpp @@ -8,11 +8,21 @@ uint16_t pitch_raw; uint16_t yaw_raw; uint16_t roll_raw; +uint16_t touch1; +uint16_t touch2; +uint16_t touch3; +uint16_t touch4; +boolean button1; +boolean button2; +boolean button3; +boolean button4; + float throttle; float pitch; float yaw; float roll; + int takeoff; int land; int panic; @@ -36,15 +46,41 @@ void loop() { yaw_raw = analogRead(34); roll_raw = analogRead(35); + touch1 = touchRead(27); + button1 = touch1 < 30; + touch2 = touchRead(14); + button2 = touch2 < 30; + touch3 = touchRead(12); + button3 = touch3 < 30; + touch4 = touchRead(13); + button4 = touch4 < 30; + + throttle = convertAnalog(throttle_raw); pitch = convertAnalog(pitch_raw); yaw = convertAnalog(yaw_raw); roll = convertAnalog(roll_raw); - takeoff = digitalRead(25); + Serial.print("T: ");Serial.print(throttle);Serial.print(", "); + Serial.print("Y: ");Serial.print(yaw);Serial.print(", "); + Serial.print("P: ");Serial.print(pitch);Serial.print(", "); + Serial.print("R: ");Serial.print(roll);Serial.print(", "); + Serial.print("B1: ");Serial.print(button1);Serial.print(", "); + Serial.print("B2: ");Serial.print(button2);Serial.print(", "); + Serial.print("B3: ");Serial.print(button3);Serial.print(", "); + Serial.print("B4: ");Serial.print(button4); + Serial.println(); + + /*takeoff = digitalRead(25); land = digitalRead(26); panic = digitalRead(27); calibrate = digitalRead(14); +*/ + + takeoff = 0; + land = 0; + panic = 0; + calibrate = 0; copter.command(roll, pitch, yaw, throttle, takeoff, panic, land, calibrate); diff --git a/libcopter-arduino/src/sg500.cpp b/libcopter-arduino/src/sg500.cpp index 0a1f2d4..000e6af 100644 --- a/libcopter-arduino/src/sg500.cpp +++ b/libcopter-arduino/src/sg500.cpp @@ -24,10 +24,23 @@ void SG500::init() udp.begin(udpPort); + // reset + Serial.println("Reset"); + buffer[0] = 0x0F; + udp.beginPacket(udpAddress, udpPort); + udp.write(buffer, 1); + udp.endPacket(); + + delay(1000); + + // type + Serial.println("Type"); buffer[0] = 0x28; - request(buffer, 1); + while(!request(buffer, 1)); + // version + Serial.println("Version"); buffer[0] = 0x42; - request(buffer, 1); + while(!request(buffer, 1)); } void SG500::command(float roll, float pitch, float yaw, float height, bool launch, bool panic, bool land, bool recalibrate) @@ -56,48 +69,55 @@ void SG500::command(float roll, float pitch, float yaw, float height, bool launc void SG500::makeCommand(byte *command, byte height, byte yaw, byte pitch, byte roll, bool launch, bool panic, bool land, bool recalibrate, bool auto_altitude, byte yaw_trim, byte pitch_trim, byte roll_trim, bool compass, byte percent_raw) { - command[0] = 0xFF; - command[1] = 0x08; - command[2] = (byte)(height & 0xFF); - command[3] = (byte)(yaw & 0x7F); - command[4] = (byte)(pitch & 0x7F); - command[5] = (byte)(roll & 0x7F); - - if (auto_altitude) command[6] |= 0x80; - if (recalibrate) command[6] |= 0x40; - - command[6] |= (byte)(yaw_trim & 0x3F); - command[7] = (byte)(pitch_trim & 0x3F); - command[8] = (byte)(roll_trim & 0x3F); - - if (launch) command[9] |= 0x40; - if (panic) command[9] |= 0x20; - if (land) command[9] |= 0x80; - if (compass) command[9] |= 0x10; - - command[9] |= (byte)(percent_raw & 0x03); - - byte sum = 0; - for (int i = 1; i < 10; i++) sum += command[i]; - command[10] = (byte)(0xFF - sum); + command[0] = 0xFF; + command[1] = 0x08; + command[2] = height & 0xFF; + command[3] = yaw & 0x7F; + command[4] = pitch & 0x7F; + command[5] = roll & 0x7F; + + if (auto_altitude) command[6] |= 0x80; + if (recalibrate) command[6] |= 0x40; + + command[6] |= yaw_trim & 0x3F; + command[7] = pitch_trim & 0x3F; + command[8] = roll_trim & 0x3F; + + command[9] = 0; + if (launch) command[9] |= 0x40; + if (panic) command[9] |= 0x20; + if (land) command[9] |= 0x80; + if (compass) command[9] |= 0x10; + + command[9] |= percent_raw & 0x03; + + // checksum + uint8_t sum = 0; + for (int i=1; i<10; i++) sum += uint8_t(command[i]); + command[10] = 0xFF - sum; } -void SG500::request(const byte *data, int length) +boolean SG500::request(const byte *data, int length) { byte buffer[64]; + boolean ok = false; - udp.beginPacket(udpAddress, udpPort); - udp.write(data, length); - udp.endPacket(); - - for(int i=0;i<10;++i) + while(!ok) { - delay(10); + udp.beginPacket(udpAddress, udpPort); + udp.write(data, length); + udp.endPacket(); + + delay(100); + udp.parsePacket(); if(udp.read(buffer, sizeof(buffer)) > 0){ - Serial.print("Server to client: "); + Serial.print("Received: "); Serial.println((char *)buffer); + ok = true; } } + + return ok; } From 5a1206c992133eb66d80bbdccadf63a7c93bfe65 Mon Sep 17 00:00:00 2001 From: cody Date: Fri, 11 Oct 2019 22:53:58 +0200 Subject: [PATCH 3/9] Fix yaw bug, add buttons. --- libcopter-arduino/README.md | 18 +++++++--- libcopter-arduino/src/main.cpp | 64 ++++++++++++++------------------- libcopter-arduino/src/sg500.cpp | 3 +- 3 files changed, 41 insertions(+), 44 deletions(-) diff --git a/libcopter-arduino/README.md b/libcopter-arduino/README.md index aae9dab..1f0877b 100644 --- a/libcopter-arduino/README.md +++ b/libcopter-arduino/README.md @@ -4,11 +4,19 @@ | ESP32 Pin | Function | Input | |---|---|---|---|---| -| GPIO36 | ADC1_CH0 | Throttle | +| GPIO36 | ADC1_CH0 | Throttle | | GPIO39 | ADC1_CH3 | Pitch | | GPIO34 | ADC1_CH6 | Yaw | | GPIO35 | ADC1_CH7 | Roll | -| GPIO25 | Digital Input | Takeoff | -| GPIO26 | Digital Input | Land | -| GPIO27 | Digital Input | Panic | -| GPIO14 | Digital Input | Calibrate | +| GPIO32 | ADC1_CH4 | NC | +| GPIO33 | ADC1_CH5 | NC | +| GPIO25 | Digital Input, Int. Pull-Up | Takeoff | +| GPIO26 | Digital Input, Int. Pull-Up | Land | +| GPIO27 | Digital Input, Int. Pull-Up | Panic | +| GPIO14 | Digital Input, Int. Pull-Up | Calibrate | +| GPIO23 | Digital Output, Active Low | Connect | +| GPIO19 | Digital Output, Active Low | NC | +| GPIO18 | Digital Output, Active Low | NC | +| GPIO5 | Digital Output, Active Low | NC | + +![](images/ESP32-DOIT-DEVKIT-V1-Board-Pinout-30-GPIOs.webp) diff --git a/libcopter-arduino/src/main.cpp b/libcopter-arduino/src/main.cpp index dbd3a0a..1ad9d9f 100644 --- a/libcopter-arduino/src/main.cpp +++ b/libcopter-arduino/src/main.cpp @@ -8,15 +8,6 @@ uint16_t pitch_raw; uint16_t yaw_raw; uint16_t roll_raw; -uint16_t touch1; -uint16_t touch2; -uint16_t touch3; -uint16_t touch4; -boolean button1; -boolean button2; -boolean button3; -boolean button4; - float throttle; float pitch; float yaw; @@ -32,12 +23,25 @@ SG500 copter; float convertAnalog(uint16_t value) { - return ((((float)value) / 4096) - 0.5f) * 2.0f; + return ((((float)value) / 4096) - 0.5f) * 2.0f * 0.8f; } void setup() { + pinMode(25, INPUT_PULLUP); + pinMode(26, INPUT_PULLUP); + pinMode(27, INPUT_PULLUP); + pinMode(14, INPUT_PULLUP); + pinMode(23, OUTPUT); + pinMode(19, OUTPUT); + pinMode(18, OUTPUT); + pinMode(5, OUTPUT); + digitalWrite(23, 1); + digitalWrite(19, 1); + digitalWrite(18, 1); + digitalWrite(5, 1); Serial.begin(115200); copter.init(); + digitalWrite(23, 0); } void loop() { @@ -46,42 +50,26 @@ void loop() { yaw_raw = analogRead(34); roll_raw = analogRead(35); - touch1 = touchRead(27); - button1 = touch1 < 30; - touch2 = touchRead(14); - button2 = touch2 < 30; - touch3 = touchRead(12); - button3 = touch3 < 30; - touch4 = touchRead(13); - button4 = touch4 < 30; - + throttle = convertAnalog(throttle_raw) + 0.02f; + pitch = -convertAnalog(pitch_raw) - 0.02f; + yaw = convertAnalog(yaw_raw) + 0.02f; + roll = convertAnalog(roll_raw) + 0.03f; - throttle = convertAnalog(throttle_raw); - pitch = convertAnalog(pitch_raw); - yaw = convertAnalog(yaw_raw); - roll = convertAnalog(roll_raw); + takeoff = digitalRead(25) == 0; + land = digitalRead(26) == 0; + panic = digitalRead(27) == 0; + calibrate = digitalRead(14) == 0; Serial.print("T: ");Serial.print(throttle);Serial.print(", "); Serial.print("Y: ");Serial.print(yaw);Serial.print(", "); Serial.print("P: ");Serial.print(pitch);Serial.print(", "); Serial.print("R: ");Serial.print(roll);Serial.print(", "); - Serial.print("B1: ");Serial.print(button1);Serial.print(", "); - Serial.print("B2: ");Serial.print(button2);Serial.print(", "); - Serial.print("B3: ");Serial.print(button3);Serial.print(", "); - Serial.print("B4: ");Serial.print(button4); + Serial.print("Takeoff: ");Serial.print(takeoff);Serial.print(", "); + Serial.print("Land: ");Serial.print(land);Serial.print(", "); + Serial.print("Panic: ");Serial.print(panic);Serial.print(", "); + Serial.print("Calibrate: ");Serial.print(calibrate); Serial.println(); - /*takeoff = digitalRead(25); - land = digitalRead(26); - panic = digitalRead(27); - calibrate = digitalRead(14); -*/ - - takeoff = 0; - land = 0; - panic = 0; - calibrate = 0; - copter.command(roll, pitch, yaw, throttle, takeoff, panic, land, calibrate); delay(20); diff --git a/libcopter-arduino/src/sg500.cpp b/libcopter-arduino/src/sg500.cpp index 000e6af..2726c05 100644 --- a/libcopter-arduino/src/sg500.cpp +++ b/libcopter-arduino/src/sg500.cpp @@ -75,7 +75,8 @@ void SG500::makeCommand(byte *command, byte height, byte yaw, byte pitch, byte r command[3] = yaw & 0x7F; command[4] = pitch & 0x7F; command[5] = roll & 0x7F; - + + command[6] = 0; if (auto_altitude) command[6] |= 0x80; if (recalibrate) command[6] |= 0x40; From 95ae197edf0960a8448098bf81c3bd795b8db925 Mon Sep 17 00:00:00 2001 From: cody Date: Fri, 11 Oct 2019 23:21:23 +0200 Subject: [PATCH 4/9] Add image. --- ...32-DOIT-DEVKIT-V1-Board-Pinout-30-GPIOs.webp | Bin 0 -> 60141 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 libcopter-arduino/images/ESP32-DOIT-DEVKIT-V1-Board-Pinout-30-GPIOs.webp diff --git a/libcopter-arduino/images/ESP32-DOIT-DEVKIT-V1-Board-Pinout-30-GPIOs.webp b/libcopter-arduino/images/ESP32-DOIT-DEVKIT-V1-Board-Pinout-30-GPIOs.webp new file mode 100644 index 0000000000000000000000000000000000000000..a2b46b2b9d581e92810493cd52c72b98fe1e5089 GIT binary patch literal 60141 zcmd41Wl&r}*Dead0t6!1;2{YRdNc;Xh*hw6u zv=|jw>dM-3n2+c*^mp`ktmo!io15rStmVB+G#cI6*~!Afa&mP1=P#y}#?Q}xc6wTf zF6`*&Ku=?aBy&7J=R6%q0v}aKp+r}&S`0B z{d;-Y)6AB2ZT`gr+}5j^+-t1c`lR9Dq}K&W!x6txD!T3TGfdC2q%54$KY|AVV$er2nh zN6;J^H28A`y@^$hu5`5$I5@pP-<>1ox5IbPi5al26s(KmKeDni%ZK;cjQEnIIF~J0 z@7>>R?;eilVcBs$;b6f19P{n&cDr=p%GJchtJj;5-Mt2irR$c~yLT@OB)&(N8p#o2 z6AQV!nr1l3pv&(vhj-BlSU%#9UMqh#O&y%MLKD9d?iikP_4xw)m>a$rMkE^56lF*) z?&zc7wbGU&=~Gi#4=)J8qF~dF(0P6wdjNHPpkwET_s4g?tE6pB)EC*z$UsP zr5Q;jp_r(hxId1y-Vt--7rB9GdM<;zkcK`QDzq+ksH(z?$#~$G+l{`9+gTn_wjq26 z8IaJzD>B5d{Q5cJC;{%?*HT?_2ko!8Ppt8K6E986No^Ew{XIG~a^c<~S6WiR=?A&{a9`?TFZ8&G z$qR;~*7Jp9@NyL-Vpj8|=yvbi;Kja%5|0~@**hMpS(3;qK9A;XTe1C7kNK_mm93j4 zzpWOH1R&Xn|B8**1#`xSTC*#Eo}9xQrQ@imsKDQOgUrugya13refks<9ToKuE-Q-* ze(~Z(2nZwTPQ~;wSC*9pvS392f1NJbW{!fY%{l|srs_zckurMKusOqw2AT%nM2@S= zk?Hr`xZSfl`{Q4Y%2X$wr?SQ44Q;>}&PM|-n>Z*^cDck#J^OFgdWCr>KfzDD5Q+9sisy<$iBx2_u zP6!%g#Y^tEo_dcld4yznIg@5(w##nwPRfaTnH;Lz5!#wq@fcMs{vo2Ex0Kp1rE3*p zFw&EEG6;cX@wbBWIbT&HSI1E8FbxI>maM;0r-duPffjrK-_sZId+pFUo;kCQi#6os z2jNmW(|5Xxv-I<6t41V?#wJcONLP!+Je3)!OAqeNc}t*nbL`v&F#6Awl$L)c z456i})@VK+yc3bCHFkN*|u-lU02&e5avGQ#{0gN7$zIbSFXJn8lfx zWqhicWSnW7L7#I@zt59)$8?jf)PRZt{VYhjCJIIEC4kqj7`}B!Zf>P#KFo++5c#hVF19Vfqf{S zA+T*KgP^`g+-Ml@PFNf)(a~6+s@R3Yu0Aj*_YEL~hfnC==F;H3ZmMmqppHJ7bqWOq zE@-&Xc!$9Vv`QK-B}U)J8&O&!hPYz(1}x{|Erv4O0Y;|Wu_s5R%de4mF@=x$lfayy z20zp*8Zt;RT(~T2N&{+}F|eKfvu^UDgl>~m9-#2)duWTT<&Nb6=(YKbH$K5u(dv`9 z-qep;oGs3~Vl!8e!DERMR8LcuBz2%u%iA=Y(T-dvkB;h%A~S25Y-aeHTdeaVcmDAY zs^nJp-H4kPxem=)F;&kPvQ7{OS&SL8s*{QC&KJ$EU@Y3yCsdkDKC3Du= z-WWVs-8^m*SmEMR*h&IqO5$Tzn2?C4)ZRPe~HL`bKz6Uth&0p}1 z-$cMuJ7%uAa2VCV)C${v^$i)0bsfQhZ^tu?0Ya%XZQ`RK3I$Y&XnC)r;uNLXgO3pJ zt<|W;ENfaQ*YI!y<2T7q4LYUilB8Khlt?N+k5Atc5wmot9ktY2#4Rxw2Vv;hmQ)WE zRK+n!2**VYG-xj@Ey-ztM5aO}Dofu(YQLg#>nu@V> zAj4>M&HA(;jeSucfRB=*u#rP6C&bs4{7f!@%bOa!N#>PS9c2Z|X1n*0zz08r62jx; z!TuBd4U#N0GxH6^Yfus6?>`YfC@`of!{5?VOAdTJo{~XRFb0e5PjyNf5wX;X$TsCK z3T3*{^xY6XZE*3sWtqtbIsXtEJ~MIUoE8P}IsO{0evU{r7w7W?izf7&dI4$j#e}8> zrR}$G4AA-z0kaH_pT?MPShe9kbP{R5_+pP)M5-L;10!tZz%ANKRtDi8Q`>_-WfMYn zoOo^><%9G`?)fHlpv(KV|K`kXPNyR^yj>?E?E8BXszL$v9&v2_YKNn)!aLn7h(vu8 zw~HZVC5BM@G#JRDM)t&h%_Ws_m4b=LJa*?*Gph4!<-skn(FdRzhZ^>euT>Zqbs+I+ zEyX)!uydhexvNN7a0o0B;P>OxXJxI)13H$p-e*g{S)i2D=r2l5WSM{C(hMG9s&oU^Ph^^3TtG=%zj|2Y#c&I2KZm+Y?bF$Oft zaG?NS-)xE+)%@5AX|)=*X2KY2j~`w!OM9tLx@5*aQEFe`k-<}Kmg5^$l-gdq+-GC%erSa|E@-bzeB-$?kGDL z_VH)lNE#W~m?`;i5@=uAl^o@FI%FOCfb;g zK3fh&TIq3_qPu17{$YXTB&z>*8dQ42DUSD?9MNQ>QBmmTCCLDGf5}kA=%X)0wHgO* zk(bE>b$cD{$xZJeXrA z=rk+X@)xZx*NVpyphN43nlt8*R1WOV&t8*H2`*g&eQofW7+i{PVAzObLi|YpznJ=gF-MmiGt988<4l=FOD}N;2_dZ5;kS<0pEG z&oE_}R61s0T;D$34vWJqr(pRF8Ca_*o1KQShKA@C7s4g|V>5g4qs=R%kBZsjf9B(Z zg2;N~Qh}Q#Tl4%Juu!aHb4=`C99S@SnA;cA;fF6(!W2jc(i7EvbVa6Ms+-ywic=!a zq;5qfs-IoG8k6EADN%v3YVSI=Mo>E+9j>*${&T;6I;*+(tbGh!vVpM{(3zBvX7QYE zL7@NZG$1EWhGOZB07f+(+;pISg&|u4?(rg}v}s?TAHMbV?`q;g$5xt6DZDv#lTOV; zdZbZ0rL_9=9X|_TLZ6?z*@0m)hE{(A34zaTwrwtn7!MgO0^*USQOXx^Z3H0yNj({f zP>oM3B>)*cJWwHI+O1FfhZLCbKSbFPFH zI(C6#^Gfp(fT`Vlao=ViPbL}^IX{y11Az&${dX6r-SpdM_s!V^;%GQ7m=$y}2=YY! zam`iBCR-r=G)=Ib{3ol8Eg$qe2PxSiX;L3Jz|?|C8I(Z7*nH*Pq~IdwR1j>)qBVCX z5PYiCT2a2tFb!s^Y-=Jl_@+V+fftECi+dJ^1k~mLhp)+MdgC`l7|zenUy4A42E7>m zjhO;$sF}=HkRRM&$tZ#T8;cwA%d`p7u8p%mY42z`@EK<14Ha?k6^$Kv#xdPJd}6E% zK;nGbpv{Vg*DKR}`eu?ge`Vv4#SNb0Z;u``{K^+_x>?4H(T$?+n?1PCctK;dQo%11 zXYmLYRQyROlCS8T;h{2(6NH*ECu>|5%+eZ8tTzK{xDRXc%>>_BQCPWMviv*Xe(+Cw zoz7C%z7~&!R&L*eF(Ko}ZVL&#K63S3qaxaV9PtjHRV>t-wvh+v9Dd81m@7dBt=!+_ zqKUgXE_dU+ldIU@w13=RLqIq3cB|q01*IsjwH;)K_-ikMJq0S&)GIlqn{!mRe}BA8 z_lbNr-qs+2M>>aTt7L;Yu3n&z^#x#IQT1H+Pxt4lSDpp5Q>q(FlwpP6@AAF4ru58m zmeI?&i`UmJ1|+Z9hGltbemK1L#mfm_EW-s`uh(go zP98NO>zm?qL_JPA(Fi+~G{0Bye`+1Clw`{3Q7tGraj`eqe7>t2fk*ROb zd>L5$cRus=?hHfh2JnQ_K=grAUH+(d{}la_d6u(#)bAv(S<(4uIKxtT??L@J*r#u@ zy+zdPvX;_xPQq<2<8}-)DM5D8Z(ymrJe=zO(8Nfw8vtY~gO!a>1}2FK0jf zaUK2x@Pr!@ z|GC@5Tj|q7jHPBK@9x)eQ3fSi?J$o33cI8y)UkpatM6r7pZKkT0NNhkw< zQ0&ddk|H8}w%>@@BfObdx30PBvTG9s`e?%Dxw3Zwx3{bI>p=1(&o-G7QL#9OoHYjq z(XeBUYfmrtpJDmZ=jNo2vsa$qh62f0JZiHGGP|3miBQ!WEcwc39%3~QWpkbjZV6u{ zl0mF`YC1^5W_EdN90?BfiwbQ za-UKS^SVcARIYHj8=4aQl;S>`_EaxHt?iGFN|1;|Nkp|D@{bCMwfXLQVV>-)@V68? z<&OvC4b(~o_ry2{IwSA-foz%4o~eS*6sM?C)t*ef`Dd0n{j#`z_cr4wxnp~Af|*wY zU=1sBAin(!;vCG$PL}eC6CR95G~BoW(Ctz&^`=pojc}}+^F7p%^_yYR79EGf67Gni zELq~PARA)s$0J-X_9XV?qcd4|gu**Ec*;ONox2&+!+tlPr=n5B!rgMWW8W+Qf0EOxap!Lb>6Et$+M^(; zI(Fj^P$EAd00R#M!2W>7fVZX38)7|}Fm9;4*7zPW`p6|v0ok(JoR;_VRY@?2kAhwM z``605RBDt%1R1W=s~*6_VLScTC+gj z&Vb;`vFiK8Fu(^&aH`l>C&FduTk!6WRxTiZhh=;(z68IQV_0UK<01eR2)2j71cx>} zuitL&cGFb~{9Fn9)76`sP3?w{DrrGnBRtB}?Q8a}4R+%og9?Gx;^K-q;izPQ4DLY-fr!qNhmCj2al{j( z<`Bc8hTc7U8(zTWFW?v=>H$~49v3BeWQG?|Tj<%M{^qX=)!p@%#oirR%@-lZNUo?p zlex37rAAI<*(d;c%Hm+z>Q;>esYYTa8r8ivk^>KREK`TfcX!0?i?R)9DWw6E)uLSy zG#9OS?fF7SUzKr-@U)VDDNB)pCym-_A>3r&udz=FJK}0?TAsfEOr*O=dMzCcgf?vjhjx7teJcZ&yS_U| zBX!y`dQ}6d6LI*ekjGQdgSpe)ry|*r)T*x;p@IVSYob^lq5ad)s-QwKJ3GkJJ-7I; z=VBN-ilyyhc6`b{#GR?k`)j9Aw~rT*s%`}(Dw$2 z`g{k`6o!q|p=^@nMGltb42+xD?1buEcPmt5Y0~X-yC0qJobd12AFd$-$|y+us*GMws-PDXn`L z`>rc~tEm9*i@!$L|N0fQEnY+eB|H4`H%zFKDahb|D87FT-~XH9`xoT@KRn?7ot^k) zG^4`QzDcL1pOAA1=pBbO@@OVV@pt=7D}G7fqR>LBL(bTAN6A(?JT#)hZtF3}g;u#g zo1G!KR;+)HC0F{i^}`9~AeWG1&Pi#zdEXY0uG%hNpUqHCrn&fTU1mBn;70W^STSAp zej9VX>*h5ybx-{Ql=@Q2gG+>rrthc-2XnH_#aj&<{pT`_GP9nQsS_n?)>!ND#~Cot zb3XC8{*W$Z%W~C(l zH4Gn7PCmXkH;v7X8UpaFC(s)pMWSwA`}GSyg$7iLrn>c}juk9KW4aAbDqGvfj9vU@ zwV+FU%IH{r`GNMACGY;@7}AH0B6iX2zM?S`ajwENN}-ifl%3y}v)|sIV8Zt+ynx+_ z99~7W=;M>Z216J>k`e_eyil;3TW@;p8-Az3v1dlbfO6q)*fkn1>}-%8G|M&@&j4nZ zRSoJ%5u&zTGC0fjZ2TbkwT`5k)iI`)?mzRk3+-<5Dd!wMuWY&SXG`fAy%D||!7Q5| z&PM0Qn*)If=z=Z)N_=~>iB(bA;8?RW&C)TJowDs8fCXpV$b498IkP>6b2b;}0O=Bo zT=L)BH|;-fuColmKqW!TwoG@u z!FWlUNVfpa+;8T}z-%ah)&0QmK0h9A?1`7n8-bCr0MI^pFid6!WC{Pn=*PcFH}vX7 zI0n*I^fi5}#pL!F1@7nh#}D3-QFZ(1T2_#5&L%3|&0=O(izk`rA^a3#%?!^>LTyOh z2ZCY6cLR9@AD=-m`|2^cw5Nlp^d6xA9-rL#kN|lP%q|4DFHX-*#!Jy?Y1i!!C?@=; zCj}Vh2onv>`}mf>Xi`uxwTGGf->Qv34b+bc2y;seo!9sO@Rg+LuAB#{M*kiWg;!EkU@`s zJRPnd#O5&Ea5Z#&BL|*lSO40|Z+sU9Qfqwz3KvbQymYD%I|h z#@vg^gD=3*Tv81GotW34Q+B?3yG?Za-tDO+FYnrbycf3-A2n3OI+!Ww6UP3jWZcYc=YM1v8VmIFA1eH( zNfwMj2LE3Fk^LitqW^*He;P53e+&J8WdD@O=3)B&(}_s^k5~V2ua?|DaxQoOI~0B2CEGuzCQ%LX+8!;?7-0t4rfUCp(-HvE&kcZD zRcHOs;?cIcxTszn{4!2AEDW0z+!~EV!%cexp;U=4|N52`! zC(yr^GdUXmz<=Z0Y0!N#@%7cIA;u#44yxplHt!7Ce-#u-J%3i6B% z4zPYjNG=`z04+4)M!co@rH;<588UNsmlMu-(Yq zulefupjY?}g-TGZ@aZ_BIA`SV2W{pjug$xu9^$@GQwx8R9gF**Bg&Mwoan;l-q?S` z^de}Q`Kpth2|y-6it<}qTRTsm=K>$K1v!WU%J~wN=wnAfp!IKcSd4}TQE*8E&36wy zV=N)AQNeJ{0=mZ&rq$$xhvC+pKlSpOJPo!Dd_0vdNDrS)lpS-efgen;>$e;CnR7mb zb$@m zF23}!1*{?Mx^D$-a+$Jq8nu`yxiY`MArLs|2NyDs?qNW^K7h;redh2-SNWu5hlv$eJo7)ex`;T8R7{dZg zhL^PMzXp33%b69DA6>{%#F)Dl>vcVau27&>qEu>`S3}6Fv4Z|IDuW#>^Th_;EfG$tMm+42Qw51O1JBGKGr4rBu8P4xHLe+ zAK%Rg1|B!85o@PcU47VJu%kpJj+tFn2mF;;QCk-D|AXE$j9U1_xE_j0Dv&)*PY)&? z+j`}fbRREg*~)@xz-k1b@eoVLwu}%EyT*;Ig2Ih5ElPV)sUjNI?~`e#uKeL+Rkf&& zWQ|>vXeBlz*BFW|^#V7QBt?nHTSL21zAyaPO!P^!y6Hi1kNX%^wNSS4h~=%qEOUV1 zW+GY>O*Cz>ACHeJx5um>356@*zF;<|`!xL1*O~^Anh>>0xpgHPeEdwu-vi5X$Ry;2 z1bLYb65ga8>LwI2B?!=iYSCWZ6dx*-nSt)JP%`ItYqkrMF_(4u`v2VfD zhu{50F*A_fiv0Dp3?!fs`~1X}7LKi678ltQ>@hE~j2K=tzu+^Rghrk=Q0Ul_;=m~s ze15Kl0hiflqQ!}M)Jb~gHGTH;A#*w9gSMV^$d0_eQ4 z7-J0vX=hseZDpP5d5L={9|HRN(i7a(RDu9z*+71A7RGJ3j~P5m%p-AOgtPB!uE;5E z3jbW=H_M>-xS~0>A_ryrMD+xoqOq?RozcX-`>A(hU$MKxNkWZH*|2zxUfa(dWAJ*! z3Ob&r^WK*PcV5jV_!yN|kCyYi#DUwd2y|Ru4@?%L&rixPpJOa=20VC}fvl9O;6@#f zYapZHaY~~FK}|d~_IkoOO_oz@bx9$l+ooi2br9v=GbQk&_T}49ZDmLu>g?@Kg50EF z6$|%jJ-%r2a-aeG9p)|toVBS10*X)|_gTrt$-U&!Jg2tV^kpFRokq7}C}51uft&C1 z@@p?_?2rOS{&~)Zh*^#IN=m)DHcJL2x>n&y$;o9V@L8=-o>OIK(qFePXvm$)SwwT+ zKn2<4^2#}MD-7!`vmWTqJQNoJ1yUA&xy+1GC>CY?`aM%1kCUaN>`N54SW?g@Y{Ar=Ro^K`SqYQe`=z z-Q(>}ay8|Ea&?@xzxD1+e$`HJU^X%5z}%YZ>kR7E z-w)uD%GZ%MuSs1>R%Qd+Tt7x>4S(P^*&N|!>q}I?L|y9UCs3wH_O2`yWA<$qH$qHg zJ(iMy8!~#c1brU{S&BgaMNT&w6f;6e@9lMDJnj29vwBNg%720GH$U8NTRr?3etZzB z-zrTMXm0u6Q0w)!bRJ8{i>^GmW%K^+nOZ#Tcc;lyd#$B+1jng0&pZT{f1;ej=D9Al-lO!_1W|ak{fdM4 zqUl6ccS25rvYE-?(R-gsXDr8JluSIaei zl&!_WVte?|9s#{oijYdk9}$Hc_CqD{QEKNhNQIdhU=n6CWq}t!W&K zQ)wF;AHD~A$?Du#y(Q!;=o)tJTJZQ>Za9v@tB5-*q9_fG~r>!$s6DqMfa5oipw_Zu5bT2~P?zV;F20 zYGt=~zb4%Y6QNF2Go!*b<{s?gdI@kx|dE{?g;6Y7n{>yhE`4n`u~F|2SwD_y<&=7KPbml#F0*f=$vO(lud;ih zHCJ!~UetBGZdL1xhB@1LG@%f)Stuw|4sA^nT?|~4ZRTfGS%Q(0|LzQ7WMncYo5~hd zpkUb(wriz;S|na}9@rvQzFao@&Y~kfTvz5L|1^L~DyaSPotHAzgNxw9v|S&tt-|99 zQ`27v0q2U=SyC`p_bd}cC{_R5&dFhs$FH;K>6yB2a|P@QyOw8gmt{}!Vc39`HO`6| zW$Kg5PheExo9gGne-a>MsK<8rj~?f!cZ~A{QO7k2f5{R0`TAaR1>!0m>-rw*3zq#5 zG@c$z1ts~4inyLiJHMW=EWxjnatom`xf`?jn#=U!B-L2Rg05A?5%Ocer%9##$gxNGLUMdbpQvyo#JI`qUJamJTKZ^D)XnSWuX}taJ4!>&k zGEeV7L&CrOsj47grAabvsdntAj`-YctK-@4m$TnyPCxGCujkNKJBuA{HgY94tYNAh zU-&;l$k_XN97~!u>%D6&(8~l#5%w8>&GKJ5s#`5X$NVyQn3JW9=LDbM*gOaQ@HIc& zj5+14Zu1uUE%E4gmvGSB$ko+fi)i#3npjyqqrq6aH*xdu^fYiV==*)QB#i=tcuV~N zPmPo!RjKptFTKCpFJIo3X?lJFpn75))8BOt8uog%S9R(&Rx4D~{yC}bZ90mBDR=3` zRckezliMByfgQC2FxkJH0z zn!0-_z-%>Dmk;|!kfQ-`cBcKoqwqLIH8vBJ)Yjnj8#1Ss6`|BPQWB~(KpVp@tLI`L zx$26zgnPc0R&)BQ)-k0yN?z1|$`TuE)E~bJn`OYV4vda`8n;XByz0~5T-!5BJYe@Z%< z<(H?b7r4mdrq?)5idu_7JWIWK!}hE3{K)5~1sl9vMfyPshe3c@XL$aEdjroiRP*_2 zpRhdY2Oo=sy=?G}BTmtRb7u4&Tsp}s**7%eZVJ zA!I-Ste@ksmwtQjx;FnZ{rdXDF$b4Vk}QfE3diC7uD6+#`qwlhF|&s+R+ zD}$^4kerx_2d&;~!0Ns~kwOzAA?$3bkkb^6neUUg0fF~exJ!&Dw4D>hCvPpECtt5g z{2`!ANHM{IpPq6sn2xq4J2OJn>bHF;6g&VZ_Y*?_tq&hT$$~!soi2H*D-QvTXFq!N zJ*Hg3q_XJ)&9gf8mEnYCI)nh{efj$41h~dV&TGX3g6y5x*JU#q!atTvBSbYs3RMq1V<(AT zR5899`*SN^-~Hy!<+%0s*6Q);U#-WdJn*jU^urY~HO7lK(97}aCfEIr(m}^K_}5nT zkr54v9(`|XR-VW8=5ndPjxwk4bKVAZllC#5lW`49&FOStD^RB1ZeFy^Mu+Zf2x>^WK-Sc2AGYX>PwuyY4?jN>{Se>g=rPhC<+!};i- z?T@I)fbg2OSoOS*-qDP>!_R1Qo&4D}D9IlJR>U7~Q)(OE(&Zhi^)Dg-a?5z?hWNR` z!~mSxm4N5r5}%}g0B{fycune#PJek7z$X3T?M{ocKM!*e5UtAVO0ETg>oZ;{(`7G- z`SuB!VvVAiJQnV*OVz9hz2lOfRq7_1%j0B3cBfdVUGWn13&>-db`9XuM)ofYyq>s3 zQ_>sit--`##jLeiI@NU`;UiZ!`z3&HrHcOChWwtJ1Sc0#*`cbp~MTanKb(4fzk4z8M zt2BmlbwhAq=I@Q&)3k4Ke|0m`F;d;^6*Px62~F$0&{R(ypJ?suA_9xjq?iDm2=qr9 z_aib!d=@8KkK}xQ6$bUD#87``Sm#9$>N8e`d+iQ}!WPQYry{ts0wNPFg>()F#F+6R z$G`D|VJF(Aez?v*+Ehid$5Hg;Ig&|@Py)0_K8)`Uer(`G?_42wz*q$l`k3BCPEa~R zLu)e`+yls!|($wnX}4RryG<@J(DaMK7~C~xLg_kQZH2D~oA0WySI9k#8%6gY|u zI5nD`d7F0(sn_l#pjaXxjK+VhPEg-nZ)I54{^0LhqoJK{B(x{BYwwXc~h3*(CrItHcX-zLwEBeF{cDL6LfWH7o$MbO-+_0 zZg_JXD;QH02d`iNMKkm(OFwL1RYtu4h^;ucJ%jmE-pkn1Xx8XvljPwY&)RP&zC)IM zh*LTu3M2U(wKJUbmQbr8=r^)m`KpM4#aF4rHn#NC_OlhbMyC_>ay%({TQ|TiiiYWp4|OJtzuO8EoMoni>%&?E4`z7ZSMM(Wduxb6%7-zbwnAQt2*l{RbK!>tX>nA31Y! z3f;EoRLd?mMpCSW z>Ep+XCv6<_&tjG-q};1G($yY&D5V|t*~?J!lDC@EK8H78AE=^T#&1IzoZBorv}OYE z+;@^0T;8WW2!VwfHd+^bt4cGWn!g${o3wLPOsBnp>ezCuN|Z!LPe?t6%kss+oE7bg z{E$-G$3sJRZRrJ!Bs6)HZr_L-v$<`WYXAP&6y^Fzd8A2u zce->o&%*8-H5dYST@&HO4w6luL89MW-^-n}1kQ@+a0s{x@0y*&4o7$28ad+s`~Hc_Oy+f7~j zs8a5lDMMKzQHTC(+=-O3$kdC^5s?A(0yHEJ9I^{nN119oh$?nw(@_W?%PZ5U#QKBG z75&!Xt1Ipbw=!EZjVA3cfmPipieVjeYi^(!CG&HWp!yxrzfd5)?w=pzvpDVQKuSbDXIl-9g znh?IHcW?OeyTifC8Ba0`P5-U0`azf_~ z4Qo|m3Nq+=+;{>T&{Xq}zA;(o+}oJx$~(BylwGN|_)7rC4J{ig&iuy%jaaoR4Y~^n zuJ!odCy2yd^9rw_X;Nq6IJ{)Qz}=4WqPuI*NJP?~#G^emJF^`lS4YeGw<-a6t(^|v z@&a6q*nlbO=;gl?E{o;-13~IfAz8fukwBj%2_7Q@16SLPImP3`B-&*XOV0C0hgHVS zS1+0_d;(qt9tOx*s$X3taU7OS=yDqw*oG{@1y}FySmQ&wA{UEO81;QzVSto#orX2i=4OilXiP1Cj}VX(9ecxD zw8?R{*UUq*(s4SzBD#!inbT@{d7((VdbcQccsq1CF6MfpDtI>p7{HMEFeF0%&h*74 z)~i>##dmE6_cnz1yqb~$yYmd6HL{&b6wHdMeLNJ~5Iiq>7uWPpN_OERvfsps=0i047(;(Z*+znmKroZpFvj_zG2jQ>GT*{ibpD*HF1xSWms} ze(;+m2aPTGy}0pv)-1rid-K%1qS!RpIB*XrX|>oTB#5}6I6W~(^W_z2Bypdl9(EIClCUs#U5U~k%LMY z1C*`?om9W=Z2N#KjT~{-^XaLbGog!8?x9n30ICqjw1=CJ*QKH}J*X_c3vBoxknAw} z3Hwd)=i?-Jb%%p(i1pzu+vddC$63FvS7AGC)iw}~wQIG>A>k0%2tt1`RVbMAoShpV z&(Qpl*muLlcM{4DIMwk4ykQ{TgZH=)y@Ms^ra=m*6c&%s^Tto#H*Z7ycc7<(o4QLr zIL6x(`CJhn|42GQqB+l#CBoE4KfC_!_UbH$Lq+jX?)3a{t4DBxd?0)ava2;M^!HMy zut1QPMKT!xwjL$!a3`%qa_$bAeh_zbgNOaPC^?~%tFKrytK4}_lHUZPd=8OFq*p<^ z>}or(C&@Hm4`pxj*;xt$br0;R9_8rQ;F^@~X&#qg0U3lGWJw}cpY0h4kU%o->s}ow z_IC>0sVpf6&{{_yyX)CKg!9our>wh+BIDqzoIIzB=EPGJDIaP=1iLV|E;yMU0`c`E zs&TbTNFNovtPRM$&a+s(xotO(CS+)Q;=#13i#2|io#T314X<5)kQ)An1m)O%}Vg4&6e~&l88O4_FeX$(4K{{*& z7-(J6s_x+@cd9Wa0=7G$c}rpLKO3xEMvRd27l*6sI<>gh>=Xftl+iy3iKfs4HgJGm z`kb^U9lJJKB%Zv?I?svo=3Q14i1aqf_xb6(lKUeLDyy24$e(?91OyM@rV)|6b1JT@ zH#|chrZSU#AAWd4RzDY*V|LmbLa^1Xet-M;3MeFde}8y#nhLf%aF*X}8kY{*WOA)8T;HxEcVpgUQu<sM}kDRUbdbj1M%ap%-SMrDjL6pa@zo zfPxd=%ubEPF~XD>6Z@DY+>)h=iXF3-0S7fDPW@wu9*L7aWl3bW`Q20x96GW+6-~Mk+xv za+_Q19dZD4B{OLV|MJqAP|S54>4F&z6R>>c(?Rn|<3l*NJPLQ4R36>_Gw9v<>v!Mq zhPU67<5=J|47+&9?=ZfN##8TrBYB2}t+f|}?k)JvdkH3cW1&(&fKXtNt$BCg`QO7H zx@UXJJdEnA9g*V9r*-xg7B9T%a4ubEfO$T-u0|OnLq5?Wy*MwJ9 zp=WGdnIM9%LQd_PJ`@HOafI-%prRa`h)mFq!OKNabys|(R7?kUn;0Ayi_=iz5t$jG zQ}?;_(*7(xGT(*>k`@*(oNn0m0c}(i1T^CMCG`*<#|maqPBTvX!ARm`(~$~nHy#bc zjkWRLnU^8|T5S?q#QEEX_={<4M9lomGTua`_gunX8SVESmlC`k?atW(mQ}HFzJdnE zU)=kU!6YA1{$6c1WQ|hRIGkB@M@oCg!zPpKTpK zZxs0-6&fGVuRVhYmgD&7j;F@G``x@K2ida0$qUf_X`C5>yJIXl&(B3(bKDa1Rwe0U z^U>%1y>7`%yrN=uuG1Gj&G9?^hNoJa&BOjq{5MMeZPOIi%EiABauB|v5s|4**6~zQ zc46>+4>jWU(eDT$KK#bho7>wLX^ireYInC4-g6FrV;4h1d&-o*@?FGrpE6fjX5w>A zeVO$q-eXJQS;W?@9U|uYYopVMxV9rCS*oP^g|M6=_H)UfyqzMmac2L>tCH|YjTxXe zB)i$OvAZVHmMKa3T&m%SA_6?*=<&+m`c%wMJuxd^+RSp&x*O1+`PWK z{BldV59IK{1q+n}!Lb~}CBAl&(HO}0E*-k_gc9c!1$;^pVI-dzQ3A@jWGbVF6^Y72 zu@c`fO7m6DH+`h?G@x)%Tl|WzoHIle)tSWFQK2IC7Akww7xYr_02{Iuh16&kaV&57 z3fG^?X@Bv2RZe&cmRKI(B(#2r%fGBop|XhC)3V&tP=u_*LvX5u^pqO()msSz4s1w$ zSwReCSe{*;Jom8%y|xg|-x7b8la@p*@T?IRLk7^}Rd*d(0(gB{V4%dyr&95RIulHF zPBazX18c}@hr$6B4r`-i5l+#H4-}U2=9%j#sJ@j3{Q55-`>AF60#`KcM~Er5w5ToGU`Ix{!?Y zwe#ED8$LTv0j-jV`nrON5?|v~)zmgkwwCB5%|RY*R0_N>FO zh628eU%&)GGQYngH~FkXk87AX+{)VbGNF#?81OAkp*A`D`=7)oD*zPJv2W4Qqj$7O zY%n=&tyw&}U*A)V?=;LO%&8}NulL+hTWCDwz6dCQ8EMZnEX3pst9=Zs$L17KN+8zFlgzL^RqF#xeuKwPWYKd7$_haeAGHgpxrdQ$a7$o-t;TECh@0mEKDm!_1*R> zfYECa6op>h7blQOYT8~CFJFR5zka$2O@lNsqREOxnI?uNFY#dN&4$;*uSx9+Cs2Nt zB5-^`o7LD`J7wO2huqLX(cUO2VweU!u_`_lt!k>UQbu0P(ah2bK~F=a5YoPx&PknDZ9s75j@Z z<M}J=*Od-L09afFQy#O^ zrO0d{Wle9M^eyr)YA!i%t4dcQm8nH+IdtL`r+(r~gk;nt4jVPZ=-D%us6!Jvj+!-Y zr&)B=%aO`RS}^Lt7ASkd`{38H^)NNxH}gHxc0ejnhNU@aC|P96SHdy)eZ22cev0Tc zHPX%omw~o>A5t1tM-Iq)NX+m7mn!eK`L_=tH6_FrR1H3yzmrD4@omy=*M~DO7O7`> zIPmkc)vf%5Mf9gae^Ss#IR3PpDiVAnr9rdgKgGfj`t6IaProdQLu&9i*e7r__y+1a zDo;Q5tSDOPe*xb>Ais5MJvz6zMUqsm9t%xMlBigRTbKHc?Q*K&QlSogNI$RAz*SRd z@N-y!U7k~paI$%bqX$ON%jYb{NYECV<}Gm~r`kPQW*R63W1$ig!1xxHfye+i(XX6FhR|>%KV@4B#+4qp$PQHW z^E)OMw`}Kf#ze!JjF%P4WoV$2H;ixsXUwhWd4x!aPKgJ>@1p8UW@w-y#u)V*Q!${9 z&tS~50n)QfP0%dHLzFrl_aBL&hl$2G4R!sZ)GT;~`f{3&wm**&`--U+oW%tPK)wiW zti~7zq|xVAuSc!nzUY^&#sehd1L9{4G=wD&XBw z^-~UwI0(*pal7E*%4g`=@3%bv`=%=&Z~6G+EpH*7uWV(?-glmV{?BpG!7*`Pz7t&R&V-;B zM;<)Xf}AmXG`d~J?Ye!v+jWxkt9c7)XG~plcckCMM#eTkzuVZL;~L>qbv3WMPdR~Y z19-y~M|sE@v$|!CV7$UZIk=-x(}v7wu1dq$`_TsDB?7*Xm*SXh0L;7s&Bfo8B4wxF zextPX6=+ueEIZwD9FnTP6!jFTZl4HGM`>MQ2tn-|BU+UNUXlF@POpZXj_lHGoKtL1YAfa+I<00}sbt%DX12P{- ztfbEVbU@~ncMY7bDH+&{G!AfLtSg__w#^TFap}vC4}udWGV$r7oiQUOkcm$jIAikk zysbT&ecO0?9S6qzeI8J32AdBh*ak4pnCHZ&OGJg^V#XQM+f%S_bf}9P<0Ne2Q|gex z?TS_Lh+_#B)P*Gydc=eEctVwg?m?DF=mnh?g621eO%l^!C-ymgfEFisXwyssoantO z3G>S^-SGinaGN!KjB`byxypt3JwC@CBy~N2bEK z4NL%UZLr?!Jn~88_|wu&L=T@ci5rbyE}a`>A;K{}A_&rw8N2 zj|RX}pyojk82`XD6c&zNL12@cSba%WkoVxH1BssxBqk)tDjo*P@>X(UTsGLEJJ=hE zoiY9Pb=g_!$r)!%saj24=QW;OWa#0r)B`WB5;WrhcE+qNN70yfr-Sk05?oz%>#vs; zh5aqMyWAMZD3MQ9aEe3uA8KSbZ#UlfA2k9Q+&@-OYW4K{o5HadmuM;A z#L<}b;_8SPzP;*1d*M`GTy0-qjN`uaZ2}+prt*KIji}qO#Rm%0O~_UcV+?LSasNkJ z^Jiik@RVR|xcE}Vr67cHLSWtlbHi64bv9_j=FMjltKY4>DK7Zw0PU|SYr9r(^I9b* z#*w?)*G)Xe8Iv}+J=d|ObKSlkUgKzAZr-B^E@w=^IZACjt=XrJQJ?7(SUY3J#2Cl; z!;MEYce^-EeAFUzi}U9@?Ec|CpK8doUg1#gM{4lY&X{fBj9IQ$*Ml==j8r|ww{pfD zEcG>vREZvsanqd-!J9g+saaZM{4*1zVF9Mp$W{+9&Rb-__FNSm#Qo!`!T4ImK%y5X z#({g687>vH4K&_38~DB%;{-#27mD9@80*SA=7brpgYBh0Qj_;+kiz!ztWR|r6slp} z@0?s00gm*%>f?HS^YKE?XdJ8>H$dHZM4MJ9DrBQE_NfMEkb~mWyLu&Q)$K`~mU;^{ z!MTcDho)i+2@hYI=GIvw9Gi+Q8~)K~EAO8KkS(ReeC#)fykgi10n-TW$`$2eB<& z72u{>P<;vgLpHf|p*l!baq;fJvSs3BXYDX9yMUZA`&+gTwXaKS_R#6}b-?5=mm~Xj zw?y<||J&Zq&Xgk;n8{y0^XQwPHb!vNjpaH%>x_vDgLK_k2=V2#f-h7IQmtF1XvU*< z0cT5fwkj!8>{t^Q3~_>aBiv`=gIqZsN&k@WVb+MbTyVp>7;k{g$av-E<}It1s20 zZv50>9Qe@yjWM)pU94QWpP2~?nz$-qey9R$lM5K5Ca%iLwt>Wzn>X(j@3k*fN8W+L zwD<6$jl0BZBbtg0O}%!e)w3~18iSoNtG0;M-5Z&y*!-%7q#a{^oGsNIdtgL@r88zp zb<3WlV}^R=?)s$Ap_V?V{PFJgXr{E(6N?@1H+JLXFYziz`;9YmCD~K8REtL?Y2^rG z9pj8CfKeSu(C6hnyeU1jpV~H6G`^DOTWa_@@ER9~0EY1UTprA|R{a)ZoB47xE=ymb znvgH%KBykIog^*QPf4LV(F@Nx0T_cbE_hNf7<(nY58a_R-b-w|gl%%q2L@t)+_TUK zCaW9>;wV%{;)O24G%>25$r%&RoEl*@F)G>{$(8=0xVi;AI7Wk&`!L3eUEKnhWDz!9 z7KpAwm-3lT)YPgNnzG;6;q(ufH39}Iy3taPp8O?dCi;yp}@w}9evDEwhXV4-12h=-!{X@pskDO6wOd-r~j3zU- zbjD;hiA)pqvU_JDiwi7t@Tgxm&Klv+GveebmFxOQ`wK?{HzgbG4vbzxN$Bv?FzA2?c8uycQ$dM^bhB}KZuDB!I)r-@ndw5I znuuWhPmeJ)aiLZwch-$nKJl)&e-IIj|LHM?^pC7~cUFyIh*PvnlfMuVjGrE9wDC?T z&2@~?98PX+sSbcI5|=Q}b>_;&=aPHwM~<;)=Zt7gAv#&w^0}^vX)*N-Srwh-_)p4w z#Y|wVav#Rf+2!KoFDV&Iow;5pXwBeDT|A*R4VA}gDzL0kiMFDPIm>p3o=^SqeV$6=*k@^ zp68N^N6GxgZqfRcrlAcuf11vt#%n=l*GriUhCU_W1H5E7l^Q=qFEJezxZlsh8Phug z`+4~3bj)Z8oeo=MMwnJ2>Gd+5jy;CWsWxQ>i%R-S=j?#R*08YbPQK!^QH3Xe;>4Wr zPQIrQc8ykvhTjMaTT;)rO7K^h-8>wJAzABg+W=Q)jYwgJUVB!R+zJc3Okbaob;81- zF(JO12iBE%ijI|rjiFTatEH{X;iAxFPK=A^Ju0Rb^YE_XM|k}avudYpT7t1#Fs@`U z4*a~idD+>7=Emmc#zvX!rRL_%ETOWM&5g^>2310W^@BiJ+k0MtmCIm50$6c1H(m?O_}zjP-Mu3b-oi}{T-z?Ja<_; zE>RM~SYw58vHDT*cNEoIJg@j);SC*yeZ}7y4c*1xQXNub53Ej#cUse2OfYsc#b zE8EmToA*|q-@CWqu6XbM^Y78S67N#`_b$5uPF*WEQx^*i4`d%v%l5WW?J(^g>ecPRplxjA!5;r zRmt%I0dCCViuXxLNm()dy0Nc>CrIJISWsQZ6Yz^Bya#JqmAvxnyz*_DgX#vQfVWSs ztb#@L&Z4W?-g(v-TSwz!VYir=CwrGPpN{yKxPag*apDx2q;#6G>}+u_eMe9dqIYaiGc-o z&llXiR8YWOsE)YWd#hU)aW!wdpZ-pr?lTXapPw$`UPJYx!pL26w4&R0UGG;b-543^ zr>{Ql$AK}JaUCzI5(t!{+VbN?yy`B%n1_twAl85zO(CxqY%B)z4!qD=#D%d`hLZxeouB?cY-KCW`@M*!fn}4kz0FC0isv)8obL68@E?) zqisR-<&XSy)z{IA-@fiwGBb@}-cz>QsN<>|SB;A|Dt3p5?5Ki5b><0(C4h0;Q8egy zIPZw^4ot(K7Y=U;52ub6abWC(Gv*xNC?FufjTi?w*5Q z#TXA7x0fGhz4icOdc|*FZ+Lb#!dTbV!`Z|o0y}E{?(jE^P&Yo4y(2WH#&aYF=WOZ9L?Pf?X}5Mg|r2mMZfvF1*PA3V80H3;#d zRRLykrwq*e2i6#eDMi7W6^>cpC53XmsMOVDDcX=B-@Y(8@XDl z!JN8pU8uAb>c)COMUU>7aic~r@s8w`Khi`VQ=^qg+{6VK>-HVhdvju}fO$vtybB29 z%c#d#08Lzn#r1mL)rzA<6Q_C5($zP<1}!2v3e{q-@F1|V0&S2bme({IE^=X9V%Qjo_#8GE4Ql93^4kjCD81Wnm5Mt? z%KW~;D;Q(-#z?3EM{r~8$-f0tNvXU0YAdjbW8vMS0zR5VOxzx!=!YpMjF*-D23WL~ zaCSI3+-)Nb&n{h|b)&znk18u0q;}w)OQoFYA0=DSr5lMDq^EcRj7#XNS+6YIimr_D z^kAcuQn&Ppri#Y%PChy^=S+w1(cSF2qI*C{O+UpmP;_!s@4f0 z)kCX=`IS9AwJMl2&NBVOIvPWU2Na$sClRd0lT4u+t<7UM(g%@f{4`~8VMY_^|L_PY znk#X(^#;h_O28WvOvia8Fh^O~?IDa!&X^I*V?-pwXc=rHGymDr=|G#-W(cC>Qjdo0CENWBdhB%@5G{r8Aa6-eJRc_4Ug6t3I zxprZM6EAqVGgmHTIX&Pw_`sVksXm2AFm{hRSI>;__pl~wl`EQ=@iDHrf4Ftl2$Vw> z9qmr{55a9${(LKDzf1K~?EaydLOkYYTAG=6;(m;M+}Ys-d7!RM{zCN6i}7reONHtH zl{+U!Md3JJOT4%U#zZb)91tDgMoT?B!7;JaBN!98g0ZwTY|bh-4sZ%kX|uvWYJxGr zm|*Nu`bU~O3)RRrKr9v$jQ@!+4qiVqT0<~qqH)-qMXOY9EmUVMnM0!SKNZHS_Rmm{ z?_RpMHf@C~QqgZJdcI2zx6A4D0cEr^Zz10Gx-s-Nsp8|^*u>=%uX3%4D`}}SmyYe} z)5QPU6$KNF9aY4Blz$b({3IkW$yTNXyPe(^WL_j#yaX?0dr^Pi{D1$K|M(a55C8uc z^YTB~2dgKxEB}u3nFC&laK+))Z{1wvbetO!4N1TF2gEE?md|Z=(Z?%6t)h={6B_{_w{?f7gtS+5TGHng)`TVP|yP}`3A{aZUbtcQZ1Q@_TKcb}<8qHvy zJRGm!5e{?)G`)dc(8p}p14iTjzWAA+FnY#jX{l$XSXul_ln$L?%8^jCusdAc+*et-e)Ye5Z;v8 zj4Qnl@}!gY>`5v+zIlZu*koCwv@l&p3r|j;YN-}%yuuw#|A-E7=NwKd^hM%Gp*lphbP1H>SHeI?Q>Jc+0 zsuN?(++9_}w-&`5SSKtQ^7RF0Wj^w$F6j@8DcvLR6ds%7TVEyeJQfzSqmXl;q7QPo z;rTk6Q|;qUXH1wGHQtdzb+j_rQ<=@>Q$75RukVgN;qZw?zK1$X3in+WiiU43iOKGS zuR`TSSf|iaF)=3wT|tZS#u#J&zkCRbx0ihS_IHaueAfTkqD3cvMQ`)}qx2KB__*U! z|Cc}U|F`daKSYNwiaE(fae}ea(OCBR`GUmqhlvH10|kk)@@oZ&UMm^EE3PFbCaw%h zpb82;2M4@&6F*nWz}|A8p!(f{z`TnIQ(*kdU*4_zFxuSL|H;niyd${l(({ zZ29+Jp7_OYJQhE*`0npstN!hO+^t(Y1;)Ce`i_POUG;H|{-ANYpyIk-AKW+IyNkv+ zI1jdmZa)a#nF!;uiQYyqzO}=+YOvgxnsNg9RM%&HLmfdr)q)}Q4)CnrCOF)?VwIsw zxjQWNmbgp6<&23f^*oau!8jm(X}l`ltr)|EN&(ZwSX|13kC+=Qwu{EXtA>u$l;&RV z!MxF|t<-7kQ(bL*CFKP89tpuxU`$wbj#{5p(Z#pJ_}M?Ie+9&L_}6^+`paMV*L?AB z&1cqrdHwg3F>Ym5Ig>b0LN{vU?_ z{h9$`9P^9+CH}=?C|3Wb?zP3Q-TmGF$os|O*NnfI0%L)+0i5%2sMS|II@hut2V31i zjB(__SRJZ2AMB>1v0wSdat32>ON{yZa`Xa)G7b4uD>Zi+pX$>^3e7>*r@9apnmajM z&X`gKHn`1nWV~@q4D=hjv5hNUyHqNTiJ5l4ajGZ!jG7pGpX&0RJU(BEeX0eFPxUTi zgMiN)%26I38B~u61$U3~3jeRsTV#hZkn6v;`NOx>pF(ljzvh#*Z>xXx@kxyF$%;?W zqwgpFjbFSi{uS*1FY%{q(b4_{W7nc_;78)-#v6fN2;;zy^30x=z;~ioTXVB4h}yf~ za0xJ$;Ru`{e(!UzlQ+CO6~<6#{_Wz$ZNEj;nB^=@N7Ewu8O2oj@dm@mB1<6?qWfeaH0&ck;?PqA~bXA2InbgSY z7zfrgLjGXID7NSt@+g|hZa!G!Xdi5HT7VmE10<^)vL6cJBaHcW2Dc*czXYFZr4sv8 z7h#|3B9l+GP=GKlY3t%CPf@2iF#h<=+P4j#u6dC8{8ZTDI)HKp9|M1GVM^FY$Yc zA1&Kl{V?dU7+3!eVO;&Y*VHt||G5)4bN!~}XFvO&6~9~j8%n)MJO#$OwyxE;)Eo5} z+o$epn=rEWIXZl|~g5c0lK`O=RQ++Etdk6Sbk1TAo^{Eyi zjH?b(2j(|Yr-gPHKl?WID=1SxyY`PY>QDV^)Z&g$O&HU=Fvk99|F39_|3WaHiMp|u z;Xwkz7p6;gFU&E9TiHUg+5*~~3-QPm=U0i_+ z)jxr{@o#caG-eCci+}RkYp)r9!i{k)bs%JJ&2>%nHoXq+8!(dA`{}@0@Be4-U4WW8 z*MNCL#@Rw70bNUV;~;AkMBkto{>F$nxYu(sd@kwPnq zg|F&CQHu437OTA|w(Qwn$9~#s+kJGtPR}{E?z&sMXZGy*KkvI%ErH9i`RqyC=Bn4?EcpPKjtW=v%wOPxv(UOm;Hq`r*InC($Z)W}nv z>-JP*jDw9wqQ)dCy+q>?;r82(?+~^*eVzAh-`vkZ08<#>cYNpg?z{+NJRhPEw%XW zsm2&byhmItEBkz2S(*7ucwQC1-SBl;**U0N<1ViF__DGKuY2#}lJwSUIojqDO<`^F zL}EQhQ>uJ5EpNSaYiTteS>o)|FHf`ofo>aXv>I15?$(=f2_wCou8?NW%d{5kFy0`+2 z#=@%&JVk*6BJpWB!pn3x8e9vq6wGqWx}s1xgc$eLkOfi?>n6ewvcu6W4jB?-h`S&} z-G(aE7W^E6p7qCWz6hr(zK$=1#r5L74>(C4z`}{4kz?$tN8IV#}?_``?OQ-st>AJn+b3QtM@C*S%OFoYrk&2$qU9K&XesqBW~FUqWW66;WpJ= z4yT&HIfm=u=XJNw+rB#wACJy!;pj5ucg%oOz*$^E9$Il2{^A&{K#LJOmnrsGlNdM_ zx(+BjmoFZSG2LMuLFIYiXL>)vU5(xz5X6!eH!2 zF}^Go`Y1fK6tTl`S|NO_B5sKEit!^##DHC7mz^jH4XDI!n9uU`RGXl)89dcllx#UG z3;fi4bO;)GklbOF21ky=qr<}zjmhVyqe0`}H;oIDL8JZ0*yX7fa0S$TqVEm5gX}iA zQ|Q(v;d{o1;amja|X{6rFi@e{}6MZ;69=*74(-X=mkehJ!yrWeU4P76q{nKli* zmud6)PcB<#a|OwB0>hY;iIge7=i)DkPniBOc!pC{659_?H9IK=+YD!(fco*EGQ#6O zUj?5X@!A*`gYoZMvS$A&kTRQ=n?^(9GSR>P;DOR5v*!CXYk6WED=>@^$thC@L}Mi9 za{u)>iS|Z2PdUenTo;U{x1ASx2sf!qyp3y(PK@(!^(hy|f;7M8d8g7dljcOd6i7*v zGZ-^vn2P_=81P9MFmOyO_C~wG9EDdhAMNC_KjThrM~@oi;@F8i^@B9S&es{(G*$+N zF;f_f8H^Fe{lg>{-co-P(1`MA)OJpA#^OZOy9~+>400lx^`D5G@uL&)BmIStm`Je= zEnoVpAdvD)wj031sBa9PAdzM6+xWq(?=|oI46=DHjr2L_mHXn_V z9gP=(0%XxlDLe|DK)nd8T}(}$8jX+A-w6H7CZea zWf9I4x;PpqU|>hlaT#-p_)SEh<4sKbXlIKWUyJbfEHF!w^tVpUV9a35VC+1!HE|q|6Q)uXbX-42-aapag3(h)lT6$A z8N+zVtYIoxVfCLen*u2@)L_rFsDR9vG12%{Ci=B3U`$$|m1@9e?zrhwr}r<>FkJyh z)2Y!I#Zj=l_ta6a37Hzx6Q?46r%$KWQ%y|78xU!ur=lN12ci+&iBr+q;5aa&pGNe< zf#~Vc{r<7&=tL!Y7Xe_L7UkcPiqx%3eI=k06U<=zq$QzF%o~;>UIr;VS)0HK;QT|C z28SeNtWmN{5b%35&sJ=8O-EN`!@6MkS9AOB;=R zm&sw{lhL(Pqb7}qr-Xz#QC|M7=jlp;-)77>ziu5j8grcXT6jQZ#7lAp<0mZZ+!Kp= zV98TpB!wu&+MO;9J8%j;Vs|D=pvDK#A-5Wn_cHtjw+97S&-|K3Om(z1L~eM_lZiYu zNhx6tN#sSN*-FVuVm2g7&q+)r$Yk^~)6)s%9E|*U?-hG8kS?yVQvYrp8z*kO6dq_6 zS2Tn1lVa==1gvgoxGXMcsH>}M=!V$Zu-ZweLX}xpm&p?@YiL*vGoWBHg}9)u?y?vx zKda$KJTdmnsfIa-Wo5{Li5`Q3%A97*cX*gU@7BSMk;9_3Y+5RcZXN!Hw5n;xs9M_Z z)_LSq)6z@Ydr9drb7)v$kKW0lG?`3Jb>J9-TWi)V-B$&62Vu8=B{sK!(uX2cp(xZj z?6#At!lMnAqpGW<3Z^65?Ycg3i1`d?eS|(RHWNycEQvT*NDv2(1(iKSlNBc&i->3? ziMJwd)>8A0&zVK~ixIxen7ef#{@}FgWui4OTf+E&Bx*Y(+DG9=-j{;z;5*hZxa=j z*i*%hdIBaOrjE}WFB%w}fsiC2OzNzvn`DT(<>(b3W4(jW*YK?653j|hW( z*vuo+;VC)^+PLYF=#u#&B6-~O=%l1%LNs?AoXUzJMAOkvN2fc#CHjH;MBx}s7m+7> z!PvTc9Z7V~kec?vtvd)N!i`b^x|{lg@Kq?^Y=D`c(n~g&BPR8ZaSql3{0#OUk@9-Z z_ez-v<|iJ#O*wwxm-5XmJ+gj)sOx*#H|}W6VC*->VEyRIzR{u*XIrkQRA*a2_)$Qe zQC&C+mJdajs_>*LguHyUCA)xtOF#-zpaWOtQLzt_n)+=U7NwN;$nq#NrqNNmXwidW%Koul z+q!=7qQ=m{^Nj^<=8~<^dvxWX#LT*6*vP8c#+8@qmqdSJsFm-J*)XnfTWrsm8RIJE z$-Q7K!)DCLlqZP1O88HyB)yyv;R2*PH>hX$0cwMEZw$JY{%NKAhuj+hmN5feTyCkT zp>sy`o$3yg`C!&10-OPFb4?W`3!?WBTezlH8M)ph=rNqiYEm`|ykd+e7>7Hqf3Lsx z(JMLMS6}Vot0ic3jbq7~}kAeU&6u!fC41YSk48<3uLBkF*~!c>)BPp#m;j`=egtEgDB=!AD#k^Q2==$nxG)KWe-E7D|M&sEnWsi?Y{>@e{`En3xwKm3qqY&yOefYVXJ<$;!RhKia?+04p1)`G7Gix4srI28mBB zeC|w^4@{BMFWC>WgVEC(uS&frd1RI}ns}PaWaO!iOd4FN-mfc1w@xlFnfJ25!bM3% z<@n4_J{x-&+6rsOIcQI{m$oseFF}-d-mW}>Fur!n@ZEWYarpOo?4+hE)koWNnEA%T z6^$?7&|Se8D}>G!BhU$8npco%IhkE}di64~5HLPVN8VX3Tk? ze)_2yFrNIb<)1!u^PJKxoXz@T3gg1Pg9NuU#@iMwSpYg~iALL0A{o>+hFafV?s3`V z=R4H(`n*Z{4lZEayA3T7VX|+5utMlJNUfWpy;tttjF~t#W7r8)wcG2bgGL-lP4$`Qzn2`9>Qo_$;%7;7yeSs1Ys32yV%hN8pz;#jo! zniJzaNI#D%)f$Pm0_xqN`TLbsUZSyKJ+~+26Vx`YO<5AlH=<}3M{gp6cCXx#`IK50xD&%m-2y$OTv``Z|inD|BEyLKq8rENe`y zdS8|55$Ba3LFW|=2H)4+MwROD5g21!+XjH0m1;*PQ>h-NXso;Qr0R83^s>@ z?z~cjSXvwo;v`yA0;%_)r}_fvaFBiCtGd&5mZ76@#5v;Yh=>a>g0T8^2+gm@M_AzC zO=lMu@EsqoyXZ9<=O3N`tzM`)1IE^hRT{aaGCy|op;#oiMV03^!$wK$Cq;A@mtcuR zQ#w*JxTl(1KT-`9Km%aB1?e3DW9?yOhbh>&1C*Fj2q(lTHax8`(4y*R5Mz&Ak$!Ds z^V=-Gafco-K80@`w2fgE9?=^Q9m+d;!#Wg(R#&umGiq+7)1<#PyvAUtoJ#Gvm#xQQY6g8L?1$Dv@)zyZE zD`HS)Hq7ew-8PQEX3Y0M!B&aFZ6SV+*ls3>66YFD;LTJ5=Uy@9RKWOAK6Gr=!>8*& zRcL;&10;*(Jv!*nMLz2M9y{z8(}G(gjEQWk^3pc8?jUO$!G(!>s z8?pIXDhY(%hqMpWr_I5+A)%q(R#fcShrS0E%PT01d$)0|ZRpS%qhPlknK8LN4)kOS zW-#tQZfraP_eZ%V)I>`~VZh0X?v?UjF2rJV`A$N-M%mIEDFWT{nt14uON(P#}11b)0vEEMJc+FvL&ZD zH9{Ya03V{BbNTqmm5Rh3^UPyB#`D&x;XXNUoryk#cD3kAs9;lf(ig^lnK7AU%qJ~Y zM}g1T4k}z8bLvFMtPQYE{k!o2DfQytO@#N9vOpsVq-YjKqR(O$SL#RMCZ;{}7^hA3 zaqHMa-@0))9X<6mY{whn$D|1SLnB_|G8jK;F{VviI2pT=8I1iekpUG3V+LaeV}FV@Eo$s=lvK3*l66;UKqbaX zcXbK^D9)bh=v06HKhm-oj9FP}etiUzSON5NJByUT_{sYdt+NV-M~qp}FoVU4c_Aa9 z@&fHw4Pe|DMvliMpcjctjr3zhMRwNM>CZgI(*ac7l+E?isB0Vu{#O`6Q6mE#|r$rb!?oB8Mxq<$>Ms_ z;+`6T5-){{Y*bVsLRGfP<-CNQY!&!0;Q}7acLHR^_&^9ci6^mI7{|1MipS7Cagb0)F4 z04B4Lt5s(S9nmK)&~+(rtqz?M()fwBBUm}S_$SbChmlfht;Hs83}2Dj^w z$ykGaqMSbfV^4_>p5zohf}Y{zDY(s{1h*dMTV{sSuwZ;S`v#FM2FV9VF^O)Kcr{(! zE+Ej6rK+>1vq7&{VCWKC&Sa~u5|>qA^ARf^6^%vB_cF}w882kW%>NFjb*c9Y^i{rY%Rj<_pk%RSh-YSaZanBz8)?%r}M^vW@B^ z4-bJhfVIM0iOrZ5C5zNO<_X%ig|WGXC87K6JJoWow`eTlBHf%I?P;cX5^`~6C3(kK zUavePHhK6tsjjZ?oi{O_zZfpVz_M;+($r^A0rM_zOZw zfZ$e#Rkr8Pz%TEc^EQ%%$;LKPd7IG&3=_uP*vJC{OriJ!GUd?}BX^#VC+3OIo>paB zP6Eb%B(m{gp6v=%w;mefJsBB)RUXdh?floIjEu9LP_>4u?o~V*W67Po&MIuL<-E4dvqc!*R;Rl^-iPt_SCqq#3)oBu$lSEeiy=8D2fmWPWA92UXa)(Nru%^^f%h*4L3FFfhBof>rjLrQq7B8D+Ih}o$v^%cwTo|7PjJp+ALErT_7&re_ z+4Mr;8}|xhs7vlW8sq%U+cdpzdkAjnSgWajo8w`|MA~&?FGpY(m3Wc(P-aX*sRuJA zDN=Se8a>UJprScW9FhuP^@UcYSBZ}(LC%Uyf2y0tA{Mx~1#`Sss*Uxv#O*>YR8O{b=6s=?{LAg| zei(yokGy`1!Fc#EMs;Uw#srMPJ>QqPY*v@kH-9=avk)*wUDpU>p805I<^^S!*nB$V zZj0(sJ=G7IdUX@;SyEu2$?)L|hV-VUeb8lH81=#LObVad)+s3UW9JbSp$*0ViuwDe04`R3u>3+i&XcSx7 z{Ab#Xshk|R!OOM9YU^ryaO$%!02y%N8zVYpGjnhrk#_)JUWk9-eca zxP~g#(6{BRR8y{xoLl9HaB!<5syiB`J*GHe?6;$YSXEMcS(E&w) zy-T5}hXY+g*tVVNQVfl82E5XwKWF?^k3#U-n2dj!mCBfmUYSTVsd-3@B~2q?45?<7 zws6bh>Gn#E)?5o~I32n~>|DG7E!M=hR4!WdXQ$w{&9FE02ti>ypr_gbs}402o@PvL zg&r0n(ruKREVbjNCq`ac7@gFLSCU|qdINi^TZvbvPc@@xtihg9WjVK*SQ9#(_-Z@02dPKM#R$m+O(#ns%(C1JQ*xAL^32Qj5eC4%|`l|0+u8;V_Q#j9H96vOl*jEttA> zvtJ3Q#ALA;jF~b#g|UAyg~6D?n8BDS48{z`48{z`Okpr)FlI1jFlI1j%KsXS7tPo( z41Z=UqFzltJ#j{&-~UZ_jx;2V9_4o#o#^!B&Y9>>Klj8q2IB<(?%Yg<&))}Q^}4#H z!%|kigv3l)yJ`X{cXr{i2Knr13j!%=Dfs_w{xpFfYD{i$^2}!)<2lK}{@gi13U%XI z<6z?FhG>5u*bK%`T2hvYg~L*KnW^w{kc=77pNw7TO--8tQ!wIQn?%N!t4yK_>)yysL8ap!^s=*cQarQfWQ)X$~_RGwRBWiWoS@{((w z;$6Gl(IuQ^cR1{4y2MNE_BtoW;;Rn(tSiC-I0ZJ$S(g>O0*C!{moUU(ho8BuaAPd@ zg|WwBYPM4bwebiuW^5xywsCPI2Tf_>gf`}b#HTTop2);$Y?Qc|mc%a3cjAv{IJrKI z0`8@}@vmA1(mQ#1=^ISa4-ZO%*_U>We`5nXn15;C_*0PG&pxti{2HqljI*+kr|Rj} zecDeT{)3qs;V;Hu$jhuJc}wdmT2|MIFDUEkoPeq>5Dj&+&Zw@oWUeN< zg}QF>RidwM7I8(mx~{H{xT1JOG}ei1L>~5iD4S`)El5DXmbxe75g6wmAvS8jjHwJG zw-v|cN5b?tebHv{t?tEhpL)=Kam^}h#?&^GGP2y$jOqF?nktBeX)rx@h510rI%21~ zwUP^J);H4j5vRC2^a~#l8`(yfLYwlZM!_JAWmu^fner4vOs1=`{Zly@;}wM@zH=sg z=U~S6+gxrhzH@s`(q!4cFuQ?LFH~UpfTcY`n=$vA3`MNNB^oan zvrF|FE?a$R@e1?$TvmN8tF;ouQsuc^b(1omFXys)OJdtB>vP%88Bv}Xiv;K+&Y%4> z2ji4T^#8~jY{oQ}mT0(KxN|1+DY$c$ton_hOo2Pcs?l@yztw17kEEGw^^YY+!C;Jk ztOhdw(K%(x`v&D&*sA`im-y+&JN5eixC0lwFMH5R`~=tic&Ai(=gw#5>uY}?*3uX= z(b)fJ{8cv6ABQe$*ip@JY*u|x_{MTVU7;K$YRGZ<}t&3CK2~LYUDemrG zyf`WDRvd~K2v8h~ySr0dLUES@#e%!L{Mr8*`&^uH#>iFfGQKz8yVjb|oa@S5D({O* zI`D1`!TPEfJPgmZyGCh5$e^o#j08FlPOCJmHvA5(E=2^-7vb}(TddYdX-FFgN;K%} zBN=fSFGB{nakQ<B zlLqL95&b7$)mjhOWW$?b{IdPfm*&}Tu|@ikR0yesDtP0zJ1f|r z)IRVY6?}!gXlrNe`3t!Cdn|1^DrO1%!0P~!wy0VC{E%~mszyxwV%A7GO{l;p7vtaL zB4g%zDVi^}hGtfTm&K(o-fi)(N{G&BK?Ksvptpo==nUuk1QhsUf+_LU74#ot(2&XtFx|V}kmYW@M%q3HAV~BuD+-g3{ zyZ&-e3<|teUc%^}_scuGG%EBvJ0l+5b zD?ZD7zurc%KXEeXSsg&LDu8LfN+W)#Vun#mjP7UFL1gaCA>jSV1>WJMU>O10)H(02 z%LBO=xSDK#!hi&UR)-L1cvvss?J6RjdLC`q+|_u_%44X9XPHSs6kg73p|OZ6^w_^f zKE#0`?H)W;(#s-Jin5SEvKixAa7`IWV5=myf`Jq$bG=cqVwzWFihxq@r}K-?URMT?c;G54;880txNn<4iW3efhpjP>gkh>j!CFRwT ztD`@gUR$9^dlsuT6Bpp_Y%5rZ!HPo8GdAk?)S!oSi|puOop^zCHoEhbnM;;-Tkjg@ zYfx+Vx2T8TcMgGX#|>0B-!GE(SOY!Hgp2M{o9zBg1Hw+$REr&st^V$8tHbr`;wHQo zd{9nW!c9mgku0(b!qtpV|BJL}VP46#`Q-ySj^+yN$C89$Q|+D%-`nw!x*diwd%X15 zqP!XLA8hsy$KkA|oFY+Jsu^EoDI^NUUwyvZEL5<&JX6jVR?vwJkFUa}S20dp??4_) zD-w#q&Ylz+xDa$4bAWB-(c=h)ETLk8zHwpr#y927^q*tOFk-vd$;Y3*<4fypUH^{X z65j4cU;bzx3dis`F^Hxd_E9ey`qMpPC?P5vfKckJcD3-Thxu>rj7(HA%LwPY3kq+z zA?<9FW`@sP{|&z3wI?!EyrH$U2vXL)uaWo1FlOZQT^-J1K_BQzW12t2n7%LhDL(!} zFW5jYC-M_07+o`@pLH%nAdk{g8S9hfE|iqFa<_1rzd_8LSOXw5TMu?9kd-4t3O1u+_9J|XccZdM2C{LbMt2fo) zvC&t`A@Ecy`a~ofF7|}s5P19diL-tC`H9@;@u0*hD`TJIdCE!*2zb&>;POVJlF_U6 zVS3i5*AiCUBosEqjMyOREc=@W_X}vXF^mbKDQY~5nY2`TfQNfTmx;ob4}pz=l3o*Ki>7SxkTi+i-D!&l%0xu!STXCVH;pq2RD~n zdYqV+{;ghMN*5Tf0frP7%xQ$9uLGD+lx=xkiUi3nXC~hmC{=J2Ud)3lnT85 z6A-4e_~#as%=Ffa>X_3yCa(GPniJP8m38#ySwY(UWx4vhBI!-`E+Q?2oGU|z#dU8i zOW+VhouSoB2?}WG0b32`tgD&;n+${OT3ue1PHAS*q58@>vv;^U-E* zVGu4!X7)2v6m-c@49(ZlRSY~d^dlPx-qDDM72@BV2`F7gd=5$`VRd^k5Floz-?*F= zQ>Gq7@x4ScEFybfOXlhVT)(egIdL$DhlxV#xw%hoXE#=qO`;D z*K_dn9*08YVR#A{;s_>0BFZ?q#*{3Xjc2G?mM7!sk8ByMp1pZL&bvZ#@wWyxk*$F% zY$deP@|-SW?|ldH`u6j;^hPk>dG*tWzBUzMPpgaEuTzevqY;%HuT5gwnq zIiCAkX~{Rk*ZcrY8gcFd9h&F@jjEIo(MjvR5jj}F|DkEQTy}7qu0-&|5?ibH7p0`6 zQ3?h(P-en*ruUzcQ@nN&=TyX>ikRlg9Wi*-J4xTvP6$9~kWHVlb|!>NwkM|BOlA>J z=G~;AIWB>DIBAef(57P0gR&*Pi@+6oo1hz$4k+p@!6SW?v>L!3p_SQoK2H^ym_CZ( z|AF_3L>sQqjwpNA+gx}W;ZK~)`>6F;%HWS{5{+FU_b>NQ5bnwwyl5x8QKjG z+8U6BJ=F~9>wfZZ!tNXEl5yx~%2m1w_baLNeQ}yVIgbKypRcK^*RnKXOSV2!Bxrms zR;lvR(Lf{x07$TebUZT66`%sXClc|yWm8V_dNa@pa2?MO-#Kqt58&Nt>z{11RN)ku z50Zxdgb&g4fR;wdxkq9$#KXd{=-6Sr(hH}1r0ma>OMY)<=Gw-x>czQio)OZ?G#q z{jd-c9X;xx%^v3~ZXbWPZ&)j*JA9HZU^T(8t;zv#69F!8q~R0u1+GsKH2)13?4+K6 zi`#BS{9VH`5{Hk1x3y(C0ghH;^rsE6`-m=bt9o(^6{024=7*G7gm5AU?*D3iXlA?I zO&}>iXR!9%C;OY>fwDW+lp1;&x0Fnm2QLwq=Q_uLj%duu{*1Ny&XT(y;4QN7i{WIp z^P$T~meJwl52a}Xu2U}hI)jM|O97%|9a{X1becu> zcbR+c`xY-QE-cPee%uAs72nJsZs|=Kmp4)OZ+}^^YwC?r7(DEkFH2nqeTV96o4);! zxy6pr@%1Xy<+6McW;0+`8wnmhbM;{P1hU1(-*GK#COM{ZWzypVnVrUV*krFN6$#?% zmfMg#2@e-NxDgNAg%5b$sRKeRwo%d2lH0IMQjdjIwIljwk_( z*icF_&g>s{j44fuDYd5>4vgF{MEXJ5Tc*Pd2`sFvw5#c=R@ zwcZe5HaunL-U1OkVHE|BTczTaFdhkfm2+T zW1H4wN5|Xg$2g&NGhr8)8Tl!2hqpPNM`Yq0pW4V?o92zMwm?A+~U(Fi392Hd!hBMOd-tk zGi&jOrqzay^}Lg_<=BbZ-!HK66yU){E8FLtD1eNyqZJ5}Qm6Sd1;lIQsh$ZZ5eV@q zHKJ*^@s4w?!Us)lycR6iCD@Q*D{)Wk9<+x^ZYiP$1y{pU(N>>}oB9vF%bLmk$CVRG zY0J496`%XXZ;=gh9p>^ul8`bB5cnz>)rre@VTC*)lQ}!|WKE{@i=_$24kZIPZh)Kt z6!_s7liFN&gQ`E^NSWjLZY(Ve_|2b&7u0pa3p%C79m|EzcwK0Puycz*=6iW+&_1+= z8NkJzj3#R0);3}PxZUPPt3w#J3FiTTUi!AV4If0O6j_yx3H8saq%u zKEUaxHszm{s) zmsyUb_0RI2O1i^C%F)?`wNWnvz5^SIlnBjR&0B+;d_9L*%5g?*TyFny{guqyEacp- z%ddMl`b4K)*40*ykriB0|A`<*1K}?U8)#vZQ{tuT79g zSQs_mt^JOyfr@$)om!bMQ48Je_x4KIEoWTm7%tv+B`>$~(fg|6lGZP#tK8k#9zUk8 ztN(f!gRQ;%9$$4PAf$_ikEziL0g_h8SuII;ujqi}?JT>^P#Wtm{}11RyLTn6B#VX0 zGqZAxEwn;8$DW50s18`P^(AutweM+|Fd5@GRz-ci(+16td5VX$IKXwJHXCV+MDM7q z4aH;u78iFf#WF3|OC1+ViXHzneFT?TuO9U+efx>j6#&JVZaq(iO)zj5{k9CwS3Y|< zs1;G_Ir%E7gY>^X{pj`L&#$Xi!iBH4)td~{#qQRK(r`hr&(_%Igp@Rx%@gITX@3uZ z{^JuKNbBN!^^?^1dluNzOW!p2d-kQX#wQ)Pm}qvHY73x%xr^4+Vo4gNZsA}rKJ`&B z3NPKkgR9QEM%d#@n-~$^T;lV z(IM$9TzRfUCP4ZDAoCYAuCR*JRCqt*>v zgG^sA_GL4yc+zpV&UbR&g&S$QQY&eg{QK5}8w=pw{Rq+jbEbFk_^!La6Fd~d^^1A`@V4;KT-=?;k?Cv|PD`8*sF1IC z1IP1GSs#n`^j{E8;#i-*E-j?B(1i=qDy>O_jt;Xl5+Cq`%ZDi<6w0GVDPnLTw2-v& zaN|(%4a~$`q}CAuabkJjBWmN#~_ZMUuXo40swqd=n;K- zJv>K3dX;Ek;OS*BkwRI0X0m~z*8589sw_j$nQ&`<$`Kvun|O!o&`eizwf_mhK;^?( zl1Ud12xIv$=S*1KZ3cwp!cLJCs`zS1X=kKMe#AqHLdI8+>(=7{@yoIk2~N|aX?c~G5xu>T z2$0K3K9r&#aA5H3nePRFLXVAqxa|yO85tVr@A{dhKEHwuMaW~-scuT{(+m7D54FE>)Lhh@d;shz zdLwDD-1ICRQ-B0tq-wV;=01thIx**QhKJW3zzNQo)o<~AwzCguX=c;fNPper26eq% zb|q_O9}QNXenFqqe1*%>;}O#!I!e7e87)xl-6;~Q3Yit_fH`ff6pWa!fr~*{vvC4k zlC8&d3-7=oTV;h+UV>}wIW)nB2S&IrOtFBY>A|qNZR$O`2*o|gOQoe*Yev&Lj9D89 zh6jV^w577{r{bj1JtYkyyce4g1{P7o6+gzM$Nf!Dawr){yo7YQnO0hBpN{!70=SDU z2O@?D)&P!#cw3|hy@OYIvO^E%e9ezVNM`}vsHncCh86!n)a6n(;P>@DZFT8|K*zz! zc>w6r1sMCSiKEa@RQIsU<$O#w;{HB1kBngh4RM0!7*TQ zU>!d5WUHv)JLpZTk3ZTnB$*#|YyS`vl%F8hFpjk{{=%t~LM6BT%}W~e%z=YaSgq(G zV5^ExmREEXbRnT7RvPQzfyp0lun(+DUwKFRQ`|->3e3hvQ zL%y=VI6~+iG_0$Nb-_)j6#hVQ_{gQ1-Ak%6M;d}Wg;KSMkv89jTr`gx3<2GM0f`)H zK@E5M(ID$iegXlFM+<6$#Wnj{pdoy%sS zA4Wun`7G@bn!{-R)(D8NtF5$f{ws27hAobjIf1!_r6e$^QF)LIGNRzM8^nr{MyP^D z^Oe^fJP_ebDU$|Xi$E~D=E9MGA@8!pOTPMH4By@)V`lb=UnYE-My#F_H*bhTW~8(b zpU#Kk8cIt-R9t}dXZ0+s@a;k26Z}NqQLjh6!oK9pjch4#aG>J$tH3pO!lQy9H5OkIsK z!f4N{8eeh|!GHSjZ#N#qdz7HhjIrZqIMTW8o9M?{ya0HMzT$3tb)rQf@BKhleoNf_ z3;x&F;hbm*a7O>l=-Hnvv2rR1u%SPj2V7Eo?{S2v#rwFl)RS<|J^CSGgl`b#S^+I; zJ#=j}U+{wSedeG?bRZ%4ZM}Z;vvRam?`S8%X;9(ShfE(-Pf9mRSEHQ^sTv6f_fsJ_ zdeAGj_Yr5dK9h=rh1CP?Ru-<1kou`;L7L(-bof-3C|QNgN`NbbNrffm z;wyW`q@s8GG@Vs>NWr6piwa@uX5pD}Ezv39YuTvE4_(_8=&iRhvkM8XR2dWd&o6S( z5gN7~p)@X$Kg`6aK5+D=3T&pbrlGaG{X@m3AYi^HDLQ~^z0{-b1qf$VWBX=Pb)kYU zz(uDde&*YjkXOs|;kLOkGxq@^(9YGNX?soyJNzN>}Ty`57)1m&7At||o?@Z;V>hEo8+>x<&j z^Zvk(a|4D|Kn?hcy)_2F+FEoZekyW@eM7vub%6Dt>c(c#9^>I-U*`WT(6j#Lh|Qi& z8c(DU*a}Xi29^7V5bTg0siik=JlEd#jIAYTUYbgrQqX0u46xBg?Z1Dgx#wdl%#MDr zdkNzmXpo@w+cvQ7kuu0&-dlbo>?_xf1aFIZ^!q{tX9jH7x-Z|ChGEL`#=QBx#h99s zQE-68ul>dyin>g-87z$iqH(RIJwN!wdGIVLh$n}&FfIau)x)1X!Xwm7vG%7KgnMC` z2GF%^1K_^#-BTC~>%!B9Xd+wo;AJC6NdTfJ@sKZRlLMBK((UDba|(Q@Efe-m=Ir72 z$yY+F5hgKpt5_({!qnS+Kr(7=oIOh;_3()DZ>CSd*zf$qNX)^F3_v==Fy^KEoVj^_x z$Ij`)s;G3<-dB~3gaSnS7-zaV*yhDo43Nz+c0_1DH~EneTnn^n zvk^cpawZWZ>hYoVle$3(TU$Mf9%5j%X!Jjhut+T7upM{#KcBggbn`efPtk@AF=dx< zjQH}H5nJIl8{{zmm7`k?=njvvUmexN)h+oo_F8)KyR+SPp)3A=!60;IF`Zp7LfxA% zbQl&@T0YrUxWGj4+auT~Z?L@ZlYtuK+ieP%G_JP^ZE%0L5;gT2=wbf-!sxhu)%fwPnH zy`zxkRg#cEg5|#}Z!;knR`(~y%XN!#=U!L?m#uXNab=l7M^Si}Y!(nwz87McrkrYl z1TJbzx%pn#?g1acp?)_pd&=KLX2!bYuzwy^hc{}{2Fl(w6=rk&zOjH0CESg%?fOnZ zf&s{wBP4?Zc_bS56MwI4j9<4D{dyN!2l?a~OuKMhD_>ESUh-Fh!0y8;dy2I$gLS;M zO580^l|dt3Ti*VUQoY}8g(JR2f{a_8#G^k2>ER9j?OXe)dg7{hiRi);o@UhaPu~Yf zGIC7cH!4~Py~o-+CSxL!Pc+{+%B;M*BMywqIiw>2Hc-@@Bod#W$Ps z&~79MgErDv-EW)2$7Hlxm+1SRs5}8-t>?6U({oJ(I7ZC#+8<}@#uf%yo|z2>um19O z(S3PXw(~y`FxfX5eUAb@%US#f0qk9SdQ*a&h@62&$q$1?O<2Fgx`F3VK2S?DgB)_b#ZR@5e#`4dW*4OOh}_l zfq})CGM#!^$mW_VOv^K4ef31DM-UQ&64Iz&CY4b!+*7|?oB%^ZAQBpYMJAv-!U&AJ zhnlWj{PbxJx#@UPMC+4r{>8KfW-~j`)Ni3_A#&uIa84`LxXp$8D~U^3hn>{2rRf)o z11z}FhVuNlI|Eth>9H8|Z!K}w4z_!S3k?H4uPtq7&fnrKkNbbQ{!D`4)-a7egjZWo zQhW``2fkNg++TL<>!z;g9zLiDkXgu#iFd>B!?RaJbuzx^akXqQecEX5s5*Jpm5P>8 z578XUqw}`*dRPh-%`82Nz=Oez+EsfJ{2cRR&-tkWX>$a z@|kj{$pNEpO4cz(9@f1$mStB~G)k@jXnPH5v2;@UiJ@pY0JkrT4T^lOIFLNq6{bNo!+q953yRq>9cc?cs<=50 zM3*9^K=*xVOVoP?hGWJ@d4Edm_-8(hzOh244uCC(xr^9kV8S|itf2uWfibIjv z7DQJ0O%CRn0zjMl*z^^`rQ+8(14eKmbPlU??q?$N3(&6-+)SrZ7Rjrw&bt`Z-;ZJ; zBe9PN`U=gO@$fYOGE5ZuQ9iUa_9|GEJlZjpb=|Ey`hRxY)gAQbi@=m*T)w=| z6hY(_>i)4mh$#w~=P&j)IBm(KKy8(MQr@Rk4w?SRS|7j?V;IS{NQC(?@P|xple#id zQa$-FY8DlgTy0YH$QKDQu~=5UO-7^TCOQ&C?N@~@w*lt>eG-`B?OM>KcukwWHz!d*cQh%?2eP$>;g`-%|Avu8 zydD&=KX33x^Dm;+g>KdNj=DD13-KEZUs-1A_iL_R9iWt@?-iROa3K`(d@j9E*8_6+PC*+~zv88#}^E*-qUk913@rEF^Fc)`z@L zIR|KM==tA(riL!zp4y8=_m~C1#u%qYYOuDILH(dsjD#Ot`Tdk(H9wP14=MW_)%&h{ zF+5$^sSJf#xv;_h*IMf>FPG6+KIJtLLO@E~0MZ++z^ky=WRtFt>_cZ?-}|X){;geM zz4b7>RY|phj(ay+cbQymnpzV46!4F`Fqc=yoy(osV*_#LiUmqtqBHuDCek0HMNPJB zq@L~4L^eEl@7Y?lS3GU!xgjsU<GVp2`7pTOQZ0 z_nf9tjhb4`Y3Y<)Q3-K@>B;x(!&-AIwHwj>vbCd%62Yy`cxy9wfLFOlc&^N(bK|_g z2EoO{$^|ZQlFuY|LW}j7)VMLVj@~<1_*pIMXT5g_s?CmIpd@^Zv=LFxe0+NWT0?cw ziip=!hP%sqvxi3eE8VHowNIl#5d#DttP_RxQE%WkV^WSKcUVze5?b1W>|6bsEt+;3 zC$kUZ_FbS?PF>zY41PNf!YR-6JdV#IqoJ>IBQ-bE66{OXEC)x{ z2_UshxwH?|DMBrJnDo{#ppaV54J_MGKnxi)ZyPp0g5!1AC)?Cq+3k!z(jQ7A^;o28 zbTtBGR9Z8(J>pDU+crFq@~I;0T{Wa^PpYXH1%DRePW^0_>GgWqsKuR0{;TGNb{@2v zmUw9^z%aM?T@&$iT=Ia@UGT?|z{kFGh-b_tqLn1bso4d+rO3Jqs&^~>ICA+WVfcPt!6s?mGk9A z4ef(*6I*=`2Ah;anGuEzeG%4Va(>`03aHrHH9KANziYKeZ+uioGl0OBX71x^u^Q|s zD~U?iqNNZA);n*yaywQk{K8~{uWfNwMj=`?{?%HW>2{!HU-~sbV4DyuP;|1Wc`~w< zAW4b$V;AXKu!Au=TCId$Kc17GIM8}NI3U_VY!ongH?}3|iCtu0c3|HUAmCh`AqW7y zhk4((M&$Gj{v_{`>)yr>?jV5z@!+ZA!Nb2d#f#MLg&07pEY5podAowFU!%Ahyv!+I zvvH+xhzeNQtqzIS&^I@^gzJV@hNiu?oVT^^h*xE=@mFQN&>TYygI5Af@{AE%?%jG^ ztj@gsu+H~Bn!ubi?e))+E<}r&{LO&^^IZ7Z9$@@Elmtx?Sv*tKo5n)3(K5?%J1Jd~7eJz@jqTXxQ{JbGp3YKDyZ8IW5-4SnwC|?TFlFkZA|r-z-gdqScRP z-nqdB6Y#=+IYoj_eZ<$%@Jx(R`<_%aYey0xO(eQY+xl>Pkv8_)8)rntD) zj`i7sQO+(A4_EPtNA3{^(sZJpJ=5a>0>~>aBSaZy_k&GO{y)$*8q6JNl8}$USUtZA zjt(yY1oD7sh_RLGK4)n%fePSZLU3ip#&En_|CwY>AMIVuZ#J3NF%YZTh0_V^;Y3|= z335H+qI9NzKicbT30$(6!o?`{A@_-vm-_wujD>_TBNZy%c!{?ymYWniu;V}sN$g>1iW!kocG9Y#eASDNvskg4@!gtd7VPP1~ zQ7U$7ZGf`R&b5h--nw@4eoMcf6}bN}l*ONgFWQ%EtCHg>l2?`L{5WI+-+mX^dq6eq zhQI|1cU6~7x3fj`>uR-*&H6sN^Ra%~UdH`L{_03kjdL+Bda>`WR-%o)PUHUHK7P7k znj*n8wSP>lQu{;-MZI%b1nQG7UCcvt4SFz>hp=W?!SvK{6Aa9q<5z?FgN0G(7Hs`? zwPrVY;KxILod4wd{G=-3;Wsd)NkcG7-B4Enx5F3wb#zltB@5R|kQ~$Ke519`%{`LK zN`Umct??jX*cPjO`13MX<|=>%ZHlbp$ayUI4u0kOnArucgU$?2kWo7Eqp2E_i4bP0 z_x>aD-6Fwc%*BIlZum3TJ!jzSj>`4<=#AZG%Q<)PRk!KlP?fG@!Igm68+^NR8p6#e z%VOU@KuHG|`EZ&hF+VWHdOAh6pf@1fFNUbNRB79F)cAD)*C_Om9au3@ ziI_||&6d4WI@`wmp<9Am$55NSBE(Y@&Z#;!ZQk?%VvgXYgh^;seVDR<`>%Oa*KAVx z9L*ll`sT}qWL}FkxR@{kgt<6kQoYB&teZV;@?;!{ne|~xGd83(mYmvuo@El|_LFJs zen7u~-Esl!?1tw_sL%5Uc&k3DG2atkx}}DE%*j_U@Cl@fc#kAtKhcLTeOy=W`emDz`%jJN;x6Mx1K5ri z`Q0e0n2FS&VrZ#%p9=uOr81z=%(0A0X5Cl+I(Z#i*O4tBSARsNa=YA^8Yy+Su;><} zBK-tFsY~=Vyo0ctM-LN25{%8!KY=JS8?eT?susHi>l#|SJ|(XPvriGFbO?TP)fVAd zZ)L+UE*D<#<&Nd>b)way$1nj^WN11Ye1n_AUwMPw1p$7Q$Ce7uQ&%uD99xU(??zF` zgOnE~ZtKy2V-e*K-vRUFwi>KsDs>CkYSzP+Xh=r|+c|yL2=WVE0M$JvTFus7dApfr zknf)W5^&bmao?!&o6M*1mD~q$t8xmQSf{Wo z2|&Mw``Wh`QN}w#w+{2?7L^RxI$SkjATB*4q`+kK))PfpOIj#{9V_X+m2-ihIOI{r zmgRHBxRc#7#s+q)mT-5JHXN^V?yuFd1@@`A5aK2kWB_qPhYW}lent0aCjeks4qmFt&-ebT5KCRJLtLN8lpmwX>p6g5prv*B*g)Zv{kNolbQhRFf^5Zk~ENylP;1k>e}RPVR)3$+e7S`%eKV* ze-m!Qw_*1(_h=A1Zep0diNm82q<6b#0OP#VfEp){oe6m&^Cdy+qk3hYa|$JZN*&3x zJ@-57Z_RlbhRc#|t@Yac1mzQyFDeBW)AreLNc!rY?Q7It{ia)7kC(%|cYjmy{_bPK z&sw(rtj%iMVk3=M|D4V5vV|cH+Cn@(zCV5Sz9b`sCY)8o)4LJHLQHVs(5H_J^teEc% zV$3=Z(&xq#ZQ#LmV`Py1YSdifFXCo~?*R?AyEdEbC-hh!x;@Vj+pu9Me%x365xS($ zlj>TJybg(rjUOX_jSgyOd}5P{wAD2n#ks}KQ5504%MI4jun053qKJ7%>d2%K%UNABKA6CM&)nEdg7sLg z<#u>i@3X#u!3|Q3-B?c;1?y*}rbcistfo`H_veNXcd<6`BemQ|xzRaOWQOu2ifPkJ~`jw1AEc8)siY*2h&UN>+9C$hg zlY6iH=l7D=silh7e2bPNHd1sB$Di(J<9c21+g_^z9|r)=M(%rq%-{>OEOd|q3$Ljl zuzDS@%`3B#TzgSbP7&E`3>h3#bk zW}baY$^MBWfi4dJp{F&olf++aSFn7jgd>3z4ypq)Do>;8Xw8xOd$=fIW_f>G2LDC2 zR36b}JDA?gRq`$e!NNagYSoK;;=1_1F@iOcNqmagmez^tjN;%Wh0$w9_qQCLd}xZE7u1)pA}Lual%9pDr1YbKEma$qL#%kQ(j3z(&L+!a z>qS+LQ@O=Vty*6Hh6?DX*7|W$kA!jcLH!DOIGb6sNRr6d#K`dbg`I%F_Y$b!g4xV8 z|6Yo`dja+(Yxq^pj=4ysdfuDB*xm0hJ}Q2SN+BpC1{bVg7ebr7G=&Q!Ffjc|NZb}EQ!VDiDNfaB32ABcLjk=68_9KRf+aH9C=TbD!z z7RJ1J;YEkx_d6{m3c(fDi1EB5DCV@Le?WqK@pEjS7veunOqXTjnBSeb(WBuL5$nMW z8dmo|e>+*~4WXCt|yjLNK)MJ)cHyw34U#gss~g>EEIiZdRUkA&Bgi zk3(g#W#Ixf8omRItR4UG*LjMtfo)EG;44x1%kTtGrjPu~SN)>1W*550^0yVKzhV~= zDB07dD8k(y$E&>itL+aKfA{JmK259J@rMz7l@vCh4`l#E8#Py=TS+htd>Bo!h?r$-vS_^NkvtS4w5q zW;MuSy3KwKT2%C7^BWjR-njP0tTBAW74-<9Yq}x*0nFN)p0yL83GV^WZdzXui&)#6 zwQlT&dad$eq2(jB;I2T;94M)b3`x1Pimx*4c%G#5RrLbc#O!k9o9P2{lxdkI2sst- zj;ZF7;C}~qeC(~Rt<@ywfI=21h5St2?Y1KngbPEFGndJoe+VS@nL#1u9Hii;=Q5w=_-vdN+hUh-CvAC`b&+VX~p;=@OW01+xAQ z_ph5vR7cGf*GFFS{@~9k{X>oMoW>|%l$AYih%EGaB-o;CT*e8m!zu#z-+_&=EF(JrQ`)%Rtjtr+JzLN;{M>D;slZOjfPAl6Wky(IU;;Eg9 z$b2hQKfgDUVqc!s-uawzUcUG?>wt>9$_nK0i43h(%vY-^%OHFn)*lSst2GMS8g+JzvDq)E zXe0rrFWR?~fF(Axpk>PPtTG24H)o078y>E!hUEx*Xz<0Iot3SU%fgt1xgoa0xEtYB zdNN<1$5CM3pUlI>Y~`W*1Sn&P-6PbgBPh&)D%7_zko-gmy+Bo}qR#$89vmN?CN4 zyhfaDQNGck39sU4#`8!k?hirBKSVlPwiW^wXJ7Q;i*-SU3^oZ~29p(1Kn_|7i&Y~2 zG-nyd&ys&XLV-7%#KtTTUXJPk6L72|wzm|Cy&(s=%9hfP~1`Hyne zBb42+1fQdH47lV!t;_F$f^OU9Md&CH@sgd7X64k^6M8CiV~YFjP_%5z@zkTJt_`Z~ z)KSU3w-`{RMYn7W9&~Z|>{KT(Uve&2TERSWY_v_mgM?OR$xN2Z!BV>Os}Ow_fI$FC zC@%V4s{6jZTj-FAt*AC3+j#3@i#Zcd>jf&=b1zv-^n%!oZZyDf{}o6yrwL|)Xhlbp z4yKta1B+$<_XE%bE17p?uYIhPOSo%z@$5jYxSuey_rCm9v`ApDRAbY+A>QagTzEmU zU~~;Q>O*QW^kl-PeZCV3IMnJDD+%zVGFC5##*Ys!VOIlVg&^o>_W?E-YL|vrU%Y|5 z2e@M{l}{<=l?GqNSmunzLhWiiG8{`cLe>p3dlep8L#sJ8t}0AFrYf z7msozN(UnC_O|;Jl}OjQEz06!H*u!Ir1-IkB64dmgRqV7k4WE^^UvVW(?Y4s`t5Qn z)9IY>Z~`zAhi|;u>THtksQymGcClOPCig<@ZN6ydqpv!ex~IfJ2P)4^q0@3j58qK(V!4B)AUd{8T`!cW(6qyi`v6C^rZQ0<5QGGYAevaTF znh~!^%lw?4^qJ{r@D~>yAt4HAhL+9rPtr$ay5W~h9`D#^IXg2qSIhwWOY+j*UtCu7 z?pOzw zOGkGn!pMDAL{{iLaF$H8TAYP^(AxERb(J<2+V`F|RKrSQ?zn^}*DPfTRd?gWQ2W2X?y7onvHW}f~(eqXaSO-RcOP3-}KlF>Jg@I-VU#*LwHJbZTF`$b1Xe@ z>5i$vUVxn*BCs!FI`E6#{LB{o&WxbKMsqCca`QaRhn2z}wqvN^d#|kC(WjrY&?&CYnw(OJ$e1tU4>xoWF%_@<+g!Zdff1aS2SwArZTo3Z8e zsA_k-rb@sfdw_jt)<0~A3CdTl(N8rS#1UK8;V~VZ#^h$}h)tbhQcrTml}7b|;kz+X z^EHKssGoCUwY73@Pq|374@Y-u(rfD&Bk!EdFTS5em)71ZBNB+M;hWs|0xuA*3yaPs z&nAN}%yCus%54H8sr6@U>WLN`p&=M6cO6=rp`m1H7;NlFur7myk=~fIK0aD}(Duck zALF;n4hIcuLj$E4+DKZe)6xq%&g3(i`{$MLMrl8H$W6uGAxc0S73{(0So|bPeK6a# z@gFT1!{4=fI)x3)oE#RzD~MhJVL)El?0>$i|)n{+P%*Ey-?Y< z?XCX;y|A&vvS0-97MWw<@s_L$-9J2!@0d7dygmH+y}gWNA+O$@)`)iffe#kQ^U!t- z&)E6nz!LFK$B>iP9XS2?ezNWk?EG8m1$@{&$5=Xj7KJ!VwA(Zbb-~k*l<2%uo%ai z-}wvImJMo}nzU+v%dE|Ns3%Pc!+4@3D1p~GTbuuC4x7ptpe==5_fp?I?oi72dWs@dv ztdRRPxai8cobZb|q4=Z|Oq0&JXQZovx#kQ%k1y4tF%o$lT4o?my*^vuL*0>5Lt)AoaSe+nV;+}2M3EMx%R z7V2!76`VV2qsI07=c-7N%0mIe6F)lTmvomtUbf4+h`Et+(b5V79XuN2a`UZnQUjCr zh9`ou^!}39gF1x6UUBtczC&gSvt#HV$ZRc#j-){Dy{^U2B~bd+5a-Ayg_t(SxqoO> zV4FRcn23w#?n+d29_yRi0sXQ2fq}U@uiGC>7tIJ%gpT;6NoXBl3SSmy^Fey7+@ZH# zmJ^m;Ox>Id1+LOcuyX(vSKX9xSD{BY>60)uQ?9}QWx6X_cR2aJz9h!?6f*c;kpa5C zA)(0<#CCp%ZmABdmmX>{knh2W_!gadhKs5552m=&?7#iUnCS`c(nv+NBXRshY*pP{ zk=$>qVe*nv2dWYE`y(a`Wl0?ny>XgQc(GzbyA%uRypFcIzA#>)lWkC;eo1NZ`dNz* zYM(Eg`hZf}vIe^S*ub4z+@iTBwRe+LVQu@BepEmAVaYf$N@)#p=nl1p7}sz9)L7W! zj;-2`lh{`W#(~NC_x_Go_#jWDPn#y4Ou<>;5aT`UGam`UfV3(p`J+sk<*u8?S_u1Th>OCkg$FO55)P;X zZor}9@rJj;;V_{?VoWEM>iu}}c3$;_q;YR{WjzoIk^rSa4yZY`F_ z6jVsa(KBD=_U=GfAwoY_6#fEl2!Hxvh8vekv5f2SdsbCE`<=D&XRRl~e-8{(ZQ;XZ zKC)D4@rN<9`y`B0b?UT5^vnxlA=@+i()91=1zk$$BpU9H3X0R@0-oKzXI94t@q`Z~ zlP3xDk5e%v6`x!N@q*OuE(>yBJ#~}_hzSIv&vzc80aj{6jJ?ny|DC_6;?Zt>!^jtk zk|V1PT2rg~K~2Z2o6~r=X5M7*d9wSR?$*P3)FMNVz_H_~o-ZSpBu%4`?|i$5zOR?_ z>1OK{tjEtw4Zm$8q#vtH=Pw5`pUs`3k)^)Pz51x9u4*N)J8iNv-j--l&>*3_0&fI1zBDw||8V zEgPB^<{oLQv%k$9*{NvTABOa_eR3-Um_DGOw(PY1@K-e~Hm%ds{Nh$ovb(;!lUK6DdMQ8Rbt)`Rv1RuYlxHtVigRAbV`&rAY*p zDjL9Bg|Q67^B*f1<-HrvhNb1tZl;Gv?~%n6K`OG;moJF^#+8(^D(*q}=hlisF_kE!Dq>#^~jix)ev0;^ss7i2BRRS0Dyu z3wbf+FB_fv9|O9bRJ^ph0i{cJ#snO8Z@4!38>Q>?`>70={A2=_-!eM&m-yZqPhiOK zO~P_tnsh{}sV!nkyGiztwEEjvX~U!WHm)XH@6PC50|~*)H{L|t#jS0(#_|*{hr+Gm zURtz%NG;XoqrRPSA|;g=Fn2(#-&%C(y}#!+Zs*g{0!X(|ylNlHvWjWVd{4?U+?y{3 z^#uP!GUSyM8$GKh)^<#iaNH`5>!F&S7-|SC?yYq+)FAP4URrIPQn56NzFHJiVhpWy zKv2^>xi>_6Ru>eiV~3zFOm*>FlTWn!k$rN?z66TW{Ph|9Cn&e~8x6!q{c(B#2qIaDF}$CbiQjG(+%LDKb7?`q}u~z+;u?mN1M-vGdG<_7W#4^vR4O zxQ#D&1u=n9L)+EIYlYQ!(@SONx$QilVuq3ou!;q!-aKh_%oFOxX}JISn9ME=LvCg# z+BSckKJQ@ulfDDF&m(;T0(pls>HfvuCD(o0gV1(yihA*wmrgz~*54X${%9W>+-D9Y zP=LOjminsHQIw9N#S*~`#8NBTijl9aaD64M##hDe@Eg?cPAY#jer*k%HC{Pu=Ar2hLcSM2m|IHLw; zIeu4Lk-0u|E91?{p04-+`!?M{!r?c42b{S@QX}gZi2AmMJ%53nmVkBxsm*^pt}yI{ zjBLpqhx#Ub7Eo8C(8T2ZGfUc9dlNhpZqA5;Tz_;cH#Ooq8ZZ`BHqVMTzM`Zaw#(d$ zK6C#M)l!NSEutGm&D6EH!15+vtSjB!oDB3pA<@sD_7o!p z-*sW5Ypmz0*eJaRT-i9tlKoy~YU%faSbh|(5j9-IU$zZ+PG?XN!ug-pJ-6B;RlBPg zwkw}A_ir7S+OVL~8#Vou0Dh4{9qS}dQQAL*TVhLiXsdiQ3P~_6I4E(j+dFV5vcx?G ztnH!JEZOTt8w2q{R?IpfD(``m$ZYWD6jzG4M`KD;CD#7n3q3Indl&M)UUB+w;k25A zR8&e8%JuGi8z4?JWK!7-dS9vxOeO8K;BAIG;$z`!)EF$6mHyywZ@+3b436%m<2Vl6 z$}pFymWU~H<1=#$|FKlTYM=C+mFSa(Y`6o!aignS&+nSHyc~C;QFZEDNK9^FC-# z$nhE^XrtP`bomQ7IBs#q24c{G7xY*8@+5)*AonV(z`({aZEr=8Wf}hcKd? zd@qkXdmFLcrMPoTK+cL$nxd~0Jn7hNf@x$V`9)X9rx%B`*-(F3M07T|DKF4DuRcFL zGuL|nO&=Sz4s&)N8?cC~p!S5yPOPuAOX3;|FnB)0j_Uc#xID-zKH~NKB_@uYs5-$! zGitvct4izBs8TLC4lT6yri85#L+72)b1yBOWS0cU1h;fqyBNWxHp3VGUBsrb9;Lx2 z6E1CSxZ=l*Nk<7|c(WO6mw{GuSJN+8A!=C(^}8>+MXnW(la_QT^8T4S+J%IXGTO3s z)OEfB!YFxbDg)c;u>wDbnn?4ZU0J=Z_3VVM20MT)_-r+2Kj|{y>o8~~?G%)7ZH!+# zi>Po1ZrrnX^fAvqQqq$r)~R+ev<+-U+o3C#?9wf~;j^HTl%)A`2RkvM-=X^{M_{#g zhC_Drn=Qj(Ya1bZBfeqART8l>ikmbNwYt_!J$L-l1cXiCg_KZec$D=88 ze^2}iw_QKtLbzPcw`s>vc?^s)i_-j=>CHX7$j@heTQ5aiKJ?>KrRcOLO0t49GW88f zu%W7b^wqZC=U^{sp|4|HdO;-qFT$FQ*CU^ZTX2u|^q*-zhem+AJmDah?cNDPzAWx% z(BKbMsU*!f_0;uG4>^u^UtH(Nc{EDD-O4}>K(Yh%%1FVzoDXWnL(3=LN<^Bn5ut_C zFU*%6I*61mK6mXSFgNT|@%GVqJhh}w53td6;KA@4xIAa2*@!+(AyJHv@C8WI^hu@Y8d!Y;cDP(?G<~1bJ3wnxcBgPn_fFdH}@*GF8NDclX z4BRP}`VLVZ!p{v*#VXs9xbn8p4+IKUSrtg-&D<`PSw!(SP6pE`at>c0ld88#-*683i-%qDy374o{zosb@n zva&<)g7lulHFiiWBAS;_CF-E3h2LAsbz;r=-0Vt2deF5bY+8Q|K8x%%(VFFLu`lqy zbO`Y>{li*TX-4{&$|UlxUJIqe<9Z;`Pv+idB|q-oQfT`rCWZ6*uf+L(sIwogxI}r$ z!m^BcdEkq>VKiVkySuK-DMHdXs@ot%ID{ykM3?N0FFeDewPnX5o{EF7m31s z=lwRCj=P%00mswpwCBw(l7F`+n~pec9Z)87K@Igyp!FjB$6+}h9XI?8?ih;JIznjK zty{IKB=KvNN%FWWh86PGSBwH$e9YB0qe=bS$(@$gEQQpR@2V>)!#${hQ*`hND%D8> zNqw4svzFAjtdG6yZC{wE$`h1uJ$T~(z-Ga`$tAR^eEWW>kWQWV0Olho4%p3*N9z5h ztiyn7u)EJ_N>>+H88SM;A2Q|*)< znz935ciu4vqedf-A;Hcy$6S12_#hpOXZ0ufoxCDee>d9d9M^XTwC>b)Uv4;9*9NeI z&Z|?iP<>{Y3xGxO+6hEl0kxG0yXQ+OQNpxAww$I#88d|0O64EaQiYWFrNPzR{RPFJ z%(&Z!h~a{wEL|!`$-GBnN80gHjCC2xCDFFTl*Pkw){U|C*I1|T$XJ_?U;gh4ZrUF0 z{PBwbTOKUc8g*P4->#1G4mlQJ5IPb^5dT)mMT6R{R;7UXBzoso(e@v)>B7Hs&j~{^ zym)(4{et@=aZ~Bb=V8xgB*yEit^w7($h60{aIhR76*HVp_Z4dX0rblN-WAt>Zr&Zp zdoZ8I3R=b}B#Fa8YDUQVzsS@6?t^l@T_EV>qfnCk08LGV-}lJfno8QC!UENS6k*6V z-C|yR64w*tq`f#Ku|*~Dc-`Bn`z=ZYWl2Ur3u4#@p^}lCKt!# z;zoEOTXI*nT$ly|(#$#{??OYuIHjmZl5?~Rq{I6SBMkAagZZQq|GHh=?JP@8|rh2 zpei+RpvulLn2Vk~Y=W6xBbQl&DXjV9a$T3*1TmQVdM3y=g{v=m>^Jp$LDnP2et5Q{ z;RQ(Sf4CGP!_$@1!5i-ld~(L}b(YuAaM6t4Ul|+YRa7%_+7FS~vkQaheg6BS;;S<; zoWz~YT2pk?aK{@RYL(7PmYYD+Rrj0hqdYDzIeQHU9&{Cs-Gy)QUgNDr?90!%Pba@X zIg86Itrh&B8YPCxdohKt8^tWZtnO9bPzC9CV$ z?EhR z@8L=?@hPMCiN*6;L;$7bALZ@rciA`v<+2-{MwrIz7AKZ!oE)Q#fs3oU9}7GN*d|JH zrcs)#VsK*tcBd3;tUiPTG&bYNF(k{kQEGp6#IVvL6rLrgXlVaK-1tWkdXZ?E&9yz>}e}XeuPCh_5mU zw_AiO@85SUX#PUoJcg_xW_xCqcTb0;;<0U0UhHBV?3-9oE#)9;8cCt*^5z3@?DxS3 zIOdENMomFV9DoAyOk_s7K%GO@ph`LQ;YD3)U~XuJe#Yqc8y3{IBJ`b7-=fKtv7mad zhB;KpV&6UMW5pYl`?_sTIJNq5;~x-e`KV#!ToQL4b_Yh<&d{Vi0OM02anA89ajpN~ z{*3TT07_gpxQ-Zq%ZT?|&8U(vJm60TG+;VWq5ikSV>yTBq|OP&VYv4owyHpcwnM+U z9K|^6+9}|9V+-Ih9f_k=N+3xjQE%&OdisqUehOkNm^<2FfUyuoC8r>J;v#CqSDaPmoV9bmg8B;#?w&C zKY8AR7S;85_L(M6t9k03?6UPzqM)0AFkhEh%1g2|5hynFskL() z!zJN$Vs6R|Ll>p@&hIxAb#k+? zo@CvM>@~rDtVe71gUWG%Z|P_0f#8MRZaSo9m=?;0nAaxB!qqlr_+NWI{xZPWBo@?{ z;KegwMv=xzOu#R})Ao_;1{BFq>4~gV7;6k*e&{k8#rg+YHrx6bZknSos??UnQ{hdNtrSYVQyz3%Vot zs_|g2&yk1T-TxI5fX35)Jhbs`F#@A*sHc|_|8I=}Dq#STzmj?P9|2ap?*B2soc#ZI zp&I-f52R7pUG4G}9PMhQ0XG|F3fE`-?%~h!z#`h*aJ6c~IZ5QRnA$FIJH!45-t!$^W_)VEiI_AT;_9 zq4&-sk%p>5ozk-haDsYxFcrP0b~r^BdDSV`Qt$(Y*QrrJ)wxmvaZgbR`|qnfi{x7q z`H2(5XKzqL0f%-D_Po_qjfUKfO7>-&c20s{QnnQDrnFgqDX=DR72qVH8nv*2H_#-H zm+(j+7z9t2(}t~TX6(omWK|818tugjo}< zFt>({*9-k?s1iiNd(qqAB8h+Z{|Q~Uzez{|#@3ZG#6pu0Dhz;_UfZi!!E}_Z#se+wp znflP71K>Xqe&u6Hab7jOL$j2yC?6L*XX23cG_iG8nF&-l#tvkjBT{krp{J;gQ^Bh` ztjoO)iEYY;0+d-17?tJ=n>S00BAc5K&?=(WCT}P&@V_9zb0STDRamahrh>t7;NK!r zfec4-z;c($fENH`>(Lyy7L@()gu=^ZKu3QQ?#b);ttsm`IV$E8rc8o398 z25fGv;sq)YDH{>IW+RFLANc481TZVj@psI;T!B?9((0W65#o?AC8jA-5cEcB{Hoqh z{i-_(B?JkP#Vt}iCmBPY6t%p5_K~z756VH5GtqmBl34M1ec?4Fabu#cyX@{bR80r zw@wUW1rnqCGS!V8ll@IHZ$l$bBf&tiio(e5dJnc&hMEs?+JAOP+eLMa_Tx)zKF>5KI@vr7|FM+ceYl4bArTE7crlJ>prB9s`5fqG?)QPxKle*5tg*z z+vF+syD3YJ?uj}L&PLexd*Y)oP9DbWQat8g`dFJcdBNZ;>qd!Q65E6(XCUC2VS7l3 zY20U&aDN_wB3BY!2i|j8wu{)kZW)fep)=(?N9bV_fn8b>q8bcG34+1jC}H*v72TZq zod%w0FH<_+k@`y8=ws8=9L; zjgQ}q89JKNck|7!oSS-o%UK@`)cmt;YzFtif+wkJ{y<@+@z(%?_PMIhC^iM<4Ff*B z(XZf~)bzn$ghzs@s!xu%Xzd~95FD8+=&+MNMo!5VC9)_9Sk+~M*h8p8@(hY^RWx0j z69?Hc&noIA4hqOB$s6cHFsk>?Hx?FBs)Mx$g)KaxhE${Tx<-pMq}9fr^X?**3C`&m z{j6I0qSSrZT3Om6FRGTDNl~3xf&u)m%35L-$-je0RrhmzqrTX72GpMkkc^^}pC?(s zk+iMvbK`N}m@j+|vR#YvF$}k!V748kI>(p2`u8(x%^RxsTVaa-4TmNktQkr05U0qP z8x~)FT^>9MqR~ix57DxdPtY)^vAfR1qWO8T>P+4`-a#d{XZr z&|S;=J-s{a-Zov1o{?S82TF|Q3)z=y9xOn_0;FY0w=W+6Wn#0o%@qIZdg(~5!|QPJ zVf3q2x<-==dH+HLOP&$?(oFt3!d~C8pHuBYTtrZzZ#+N*|IjoQ@)>KK@K-8x%hY$N za7A8s4`dqUw5VP(o*u7paTKoyjag#hNO0^PB6j&D1&FG8NgMY+`81bX(y5yiuOmpU zP{TIyZ0PW8PVR5XjzaoHU<@;xrJ0OM1)pyVOfFts9$u7HqlJr9oVzq#g=&|gVTu`H47+iYz+nZr{<3?tL~ z5+UMZs}!uy)dJ4TWRz;?J5{8-B977dBpeFkSVvba-kR&?&V}(h9AG%w9m&aVd=O)a z#&Z%Tfjc8eim1#?-+tInIxGyFkQ`P0X)Y1XnXZL}K2`Ffr_+`b=O-cHP~{NY`t;3N znVF`uaszO}mN42by`=A_M(Tph{D8R?N(@%@PSBCWR^{q)!V9# zN=}jF?utKIj_`Pi>gp$eOoz?jL|%=%=VK%$t8w-qWj_hj{nV|GWZTS*$*U1^)sDiU z7`@(^5~8=+x)UjnEd{@Vz0BYXJUy7dFZnX{GxYVjI?StB#k^(YXk0i!Q6FVEp{f+k zFzi_5 zd!N*}<`TJ?N9{$ Date: Sat, 12 Oct 2019 01:55:50 +0200 Subject: [PATCH 5/9] Restart on connection loss. --- libcopter-arduino/include/sg500.hpp | 2 +- libcopter-arduino/src/main.cpp | 6 +++++- libcopter-arduino/src/sg500.cpp | 15 ++++++++++++--- 3 files changed, 18 insertions(+), 5 deletions(-) diff --git a/libcopter-arduino/include/sg500.hpp b/libcopter-arduino/include/sg500.hpp index 36bb3bc..6c359a9 100644 --- a/libcopter-arduino/include/sg500.hpp +++ b/libcopter-arduino/include/sg500.hpp @@ -15,7 +15,7 @@ class SG500 void init(); - void command(float roll, float pitch, float yaw, float height, bool launch = false, bool panic = false, bool land = false, bool recalibrate = false); + bool command(float roll, float pitch, float yaw, float height, bool launch = false, bool panic = false, bool land = false, bool recalibrate = false); protected: void makeCommand(byte *command, byte height, byte yaw, byte pitch, byte roll, bool launch, bool panic, bool land, bool recalibrate, bool auto_altitude = true, diff --git a/libcopter-arduino/src/main.cpp b/libcopter-arduino/src/main.cpp index 1ad9d9f..c7a9cb9 100644 --- a/libcopter-arduino/src/main.cpp +++ b/libcopter-arduino/src/main.cpp @@ -70,7 +70,11 @@ void loop() { Serial.print("Calibrate: ");Serial.print(calibrate); Serial.println(); - copter.command(roll, pitch, yaw, throttle, takeoff, panic, land, calibrate); + if(!copter.command(roll, pitch, yaw, throttle, takeoff, panic, land, calibrate)) + { + Serial.println("Send error, restart."); + ESP.restart(); + } delay(20); } diff --git a/libcopter-arduino/src/sg500.cpp b/libcopter-arduino/src/sg500.cpp index 2726c05..7babe45 100644 --- a/libcopter-arduino/src/sg500.cpp +++ b/libcopter-arduino/src/sg500.cpp @@ -43,7 +43,7 @@ void SG500::init() while(!request(buffer, 1)); } -void SG500::command(float roll, float pitch, float yaw, float height, bool launch, bool panic, bool land, bool recalibrate) +bool SG500::command(float roll, float pitch, float yaw, float height, bool launch, bool panic, bool land, bool recalibrate) { byte buffer[11]; @@ -61,9 +61,18 @@ void SG500::command(float roll, float pitch, float yaw, float height, bool launc launch, panic, land, recalibrate ); - udp.beginPacket(udpAddress, udpPort); + if(!udp.beginPacket(udpAddress, udpPort)) + { + return false; + } udp.write(buffer, sizeof(buffer)); - udp.endPacket(); + + if(!udp.endPacket()) + { + return false; + } + + return true; } void SG500::makeCommand(byte *command, byte height, byte yaw, byte pitch, byte roll, bool launch, bool panic, bool land, bool recalibrate, bool auto_altitude, From c09563710260eb7fd7ce288a7cab6eb4c7f4a984 Mon Sep 17 00:00:00 2001 From: cody Date: Sat, 12 Oct 2019 23:52:09 +0200 Subject: [PATCH 6/9] Improve connection lights. --- libcopter-arduino/README.md | 16 ++++---- libcopter-arduino/include/sg500.hpp | 4 +- libcopter-arduino/src/main.cpp | 63 ++++++++++++++++++++--------- libcopter-arduino/src/sg500.cpp | 23 ++++++++--- 4 files changed, 72 insertions(+), 34 deletions(-) diff --git a/libcopter-arduino/README.md b/libcopter-arduino/README.md index 1f0877b..ccc928f 100644 --- a/libcopter-arduino/README.md +++ b/libcopter-arduino/README.md @@ -10,13 +10,13 @@ | GPIO35 | ADC1_CH7 | Roll | | GPIO32 | ADC1_CH4 | NC | | GPIO33 | ADC1_CH5 | NC | -| GPIO25 | Digital Input, Int. Pull-Up | Takeoff | -| GPIO26 | Digital Input, Int. Pull-Up | Land | -| GPIO27 | Digital Input, Int. Pull-Up | Panic | -| GPIO14 | Digital Input, Int. Pull-Up | Calibrate | -| GPIO23 | Digital Output, Active Low | Connect | -| GPIO19 | Digital Output, Active Low | NC | -| GPIO18 | Digital Output, Active Low | NC | -| GPIO5 | Digital Output, Active Low | NC | +| GPIO25 | Digital Input, Int. Pull-Down, Active Low | Takeoff | +| GPIO26 | Digital Input, Int. Pull-Down, Active Low | Land | +| GPIO27 | Digital Input, Int. Pull-Down, Active Low | Panic | +| GPIO14 | Digital Input, Int. Pull-Down, Active Low | Calibrate | +| GPIO23 | Digital Output, Active Low | Connection Idicator | +| GPIO19 | Digital Output, Active Low | Connection Idicator | +| GPIO18 | Digital Output, Active Low | Connection Idicator | +| GPIO5 | Digital Output, Active Low | Connection Idicator | ![](images/ESP32-DOIT-DEVKIT-V1-Board-Pinout-30-GPIOs.webp) diff --git a/libcopter-arduino/include/sg500.hpp b/libcopter-arduino/include/sg500.hpp index 6c359a9..3b4f8f9 100644 --- a/libcopter-arduino/include/sg500.hpp +++ b/libcopter-arduino/include/sg500.hpp @@ -13,11 +13,13 @@ class SG500 public: SG500(); - void init(); + void beginInit(); + bool initReady(); bool command(float roll, float pitch, float yaw, float height, bool launch = false, bool panic = false, bool land = false, bool recalibrate = false); protected: + void init(); void makeCommand(byte *command, byte height, byte yaw, byte pitch, byte roll, bool launch, bool panic, bool land, bool recalibrate, bool auto_altitude = true, byte yaw_trim = 0x10, byte pitch_trim = 0x10, byte roll_trim = 0x10, bool compass = false, byte percent_raw = 0); diff --git a/libcopter-arduino/src/main.cpp b/libcopter-arduino/src/main.cpp index c7a9cb9..460ecd3 100644 --- a/libcopter-arduino/src/main.cpp +++ b/libcopter-arduino/src/main.cpp @@ -21,30 +21,14 @@ int calibrate; SG500 copter; +//#define DONT_CONNECT + float convertAnalog(uint16_t value) { return ((((float)value) / 4096) - 0.5f) * 2.0f * 0.8f; } -void setup() { - pinMode(25, INPUT_PULLUP); - pinMode(26, INPUT_PULLUP); - pinMode(27, INPUT_PULLUP); - pinMode(14, INPUT_PULLUP); - pinMode(23, OUTPUT); - pinMode(19, OUTPUT); - pinMode(18, OUTPUT); - pinMode(5, OUTPUT); - digitalWrite(23, 1); - digitalWrite(19, 1); - digitalWrite(18, 1); - digitalWrite(5, 1); - Serial.begin(115200); - copter.init(); - digitalWrite(23, 0); -} - -void loop() { +void input() { throttle_raw = analogRead(36); pitch_raw = analogRead(39); yaw_raw = analogRead(34); @@ -69,12 +53,53 @@ void loop() { Serial.print("Panic: ");Serial.print(panic);Serial.print(", "); Serial.print("Calibrate: ");Serial.print(calibrate); Serial.println(); +} + +void led(byte leds) { + digitalWrite(23, (leds & 1) == 0); + digitalWrite(19, (leds & 2) == 0); + digitalWrite(18, (leds & 4) == 0); + digitalWrite(5, (leds & 8) == 0); +} + +byte led_blink = 1; +void setup() { + pinMode(25, INPUT_PULLDOWN); + pinMode(26, INPUT_PULLDOWN); + pinMode(27, INPUT_PULLDOWN); + pinMode(14, INPUT_PULLDOWN); + pinMode(23, OUTPUT); + pinMode(19, OUTPUT); + pinMode(18, OUTPUT); + pinMode(5, OUTPUT); + led(0); + Serial.begin(115200); + +#ifndef DONT_CONNECT + copter.beginInit(); + while(!copter.initReady()) + { + led(led_blink); + delay(500); + led_blink <<= 1; + if(led_blink > 8) + led_blink = 1; + Serial.print("."); + } +#endif + led(0xff); +} + +void loop() { + input(); +#ifndef DONT_CONNECT if(!copter.command(roll, pitch, yaw, throttle, takeoff, panic, land, calibrate)) { Serial.println("Send error, restart."); ESP.restart(); } +#endif delay(20); } diff --git a/libcopter-arduino/src/sg500.cpp b/libcopter-arduino/src/sg500.cpp index 7babe45..af417f6 100644 --- a/libcopter-arduino/src/sg500.cpp +++ b/libcopter-arduino/src/sg500.cpp @@ -5,16 +5,27 @@ SG500::SG500() } -void SG500::init() -{ - byte buffer[1]; +void SG500::beginInit() +{ WiFi.begin(ssid, pwd); +} - while (WiFi.status() != WL_CONNECTED) { - delay(500); - Serial.print("."); +bool SG500::initReady() +{ + if (WiFi.status() != WL_CONNECTED) { + return false; } + else + { + init(); + return true; + } +} + +void SG500::init() +{ + byte buffer[1]; Serial.println(""); Serial.print("Connected to "); From 254b588d6df69012efc9c7a44011f42d7285ec98 Mon Sep 17 00:00:00 2001 From: cody82 Date: Tue, 5 Nov 2019 23:42:57 +0100 Subject: [PATCH 7/9] Fix table. --- libcopter-arduino/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libcopter-arduino/README.md b/libcopter-arduino/README.md index ccc928f..e1f2e2e 100644 --- a/libcopter-arduino/README.md +++ b/libcopter-arduino/README.md @@ -3,7 +3,7 @@ # Connections | ESP32 Pin | Function | Input | -|---|---|---|---|---| +|---|---|---| | GPIO36 | ADC1_CH0 | Throttle | | GPIO39 | ADC1_CH3 | Pitch | | GPIO34 | ADC1_CH6 | Yaw | From a3b5dd940551a23fd8b24acde35f48b13ec5e1ae Mon Sep 17 00:00:00 2001 From: cody82 Date: Sat, 9 Nov 2019 15:39:54 +0100 Subject: [PATCH 8/9] Fix typo. --- libcopter-arduino/README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/libcopter-arduino/README.md b/libcopter-arduino/README.md index e1f2e2e..2d9dbe0 100644 --- a/libcopter-arduino/README.md +++ b/libcopter-arduino/README.md @@ -14,9 +14,9 @@ | GPIO26 | Digital Input, Int. Pull-Down, Active Low | Land | | GPIO27 | Digital Input, Int. Pull-Down, Active Low | Panic | | GPIO14 | Digital Input, Int. Pull-Down, Active Low | Calibrate | -| GPIO23 | Digital Output, Active Low | Connection Idicator | -| GPIO19 | Digital Output, Active Low | Connection Idicator | -| GPIO18 | Digital Output, Active Low | Connection Idicator | -| GPIO5 | Digital Output, Active Low | Connection Idicator | +| GPIO23 | Digital Output, Active Low | Connection Indicator | +| GPIO19 | Digital Output, Active Low | Connection Indicator | +| GPIO18 | Digital Output, Active Low | Connection Indicator | +| GPIO5 | Digital Output, Active Low | Connection Indicator | ![](images/ESP32-DOIT-DEVKIT-V1-Board-Pinout-30-GPIOs.webp) From 8c4e4b49a2cea3e0e0911b970972d3f9249c445a Mon Sep 17 00:00:00 2001 From: cody Date: Sun, 24 Nov 2019 17:10:53 +0100 Subject: [PATCH 9/9] Fix. --- libcopter-arduino/src/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libcopter-arduino/src/main.cpp b/libcopter-arduino/src/main.cpp index 460ecd3..99e1522 100644 --- a/libcopter-arduino/src/main.cpp +++ b/libcopter-arduino/src/main.cpp @@ -1,7 +1,7 @@ #include #include #include -#include +#include uint16_t throttle_raw; uint16_t pitch_raw;