|
|
@ -9,6 +9,7 @@ |
|
|
|
#include <LoRa.h>
|
|
|
|
#include <U8g2lib.h>
|
|
|
|
#include <Wire.h>
|
|
|
|
#include <EEPROM.h>
|
|
|
|
|
|
|
|
#include <BleGamepad.h>
|
|
|
|
BleGamepad bleGamepad; |
|
|
@ -49,22 +50,30 @@ struct menu_state { |
|
|
|
}; |
|
|
|
|
|
|
|
struct menu_entry_type menu_entry_alpha_list[] = { |
|
|
|
{ u8g2_font_open_iconic_all_4x_t, 184, "Main"}, |
|
|
|
{ u8g2_font_open_iconic_all_4x_t, 224, "RC Controller"}, |
|
|
|
{ u8g2_font_open_iconic_all_4x_t, 94, "Bluetooth"}, |
|
|
|
{ u8g2_font_open_iconic_all_4x_t, 129, "Configuration"}, |
|
|
|
{ u8g2_font_open_iconic_all_4x_t, 155, "Stick Calibration"}, |
|
|
|
{ u8g2_font_open_iconic_all_4x_t, 246, "Stick Settings"}, |
|
|
|
{ u8g2_font_open_iconic_all_4x_t, 253, "RF Modules"}, |
|
|
|
{ u8g2_font_open_iconic_all_4x_t, 207, "RF Scanners"}, |
|
|
|
{ u8g2_font_open_iconic_all_4x_t, 104, "Debug"}, |
|
|
|
{ u8g2_font_open_iconic_all_4x_t, 90, "Battery"}, |
|
|
|
{ u8g2_font_open_iconic_all_4x_t, 65, "Exit"}, |
|
|
|
{ u8g2_font_open_iconic_all_4x_t, 142, "Save Settings"}, |
|
|
|
{ u8g2_font_open_iconic_all_4x_t, 205, "Reset Default"}, |
|
|
|
{ NULL, 0, NULL } |
|
|
|
}; |
|
|
|
|
|
|
|
struct menu_entry_type menu_entry_alpha_huge_list[] = { |
|
|
|
{ u8g2_font_open_iconic_all_8x_t, 184, "Main"}, |
|
|
|
{ u8g2_font_open_iconic_all_8x_t, 224, "RC Controller"}, |
|
|
|
{ u8g2_font_open_iconic_all_8x_t, 94, "Bluetooth"}, |
|
|
|
{ u8g2_font_open_iconic_all_8x_t, 129, "Configuration"}, |
|
|
|
{ u8g2_font_open_iconic_all_8x_t, 155, "Stick Calibration"}, |
|
|
|
{ u8g2_font_open_iconic_all_8x_t, 246, "Stick Settings"}, |
|
|
|
{ u8g2_font_open_iconic_all_8x_t, 253, "RF Modules"}, |
|
|
|
{ u8g2_font_open_iconic_all_8x_t, 207, "RF Scanners"}, |
|
|
|
{ u8g2_font_open_iconic_all_8x_t, 104, "Debug"}, |
|
|
|
{ u8g2_font_open_iconic_all_8x_t, 90, "Battery"}, |
|
|
|
{ u8g2_font_open_iconic_all_8x_t, 65, "Exit"}, |
|
|
|
{ u8g2_font_open_iconic_all_8x_t, 142, "Save Settings"}, |
|
|
|
{ u8g2_font_open_iconic_all_8x_t, 205, "Reset Default"}, |
|
|
|
{ NULL, 0, NULL } |
|
|
|
}; |
|
|
|
|
|
|
@ -142,13 +151,17 @@ uint8_t towards(struct menu_state *current, struct menu_state *destination) { |
|
|
|
#define MENU_STICK_ROLL_MIN 800
|
|
|
|
#define MENU_STICK_PITCH_MAX 3000
|
|
|
|
#define MENU_STICK_PITCH_MIN 800
|
|
|
|
#define MENU_STICK_YAW_MAX 3000
|
|
|
|
#define MENU_STICK_YAW_MIN 800
|
|
|
|
|
|
|
|
typedef enum { |
|
|
|
MENU_NONE = 0, |
|
|
|
MENU_LEFT, |
|
|
|
MENU_RIGHT, |
|
|
|
MENU_BACK, |
|
|
|
MENU_OK |
|
|
|
MENU_OK, |
|
|
|
MENU_EXTEND_LEFT, |
|
|
|
MENU_EXTEND_RIGHT |
|
|
|
} MENU_NAVIGATION; |
|
|
|
|
|
|
|
MENU_NAVIGATION stick_navigation_position; |
|
|
@ -196,6 +209,16 @@ uint16_t yaw_value = 0; |
|
|
|
uint16_t pitch_value = 0; |
|
|
|
uint16_t roll_value = 0; |
|
|
|
|
|
|
|
// For Center sticks trim
|
|
|
|
uint16_t throttle_max = 0; |
|
|
|
uint16_t throttle_min = 4096; |
|
|
|
uint16_t yaw_max = 0; |
|
|
|
uint16_t yaw_min = 4096; |
|
|
|
uint16_t pitch_max = 0; |
|
|
|
uint16_t pitch_min = 4096; |
|
|
|
uint16_t roll_max = 0; |
|
|
|
uint16_t roll_min = 4096; |
|
|
|
|
|
|
|
uint64_t vbat_value = 0; |
|
|
|
|
|
|
|
bool sw1 = 0; |
|
|
@ -205,6 +228,15 @@ bool sw4 = 0; |
|
|
|
bool sw5 = 0; |
|
|
|
bool sw6 = 0; |
|
|
|
|
|
|
|
bool invert_throttle = false; |
|
|
|
bool invert_yaw = false; |
|
|
|
bool invert_pitch = false; |
|
|
|
bool invert_roll = false; |
|
|
|
|
|
|
|
int8_t trim_throttle = 0; |
|
|
|
int8_t trim_yaw = 0; |
|
|
|
int8_t trim_pitch = 0; |
|
|
|
int8_t trim_roll = 0; |
|
|
|
|
|
|
|
#define MEDIAN_TOTAL 11
|
|
|
|
#define MEDIAN_POS MEDIAN_TOTAL/2
|
|
|
@ -438,9 +470,25 @@ void read_all_voltage() { |
|
|
|
sw6 = !digitalRead(SW6_PIN); |
|
|
|
|
|
|
|
throttle_value = pool_insert(THROTTLE, throttle_raw); |
|
|
|
yaw_value = pool_insert(YAW, yaw_raw); |
|
|
|
pitch_value = pool_insert(PITCH, pitch_raw); |
|
|
|
roll_value = pool_insert(ROLL, roll_raw); |
|
|
|
if(!invert_throttle) |
|
|
|
throttle_value = throttle_value + (trim_throttle << 3); |
|
|
|
else |
|
|
|
throttle_value = throttle_value - (trim_throttle << 3); |
|
|
|
|
|
|
|
if(!invert_yaw) |
|
|
|
yaw_value = pool_insert(YAW, yaw_raw) + (trim_yaw << 3); |
|
|
|
else |
|
|
|
yaw_value = pool_insert(YAW, yaw_raw) - (trim_yaw << 3); |
|
|
|
|
|
|
|
if(!invert_pitch) |
|
|
|
pitch_value = pool_insert(PITCH, pitch_raw) + (trim_pitch << 3); |
|
|
|
else |
|
|
|
pitch_value = pool_insert(PITCH, pitch_raw) - (trim_pitch << 3); |
|
|
|
|
|
|
|
if(!invert_roll) |
|
|
|
roll_value = pool_insert(ROLL, roll_raw) + (trim_roll << 3); |
|
|
|
else |
|
|
|
roll_value = pool_insert(ROLL, roll_raw) - (trim_roll << 3); |
|
|
|
vbat_value = pool_insert(VBAT, vbat_raw); |
|
|
|
} |
|
|
|
|
|
|
@ -448,6 +496,9 @@ void read_all_voltage() { |
|
|
|
void setup() { |
|
|
|
Serial.begin(115200); |
|
|
|
|
|
|
|
// EEPROM initializing
|
|
|
|
EEPROM.begin(512); |
|
|
|
|
|
|
|
// PIN Initialization
|
|
|
|
pinMode(BUZZER_PIN, OUTPUT); |
|
|
|
pinMode(SW1_PIN, INPUT_PULLUP); |
|
|
@ -504,14 +555,17 @@ void setup() { |
|
|
|
Serial.println("LoRa Initializing OK!"); |
|
|
|
*/ |
|
|
|
|
|
|
|
// Reading all settings
|
|
|
|
read_settings(); |
|
|
|
|
|
|
|
u8g2_right.firstPage(); |
|
|
|
u8g2_right.setFontMode(1); |
|
|
|
// u8g2_right.setFont(u8g2_font_helvB10_tr);
|
|
|
|
u8g2_right.setFont(u8g2_font_VCR_OSD_tr); |
|
|
|
u8g2_right.setCursor(0,15); |
|
|
|
// u8g2_right.setFont(u8g2_font_VCR_OSD_tr);
|
|
|
|
u8g2_right.setFont(u8g2_font_ImpactBits_tr); |
|
|
|
u8g2_right.setCursor(48, 40); |
|
|
|
u8g2_right.print(F("READY")); |
|
|
|
u8g2_right.nextPage(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
void loop() { |
|
|
@ -558,6 +612,10 @@ void loop() { |
|
|
|
stick_navigation_position = MENU_OK; |
|
|
|
} else if(pitch_value < MENU_STICK_PITCH_MIN) { |
|
|
|
stick_navigation_position = MENU_BACK; |
|
|
|
} else if(yaw_value > MENU_STICK_YAW_MAX) { |
|
|
|
stick_navigation_position = MENU_EXTEND_RIGHT; |
|
|
|
} else if(yaw_value < MENU_STICK_YAW_MIN) { |
|
|
|
stick_navigation_position = MENU_EXTEND_LEFT; |
|
|
|
} else { |
|
|
|
stick_navigation_position = MENU_NONE; |
|
|
|
} |
|
|
@ -584,7 +642,8 @@ void loop() { |
|
|
|
u8g2_left.firstPage(); |
|
|
|
draw_menu(¤t_alpha_state); |
|
|
|
|
|
|
|
u8g2_left.setFont(u8g2_font_helvB10_tr); |
|
|
|
// u8g2_left.setFont(u8g2_font_helvB10_tr);
|
|
|
|
u8g2_left.setFont(u8g2_font_ImpactBits_tr); |
|
|
|
u8g2_left.setCursor((u8g2_left.getDisplayWidth()-u8g2_left.getStrWidth(menu_entry_alpha_list[destination_alpha_state.position].name))/2, u8g2_left.getDisplayHeight()-5); |
|
|
|
u8g2_left.print(menu_entry_alpha_list[destination_alpha_state.position].name); |
|
|
|
|
|
|
@ -611,6 +670,18 @@ void loop() { |
|
|
|
} else if(menu_entry_alpha_list[destination_alpha_state.position].name == "Bluetooth") { |
|
|
|
require_unlock = true; |
|
|
|
bluetooth_gamepad(); |
|
|
|
} else if(menu_entry_alpha_list[destination_alpha_state.position].name == "Stick Calibration") { |
|
|
|
require_unlock = true; |
|
|
|
stick_calibration(); |
|
|
|
} else if(menu_entry_alpha_list[destination_alpha_state.position].name == "Save Settings") { |
|
|
|
require_unlock = false; |
|
|
|
save_settings(); |
|
|
|
} else if(menu_entry_alpha_list[destination_alpha_state.position].name == "Reset Default") { |
|
|
|
require_unlock = false; |
|
|
|
reset_default(); |
|
|
|
} else if(menu_entry_alpha_list[destination_alpha_state.position].name == "Stick Settings") { |
|
|
|
require_unlock = true; |
|
|
|
stick_position_and_limit_settings(); |
|
|
|
} |
|
|
|
|
|
|
|
//// u8g2_right.clearBuffer();
|
|
|
@ -654,6 +725,594 @@ void loop() { |
|
|
|
*/ |
|
|
|
} |
|
|
|
|
|
|
|
void stick_position_and_limit_settings(void) { |
|
|
|
static int8_t stick_position_pointer = 0; |
|
|
|
|
|
|
|
// Data processing
|
|
|
|
if(stick_navigation_position == MENU_LEFT) { |
|
|
|
if(stick_position_pointer == 0) { |
|
|
|
trim_throttle--; |
|
|
|
} else if(stick_position_pointer == 1) { |
|
|
|
trim_yaw--; |
|
|
|
} else if(stick_position_pointer == 2) { |
|
|
|
trim_pitch--; |
|
|
|
} else if(stick_position_pointer == 3) { |
|
|
|
trim_roll--; |
|
|
|
} |
|
|
|
} else if(stick_navigation_position == MENU_RIGHT) { |
|
|
|
if(stick_position_pointer == 0) { |
|
|
|
trim_throttle++; |
|
|
|
} else if(stick_position_pointer == 1) { |
|
|
|
trim_yaw++; |
|
|
|
} else if(stick_position_pointer == 2) { |
|
|
|
trim_pitch++; |
|
|
|
} else if(stick_position_pointer == 3) { |
|
|
|
trim_roll++; |
|
|
|
} |
|
|
|
} else if(stick_navigation_position == MENU_EXTEND_LEFT) { |
|
|
|
if(stick_position_pointer == 0) { |
|
|
|
invert_throttle = false; |
|
|
|
} else if(stick_position_pointer == 1) { |
|
|
|
invert_yaw = false; |
|
|
|
} else if(stick_position_pointer == 2) { |
|
|
|
invert_pitch = false; |
|
|
|
} else if(stick_position_pointer == 3) { |
|
|
|
invert_roll = false; |
|
|
|
} |
|
|
|
} else if(stick_navigation_position == MENU_EXTEND_RIGHT) { |
|
|
|
if(stick_position_pointer == 0) { |
|
|
|
invert_throttle = true; |
|
|
|
} else if(stick_position_pointer == 1) { |
|
|
|
invert_yaw = true; |
|
|
|
} else if(stick_position_pointer == 2) { |
|
|
|
invert_pitch = true; |
|
|
|
} else if(stick_position_pointer == 3) { |
|
|
|
invert_roll = true; |
|
|
|
} |
|
|
|
} else if(stick_navigation_position == MENU_OK) { |
|
|
|
stick_position_pointer++; |
|
|
|
} |
|
|
|
|
|
|
|
// Done...Lets wait for next
|
|
|
|
stick_navigation_position = MENU_NONE; |
|
|
|
|
|
|
|
// Limit counts
|
|
|
|
if(stick_position_pointer > 3) stick_position_pointer = 0; |
|
|
|
|
|
|
|
if(trim_throttle < -15) trim_throttle = -15; |
|
|
|
if(trim_throttle > 15) trim_throttle = 15; |
|
|
|
if(trim_yaw < -15) trim_yaw = -15; |
|
|
|
if(trim_yaw > 15) trim_yaw = 15; |
|
|
|
if(trim_pitch < -15) trim_pitch = -15; |
|
|
|
if(trim_pitch > 15) trim_pitch = 15; |
|
|
|
if(trim_roll < -15) trim_roll = -15; |
|
|
|
if(trim_roll > 15) trim_roll = 15; |
|
|
|
|
|
|
|
// Displaying...
|
|
|
|
u8g2_left.clearBuffer(); |
|
|
|
u8g2_left.firstPage(); |
|
|
|
u8g2_left.setFont(u8g2_font_ImpactBits_tr); |
|
|
|
u8g2_left.setCursor(10, 15); |
|
|
|
u8g2_left.print(F("Stick Positions")); |
|
|
|
u8g2_left.setFont(u8g2_font_5x7_tf); |
|
|
|
u8g2_left.setCursor(0, 25); |
|
|
|
u8g2_left.print(F("THR: ")); |
|
|
|
if(invert_throttle) { |
|
|
|
u8g2_left.print(F("INVERT")); |
|
|
|
} else { |
|
|
|
u8g2_left.print(F("NORMAL")); |
|
|
|
} |
|
|
|
u8g2_left.setCursor(0, 35); |
|
|
|
u8g2_left.print(F("YAW: ")); |
|
|
|
if(invert_yaw) { |
|
|
|
u8g2_left.print(F("INVERT")); |
|
|
|
} else { |
|
|
|
u8g2_left.print(F("NORMAL")); |
|
|
|
} |
|
|
|
u8g2_left.setCursor(0, 45); |
|
|
|
u8g2_left.print(F("PIT: ")); |
|
|
|
if(invert_pitch) { |
|
|
|
u8g2_left.print(F("INVERT")); |
|
|
|
} else { |
|
|
|
u8g2_left.print(F("NORMAL")); |
|
|
|
} |
|
|
|
u8g2_left.setCursor(0, 55); |
|
|
|
u8g2_left.print(F("ROL: ")); |
|
|
|
if(invert_roll) { |
|
|
|
u8g2_left.print(F("INVERT")); |
|
|
|
} else { |
|
|
|
u8g2_left.print(F("NORMAL")); |
|
|
|
} |
|
|
|
|
|
|
|
// Drawing the Bars
|
|
|
|
// Throttle Trims
|
|
|
|
int8_t trim_values = trim_throttle; |
|
|
|
|
|
|
|
u8g2_left.drawFrame(65, 17, 34, 9); |
|
|
|
if(trim_throttle >= 0) { |
|
|
|
u8g2_left.drawBox(82, 19, trim_throttle, 5); |
|
|
|
} else { |
|
|
|
u8g2_left.drawBox(82 + trim_throttle, 19, -(trim_throttle), 5); |
|
|
|
} |
|
|
|
|
|
|
|
u8g2_left.drawFrame(65, 27, 34, 9); |
|
|
|
if(trim_yaw >= 0) { |
|
|
|
u8g2_left.drawBox(82, 29, trim_yaw, 5); |
|
|
|
} else { |
|
|
|
u8g2_left.drawBox(82 + trim_yaw, 29, -(trim_yaw), 5); |
|
|
|
} |
|
|
|
|
|
|
|
u8g2_left.drawFrame(65, 37, 34, 9); |
|
|
|
if(trim_pitch >= 0) { |
|
|
|
u8g2_left.drawBox(82, 39, trim_pitch, 5); |
|
|
|
} else { |
|
|
|
u8g2_left.drawBox(82 + trim_pitch, 39, -(trim_pitch), 5); |
|
|
|
} |
|
|
|
|
|
|
|
u8g2_left.drawFrame(65, 47, 34, 9); |
|
|
|
if(trim_roll >= 0) { |
|
|
|
u8g2_left.drawBox(82, 49, trim_roll, 5); |
|
|
|
} else { |
|
|
|
u8g2_left.drawBox(82 + trim_roll, 49, -(trim_roll), 5); |
|
|
|
} |
|
|
|
|
|
|
|
// Pointers
|
|
|
|
u8g2_left.setCursor(110, 25 + (stick_position_pointer * 10)); |
|
|
|
u8g2_left.print(F("<")); |
|
|
|
|
|
|
|
/*
|
|
|
|
static char buf[6]; |
|
|
|
strcpy(buf, ltoa(trim_throttle, buf, 10)); |
|
|
|
u8g2_right.drawStr(100, 35,buf); |
|
|
|
|
|
|
|
if(reset_selections) { |
|
|
|
u8g2_left.drawFrame(26, 40, 30, 20); |
|
|
|
} else { |
|
|
|
u8g2_left.drawFrame(62, 40, 30, 20); |
|
|
|
} |
|
|
|
*/ |
|
|
|
|
|
|
|
u8g2_left.nextPage(); |
|
|
|
|
|
|
|
u8g2_right.clearBuffer(); |
|
|
|
u8g2_right.firstPage(); |
|
|
|
|
|
|
|
draw_gimbalbox(0, 0); |
|
|
|
draw_gimbalbox(64, 0); |
|
|
|
|
|
|
|
// Mapping based on the live values
|
|
|
|
uint16_t gimbal_y_raw = throttle_value; |
|
|
|
uint16_t gimbal_x_raw = yaw_value; |
|
|
|
if(gimbal_y_raw < throttle_min) gimbal_y_raw = throttle_min; |
|
|
|
if(gimbal_y_raw > throttle_max) gimbal_y_raw = throttle_max; |
|
|
|
if(gimbal_x_raw < yaw_min) gimbal_x_raw = yaw_min; |
|
|
|
if(gimbal_x_raw > yaw_max) gimbal_x_raw = yaw_max; |
|
|
|
|
|
|
|
uint8_t gimbal_y; |
|
|
|
if(!invert_throttle) |
|
|
|
gimbal_y = map(gimbal_y_raw, throttle_min, throttle_max, 0, 63); // Throttle
|
|
|
|
else |
|
|
|
gimbal_y = map(gimbal_y_raw, throttle_max, throttle_min, 0, 63); // Throttle
|
|
|
|
|
|
|
|
uint8_t gimbal_x; |
|
|
|
if(!invert_yaw) |
|
|
|
gimbal_x = map(gimbal_x_raw, yaw_min, yaw_max, 0, 63); // Yaw
|
|
|
|
else |
|
|
|
gimbal_x = map(gimbal_x_raw, yaw_max, yaw_min, 0, 63); // Yaw
|
|
|
|
|
|
|
|
u8g2_right.drawFilledEllipse(gimbal_x, gimbal_y, 3, 3, U8G2_DRAW_ALL); |
|
|
|
|
|
|
|
// Mapping based on the live values
|
|
|
|
gimbal_y_raw = pitch_value; |
|
|
|
gimbal_x_raw = roll_value; |
|
|
|
if(gimbal_y_raw < pitch_min) gimbal_y_raw = pitch_min; |
|
|
|
if(gimbal_y_raw > pitch_max) gimbal_y_raw = pitch_max; |
|
|
|
if(gimbal_x_raw < roll_min) gimbal_x_raw = roll_min; |
|
|
|
if(gimbal_x_raw > roll_max) gimbal_x_raw = roll_max; |
|
|
|
|
|
|
|
if(!invert_pitch) |
|
|
|
gimbal_y = map(gimbal_y_raw, pitch_min, pitch_max, 0, 63); // Pitch
|
|
|
|
else |
|
|
|
gimbal_y = map(gimbal_y_raw, pitch_max, pitch_min, 0, 63); // Pitch
|
|
|
|
if(!invert_roll) |
|
|
|
gimbal_x = map(gimbal_x_raw, roll_min, roll_max, 0, 63); // Roll
|
|
|
|
else |
|
|
|
gimbal_x = map(gimbal_x_raw, roll_max, roll_min, 0, 63); // Roll
|
|
|
|
|
|
|
|
u8g2_right.drawFilledEllipse(64 + gimbal_x, gimbal_y, 3, 3, U8G2_DRAW_ALL); |
|
|
|
|
|
|
|
|
|
|
|
u8g2_right.nextPage(); |
|
|
|
} |
|
|
|
|
|
|
|
void read_settings(void) { |
|
|
|
uint16_t addr = 0x00; |
|
|
|
|
|
|
|
// Throttle Max
|
|
|
|
throttle_max = EEPROM.read(addr) | EEPROM.read(addr + 1) << 8; |
|
|
|
|
|
|
|
// New unit / reset.... dont need to read....
|
|
|
|
if(throttle_max == 0) return; |
|
|
|
|
|
|
|
// Throttle Min
|
|
|
|
addr = 2; |
|
|
|
throttle_min = EEPROM.read(addr) | EEPROM.read(addr + 1) << 8; |
|
|
|
|
|
|
|
// Yaw Max
|
|
|
|
addr = 4; |
|
|
|
yaw_max = EEPROM.read(addr) | EEPROM.read(addr + 1) << 8; |
|
|
|
|
|
|
|
// Yaw Min
|
|
|
|
addr = 6; |
|
|
|
yaw_min = EEPROM.read(addr) | EEPROM.read(addr + 1) << 8; |
|
|
|
|
|
|
|
// Pitch Max
|
|
|
|
addr = 8; |
|
|
|
pitch_max = EEPROM.read(addr) | EEPROM.read(addr + 1) << 8; |
|
|
|
|
|
|
|
// Pitch Min
|
|
|
|
addr = 10; |
|
|
|
pitch_min = EEPROM.read(addr) | EEPROM.read(addr + 1) << 8; |
|
|
|
|
|
|
|
// Roll Max
|
|
|
|
addr = 12; |
|
|
|
roll_max = EEPROM.read(addr) | EEPROM.read(addr + 1) << 8; |
|
|
|
|
|
|
|
// Roll Min
|
|
|
|
addr = 14; |
|
|
|
roll_min = EEPROM.read(addr) | EEPROM.read(addr + 1) << 8; |
|
|
|
|
|
|
|
// Inverted Values
|
|
|
|
addr = 16; |
|
|
|
int8_t val = EEPROM.read(addr); |
|
|
|
invert_throttle = ((val & 0b00001000) >> 3) ? true : false; |
|
|
|
invert_yaw = ((val & 0b00000100) >> 2) ? true : false; |
|
|
|
invert_pitch = ((val & 0b00000010) >> 1) ? true : false; |
|
|
|
invert_roll = ((val & 0b00000001) >> 0) ? true : false; |
|
|
|
|
|
|
|
// Throttle Trim
|
|
|
|
addr = 17; |
|
|
|
trim_throttle = EEPROM.read(addr); |
|
|
|
|
|
|
|
// Yaw Trim
|
|
|
|
addr = 18; |
|
|
|
trim_yaw = EEPROM.read(addr); |
|
|
|
|
|
|
|
// Pitch Trim
|
|
|
|
addr = 19; |
|
|
|
trim_pitch = EEPROM.read(addr); |
|
|
|
|
|
|
|
// Roll Trim
|
|
|
|
addr = 20; |
|
|
|
trim_roll = EEPROM.read(addr); |
|
|
|
} |
|
|
|
|
|
|
|
void commit_all(void) { |
|
|
|
/*
|
|
|
|
* Memory Format: |
|
|
|
* |
|
|
|
* TTttYYyyPPppRRrrPABCD |
|
|
|
* |
|
|
|
* TT: Throttle Max |
|
|
|
* tt: Throttle Min |
|
|
|
* YY: Yaw Max |
|
|
|
* yy: Yaw Min |
|
|
|
* PP: Pitch Max |
|
|
|
* pp: Pitch Min |
|
|
|
* RR: Roll Max |
|
|
|
* rr: Roll Min |
|
|
|
* P : Invert Gimbals (0000TYPR) |
|
|
|
* A : Throttle Trim |
|
|
|
* B : Yaw Trim |
|
|
|
* C : Pitch Trim |
|
|
|
* D : Roll Trim |
|
|
|
*/ |
|
|
|
uint16_t addr = 0x00; |
|
|
|
|
|
|
|
// Throttle Max
|
|
|
|
write_data(addr++, throttle_max & 0xFF); // Low bits
|
|
|
|
write_data(addr++, throttle_max >> 8 & 0xFF); // High bits
|
|
|
|
|
|
|
|
// Throttle Min
|
|
|
|
write_data(addr++, throttle_min & 0xFF); // Low bits
|
|
|
|
write_data(addr++, throttle_min >> 8 & 0xFF); // High bits
|
|
|
|
|
|
|
|
// Yaw Max
|
|
|
|
write_data(addr++, yaw_max & 0xFF); // Low bits
|
|
|
|
write_data(addr++, yaw_max >> 8 & 0xFF); // High bits
|
|
|
|
|
|
|
|
// Yaw Min
|
|
|
|
write_data(addr++, yaw_min & 0xFF); // Low bits
|
|
|
|
write_data(addr++, yaw_min >> 8 & 0xFF); // High bits
|
|
|
|
|
|
|
|
// Pitch Max
|
|
|
|
write_data(addr++, pitch_max & 0xFF); // Low bits
|
|
|
|
write_data(addr++, pitch_max >> 8 & 0xFF); // High bits
|
|
|
|
|
|
|
|
// Pitch Min
|
|
|
|
write_data(addr++, pitch_min & 0xFF); // Low bits
|
|
|
|
write_data(addr++, pitch_min >> 8 & 0xFF); // High bits
|
|
|
|
|
|
|
|
// Roll Max
|
|
|
|
write_data(addr++, roll_max & 0xFF); // Low bits
|
|
|
|
write_data(addr++, roll_max >> 8 & 0xFF); // High bits
|
|
|
|
|
|
|
|
// Roll Min
|
|
|
|
write_data(addr++, roll_min & 0xFF); // Low bits
|
|
|
|
write_data(addr++, roll_min >> 8 & 0xFF); // High bits
|
|
|
|
|
|
|
|
// Inverted Gimbals
|
|
|
|
// uint8_t val = invert_throttle << 3 || invert_yaw << 2 || invert_pitch << 1 || invert_roll;
|
|
|
|
uint8_t val = ((invert_throttle) ? 1 << 3 : 0) + ((invert_yaw) ? 1 << 2 : 0) + ((invert_pitch) ? 1 << 1 : 0) + ((invert_roll) ? 1 : 0); |
|
|
|
|
|
|
|
Serial.println(val); |
|
|
|
write_data(addr++, val); |
|
|
|
|
|
|
|
// Throttle Trim
|
|
|
|
write_data(addr++, trim_throttle); |
|
|
|
|
|
|
|
// Yaw Trim
|
|
|
|
write_data(addr++, trim_yaw); |
|
|
|
|
|
|
|
// Pitch Trim
|
|
|
|
write_data(addr++, trim_pitch); |
|
|
|
|
|
|
|
// Roll Trim
|
|
|
|
write_data(addr++, trim_roll); |
|
|
|
} |
|
|
|
|
|
|
|
void write_data(uint16_t addr, uint8_t val) { |
|
|
|
// timerAlarmDisable(timer);
|
|
|
|
EEPROM.write(addr, val); |
|
|
|
EEPROM.commit(); |
|
|
|
// timerAlarmEnable(timer);
|
|
|
|
} |
|
|
|
|
|
|
|
void reset_settings(void) { |
|
|
|
for(int i = 0; i < 255; i++) { |
|
|
|
write_data(i, 0x00); |
|
|
|
} |
|
|
|
|
|
|
|
// Reboot
|
|
|
|
reboot(); |
|
|
|
} |
|
|
|
|
|
|
|
void reboot(void) { |
|
|
|
ESP.restart(); |
|
|
|
} |
|
|
|
|
|
|
|
void reset_default(void) { |
|
|
|
static bool reset_selections = false; |
|
|
|
u8g2_left.clearBuffer(); |
|
|
|
u8g2_left.firstPage(); |
|
|
|
u8g2_left.setFont(u8g2_font_ImpactBits_tr); |
|
|
|
u8g2_left.setCursor(10, 25); |
|
|
|
u8g2_left.print(F("Reset Settings?")); |
|
|
|
u8g2_left.setCursor(30, 55); |
|
|
|
u8g2_left.print(F("Yes No")); |
|
|
|
|
|
|
|
if(stick_navigation_position == MENU_LEFT) { |
|
|
|
reset_selections = true; |
|
|
|
} else if(stick_navigation_position == MENU_RIGHT) { |
|
|
|
reset_selections = false; |
|
|
|
} else if(stick_navigation_position == MENU_OK) { |
|
|
|
// Reset Settings..
|
|
|
|
if(reset_selections) |
|
|
|
reset_settings(); |
|
|
|
|
|
|
|
// Simulate...so it will return back..
|
|
|
|
menu_entry_alpha_selected = false; |
|
|
|
last_menu_stick_read = millis() + 200; |
|
|
|
} |
|
|
|
|
|
|
|
if(reset_selections) { |
|
|
|
u8g2_left.drawFrame(26, 40, 30, 20); |
|
|
|
} else { |
|
|
|
u8g2_left.drawFrame(62, 40, 30, 20); |
|
|
|
} |
|
|
|
u8g2_left.nextPage(); |
|
|
|
|
|
|
|
u8g2_right.clearBuffer(); |
|
|
|
u8g2_right.firstPage(); |
|
|
|
u8g2_right.nextPage(); |
|
|
|
} |
|
|
|
|
|
|
|
void save_settings(void) { |
|
|
|
static bool save_selections = false; |
|
|
|
u8g2_left.clearBuffer(); |
|
|
|
u8g2_left.firstPage(); |
|
|
|
u8g2_left.setFont(u8g2_font_ImpactBits_tr); |
|
|
|
u8g2_left.setCursor(10, 25); |
|
|
|
u8g2_left.print(F("Save Settings?")); |
|
|
|
u8g2_left.setCursor(30, 55); |
|
|
|
u8g2_left.print(F("Yes No")); |
|
|
|
|
|
|
|
if(stick_navigation_position == MENU_LEFT) { |
|
|
|
save_selections = true; |
|
|
|
} else if(stick_navigation_position == MENU_RIGHT) { |
|
|
|
save_selections = false; |
|
|
|
} else if(stick_navigation_position == MENU_OK) { |
|
|
|
// Save settings
|
|
|
|
if(save_selections) |
|
|
|
commit_all(); |
|
|
|
|
|
|
|
// Simulate...so it will return back..
|
|
|
|
menu_entry_alpha_selected = false; |
|
|
|
last_menu_stick_read = millis() + 200; |
|
|
|
} |
|
|
|
|
|
|
|
if(save_selections) { |
|
|
|
u8g2_left.drawFrame(26, 40, 30, 20); |
|
|
|
} else { |
|
|
|
u8g2_left.drawFrame(62, 40, 30, 20); |
|
|
|
} |
|
|
|
u8g2_left.nextPage(); |
|
|
|
|
|
|
|
u8g2_right.clearBuffer(); |
|
|
|
u8g2_right.firstPage(); |
|
|
|
u8g2_right.nextPage(); |
|
|
|
} |
|
|
|
|
|
|
|
// Draw the gimbal box
|
|
|
|
void draw_gimbalbox(uint8_t x, uint8_t y) { |
|
|
|
uint8_t w = 63; |
|
|
|
uint8_t hm = 31; |
|
|
|
uint8_t vm = x + hm; |
|
|
|
|
|
|
|
// showing the gimbal range
|
|
|
|
u8g2_left.drawFrame(x, y, w, w); |
|
|
|
|
|
|
|
// showing the crosshair
|
|
|
|
// horizontal
|
|
|
|
for(uint8_t i = x; i < (x+w); i+=5) { |
|
|
|
u8g2_left.drawPixel(i, hm); |
|
|
|
} |
|
|
|
|
|
|
|
// vertical
|
|
|
|
for(uint8_t i = y; i < (y+w); i+=5) { |
|
|
|
u8g2_left.drawPixel(vm, i); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
void stick_calibration() { |
|
|
|
static char buf[6]; |
|
|
|
|
|
|
|
u8g2_left.clearBuffer(); |
|
|
|
u8g2_left.firstPage(); |
|
|
|
|
|
|
|
// showing the gimbal range
|
|
|
|
draw_gimbalbox(64, 0); |
|
|
|
|
|
|
|
// Getting the throttle minimum
|
|
|
|
if(throttle_value < throttle_min) { |
|
|
|
throttle_min = throttle_value; |
|
|
|
} |
|
|
|
if(throttle_value > throttle_max) { |
|
|
|
throttle_max = throttle_value; |
|
|
|
} |
|
|
|
if(yaw_value < yaw_min) { |
|
|
|
yaw_min = yaw_value; |
|
|
|
} |
|
|
|
if(yaw_value > yaw_max) { |
|
|
|
yaw_max = yaw_value; |
|
|
|
} |
|
|
|
if(pitch_value < pitch_min) pitch_min = pitch_value; |
|
|
|
if(pitch_value > pitch_max) pitch_max = pitch_value; |
|
|
|
if(roll_value < roll_min) roll_min = roll_value; |
|
|
|
if(roll_value > roll_max) roll_max = roll_value; |
|
|
|
|
|
|
|
// Mapping based on the live values
|
|
|
|
uint16_t gimbal_y_raw = throttle_value; |
|
|
|
uint16_t gimbal_x_raw = yaw_value; |
|
|
|
if(gimbal_y_raw < throttle_min) gimbal_y_raw = throttle_min; |
|
|
|
if(gimbal_y_raw > throttle_max) gimbal_y_raw = throttle_max; |
|
|
|
if(gimbal_x_raw < yaw_min) gimbal_x_raw = yaw_min; |
|
|
|
if(gimbal_x_raw > yaw_max) gimbal_x_raw = yaw_max; |
|
|
|
|
|
|
|
uint8_t gimbal_y; |
|
|
|
if(!invert_throttle) |
|
|
|
gimbal_y = map(gimbal_y_raw, throttle_min, throttle_max, 0, 63); // Throttle
|
|
|
|
else |
|
|
|
gimbal_y = map(gimbal_y_raw, throttle_max, throttle_min, 0, 63); // Throttle
|
|
|
|
|
|
|
|
uint8_t gimbal_x; |
|
|
|
if(!invert_yaw) |
|
|
|
gimbal_x = map(gimbal_x_raw, yaw_min, yaw_max, 0, 63); // Yaw
|
|
|
|
else |
|
|
|
gimbal_x = map(gimbal_x_raw, yaw_max, yaw_min, 0, 63); // Yaw
|
|
|
|
|
|
|
|
u8g2_left.drawFilledEllipse(64 + gimbal_x, gimbal_y, 3, 3, U8G2_DRAW_ALL); |
|
|
|
|
|
|
|
// Throttle
|
|
|
|
u8g2_left.setCursor(0, 12); |
|
|
|
u8g2_left.setFont(u8g2_font_ImpactBits_tr); |
|
|
|
u8g2_left.print(F("Throttle:")); |
|
|
|
u8g2_left.setFont(u8g2_font_TimesNewPixel_tr); |
|
|
|
strcpy(buf, ltoa(throttle_min, buf, 10)); |
|
|
|
u8g2_left.drawStr(0, 25, buf); |
|
|
|
strcpy(buf, ltoa(throttle_max, buf, 10)); |
|
|
|
u8g2_left.drawStr(30, 25, buf); |
|
|
|
|
|
|
|
// Yaw
|
|
|
|
u8g2_left.setCursor(0, 45); |
|
|
|
u8g2_left.setFont(u8g2_font_ImpactBits_tr); |
|
|
|
u8g2_left.print(F("Yaw:")); |
|
|
|
u8g2_left.setFont(u8g2_font_TimesNewPixel_tr); |
|
|
|
strcpy(buf, ltoa(yaw_min, buf, 10)); |
|
|
|
u8g2_left.drawStr(0, 60, buf); |
|
|
|
strcpy(buf, ltoa(yaw_max, buf, 10)); |
|
|
|
u8g2_left.drawStr(30, 60, buf); |
|
|
|
|
|
|
|
u8g2_left.nextPage(); |
|
|
|
|
|
|
|
u8g2_right.clearBuffer(); |
|
|
|
u8g2_right.firstPage(); |
|
|
|
|
|
|
|
// showing the gimbal range
|
|
|
|
draw_gimbalbox(0, 0); |
|
|
|
|
|
|
|
// Getting the pitch minimum
|
|
|
|
if(pitch_value < pitch_min) { |
|
|
|
pitch_min = pitch_value; |
|
|
|
} |
|
|
|
if(pitch_value > pitch_max) { |
|
|
|
pitch_max = pitch_value; |
|
|
|
} |
|
|
|
if(roll_value < roll_min) { |
|
|
|
roll_min = roll_value; |
|
|
|
} |
|
|
|
if(roll_value > roll_max) { |
|
|
|
roll_max = roll_value; |
|
|
|
} |
|
|
|
if(pitch_value < pitch_min) pitch_min = pitch_value; |
|
|
|
if(pitch_value > pitch_max) pitch_max = pitch_value; |
|
|
|
if(roll_value < roll_min) roll_min = roll_value; |
|
|
|
if(roll_value > roll_max) roll_max = roll_value; |
|
|
|
|
|
|
|
// Mapping based on the live values
|
|
|
|
gimbal_y_raw = pitch_value; |
|
|
|
gimbal_x_raw = roll_value; |
|
|
|
if(gimbal_y_raw < pitch_min) gimbal_y_raw = pitch_min; |
|
|
|
if(gimbal_y_raw > pitch_max) gimbal_y_raw = pitch_max; |
|
|
|
if(gimbal_x_raw < roll_min) gimbal_x_raw = roll_min; |
|
|
|
if(gimbal_x_raw > roll_max) gimbal_x_raw = roll_max; |
|
|
|
|
|
|
|
if(!invert_pitch) |
|
|
|
gimbal_y = map(gimbal_y_raw, pitch_min, pitch_max, 0, 63); // Pitch
|
|
|
|
else |
|
|
|
gimbal_y = map(gimbal_y_raw, pitch_max, pitch_min, 0, 63); // Pitch
|
|
|
|
|
|
|
|
if(!invert_roll) |
|
|
|
gimbal_x = map(gimbal_x_raw, roll_min, roll_max, 0, 63); // Roll
|
|
|
|
else |
|
|
|
gimbal_x = map(gimbal_x_raw, roll_max, roll_min, 0, 63); // Roll
|
|
|
|
|
|
|
|
u8g2_right.drawFilledEllipse(gimbal_x, gimbal_y, 3, 3, U8G2_DRAW_ALL); |
|
|
|
|
|
|
|
// Pitch
|
|
|
|
u8g2_right.setCursor(65, 12); |
|
|
|
u8g2_right.setFont(u8g2_font_ImpactBits_tr); |
|
|
|
u8g2_right.print(F("Pitch:")); |
|
|
|
u8g2_right.setFont(u8g2_font_TimesNewPixel_tr); |
|
|
|
strcpy(buf, ltoa(pitch_min, buf, 10)); |
|
|
|
u8g2_left.drawStr(65, 25, buf); |
|
|
|
strcpy(buf, ltoa(pitch_max, buf, 10)); |
|
|
|
u8g2_right.drawStr(95, 25, buf); |
|
|
|
|
|
|
|
// Roll
|
|
|
|
u8g2_right.setCursor(65, 45); |
|
|
|
u8g2_right.setFont(u8g2_font_ImpactBits_tr); |
|
|
|
u8g2_right.print(F("Roll:")); |
|
|
|
u8g2_right.setFont(u8g2_font_TimesNewPixel_tr); |
|
|
|
strcpy(buf, ltoa(roll_min, buf, 10)); |
|
|
|
u8g2_right.drawStr(65, 60, buf); |
|
|
|
strcpy(buf, ltoa(roll_max, buf, 10)); |
|
|
|
u8g2_right.drawStr(95, 60, buf); |
|
|
|
|
|
|
|
|
|
|
|
u8g2_right.nextPage(); |
|
|
|
} |
|
|
|
|
|
|
|
void bluetooth_gamepad() { |
|
|
|
u8g2_left.clearBuffer(); |
|
|
|
u8g2_left.firstPage(); |
|
|
@ -675,8 +1334,8 @@ void bluetooth_gamepad() { |
|
|
|
|
|
|
|
u8g2_right.setCursor(15,15); |
|
|
|
u8g2_right.print(F("Bluetooth PAD")); |
|
|
|
u8g2_right.setFont(u8g2_font_TimesNewPixel_tr); |
|
|
|
|
|
|
|
u8g2_right.setFont(u8g2_font_TimesNewPixel_tr); |
|
|
|
u8g2_right.setCursor(0,30); |
|
|
|
u8g2_right.print(F("T:")); |
|
|
|
strcpy(buf, ltoa(throttle, buf, 10)); |
|
|
@ -702,7 +1361,12 @@ void bluetooth_gamepad() { |
|
|
|
u8g2_right.setCursor(0,60); |
|
|
|
u8g2_right.print(F("Rate:")); |
|
|
|
strcpy(buf, ltoa(ble_profiling, buf, 10)); |
|
|
|
u8g2_right.drawStr(0,40,buf); |
|
|
|
u8g2_right.drawStr(35,60,buf); |
|
|
|
|
|
|
|
if(!sw6) { |
|
|
|
u8g2_right.setCursor(60,60); |
|
|
|
u8g2_right.print(F("LOCKED")); |
|
|
|
} |
|
|
|
|
|
|
|
u8g2_right.nextPage(); |
|
|
|
|
|
|
|