Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place. Commercial Alternative to JupyterHub.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place. Commercial Alternative to JupyterHub.
Path: blob/master/ArduSub/joystick.cpp
Views: 1798
#include "Sub.h"1#include "mode.h"23// Functions that will handle joystick/gamepad input4// ----------------------------------------------------------------------------56// Anonymous namespace to hold variables used only in this file7namespace {8float cam_tilt = 1500.0;9float cam_pan = 1500.0;10int16_t lights1 = 1100;11int16_t lights2 = 1100;12int16_t rollTrim = 0;13int16_t pitchTrim = 0;14int16_t zTrim = 0;15int16_t xTrim = 0;16int16_t yTrim = 0;17int16_t video_switch = 1100;18int16_t x_last, y_last, z_last;19uint32_t buttons_prev;2021// Servo control output channels22// TODO: Allow selecting output channels23const uint8_t SERVO_CHAN_1 = 9; // Pixhawk Aux124const uint8_t SERVO_CHAN_2 = 10; // Pixhawk Aux225const uint8_t SERVO_CHAN_3 = 11; // Pixhawk Aux32627bool controls_reset_since_input_hold = true;28}2930void Sub::init_joystick()31{32default_js_buttons();3334lights1 = RC_Channels::rc_channel(8)->get_radio_min();35lights2 = RC_Channels::rc_channel(9)->get_radio_min();3637set_mode(Mode::Number::MANUAL, ModeReason::RC_COMMAND); // Initialize flight mode3839if (g.numGainSettings < 1) {40g.numGainSettings.set_and_save(1);41}4243if (g.numGainSettings == 1 || (g.gain_default < g.maxGain + 0.01 && g.gain_default > g.minGain - 0.01)) {44gain = constrain_float(g.gain_default, g.minGain, g.maxGain); // Use default gain parameter45} else {46// Use setting closest to average of minGain and maxGain47gain = g.minGain + (g.numGainSettings/2 - 1) * (g.maxGain - g.minGain) / (g.numGainSettings - 1);48}4950gain = constrain_float(gain, 0.1, 1.0);51}5253void Sub::transform_manual_control_to_rc_override(int16_t x, int16_t y, int16_t z, int16_t r, uint16_t buttons, uint16_t buttons2, uint8_t enabled_extensions,54int16_t s,55int16_t t,56int16_t aux1,57int16_t aux2,58int16_t aux3,59int16_t aux4,60int16_t aux5,61int16_t aux6)62{6364float rpyScale = 0.4*gain; // Scale -1000-1000 to -400-400 with gain65float throttleScale = 0.8*gain*g.throttle_gain; // Scale 0-1000 to 0-800 times gain66int16_t rpyCenter = 1500;67int16_t throttleBase = 1500-500*throttleScale;6869bool shift = false;7071// Neutralize camera tilt and pan speed setpoint72cam_tilt = 1500;73cam_pan = 1500;7475uint32_t all_buttons = buttons | (buttons2 << 16);76// Detect if any shift button is pressed77for (uint8_t i = 0 ; i < 32 ; i++) {78if ((all_buttons & (1 << i)) && get_button(i)->function() == JSButton::button_function_t::k_shift) {79shift = true;80}81}8283// Act if button is pressed84// Only act upon pressing button and ignore holding. This provides compatibility with Taranis as joystick.85for (uint8_t i = 0 ; i < 32 ; i++) {86if ((all_buttons & (1 << i))) {87handle_jsbutton_press(i,shift,(buttons_prev & (1 << i)));88// buttonDebounce = tnow_ms;89} else if (buttons_prev & (1 << i)) {90handle_jsbutton_release(i, shift);91}92}9394buttons_prev = all_buttons;9596// attitude mode:97if (roll_pitch_flag == 1) {98// adjust roll/pitch trim with joystick input instead of forward/lateral99pitchTrim = -x * rpyScale;100rollTrim = y * rpyScale;101}102103uint32_t tnow = AP_HAL::millis();104105int16_t zTot;106int16_t yTot;107int16_t xTot;108109if (!controls_reset_since_input_hold) {110zTot = zTrim + 500; // 500 is neutral for throttle111yTot = yTrim;112xTot = xTrim;113// if all 3 axes return to neutral, than we're ready to accept input again114controls_reset_since_input_hold = (abs(z - 500) < 50) && (abs(y) < 50) && (abs(x) < 50);115} else {116zTot = z + zTrim;117yTot = y + yTrim;118xTot = x + xTrim;119}120121RC_Channels::set_override(0, constrain_int16(s + pitchTrim + rpyCenter,1100,1900), tnow); // pitch122RC_Channels::set_override(1, constrain_int16(t + rollTrim + rpyCenter,1100,1900), tnow); // roll123124RC_Channels::set_override(2, constrain_int16((zTot)*throttleScale+throttleBase,1100,1900), tnow); // throttle125RC_Channels::set_override(3, constrain_int16(r*rpyScale+rpyCenter,1100,1900), tnow); // yaw126127// maneuver mode:128if (roll_pitch_flag == 0) {129// adjust forward and lateral with joystick input instead of roll and pitch130RC_Channels::set_override(4, constrain_int16((xTot)*rpyScale+rpyCenter,1100,1900), tnow); // forward for ROV131RC_Channels::set_override(5, constrain_int16((yTot)*rpyScale+rpyCenter,1100,1900), tnow); // lateral for ROV132} else {133// neutralize forward and lateral input while we are adjusting roll and pitch134RC_Channels::set_override(4, constrain_int16(xTrim*rpyScale+rpyCenter,1100,1900), tnow); // forward for ROV135RC_Channels::set_override(5, constrain_int16(yTrim*rpyScale+rpyCenter,1100,1900), tnow); // lateral for ROV136}137138RC_Channels::set_override(6, cam_pan, tnow); // camera pan139RC_Channels::set_override(7, cam_tilt, tnow); // camera tilt140RC_Channels::set_override(8, lights1, tnow); // lights 1141RC_Channels::set_override(9, lights2, tnow); // lights 2142RC_Channels::set_override(10, video_switch, tnow); // video switch143144// Store old x, y, z values for use in input hold logic145x_last = x;146y_last = y;147z_last = z;148}149150void Sub::handle_jsbutton_press(uint8_t _button, bool shift, bool held)151{152// Act based on the function assigned to this button153switch (get_button(_button)->function(shift)) {154case JSButton::button_function_t::k_arm_toggle:155if (motors.armed()) {156arming.disarm(AP_Arming::Method::MAVLINK);157} else {158arming.arm(AP_Arming::Method::MAVLINK);159}160break;161case JSButton::button_function_t::k_arm:162arming.arm(AP_Arming::Method::MAVLINK);163break;164case JSButton::button_function_t::k_disarm:165arming.disarm(AP_Arming::Method::MAVLINK);166break;167168case JSButton::button_function_t::k_mode_manual:169set_mode(Mode::Number::MANUAL, ModeReason::RC_COMMAND);170break;171case JSButton::button_function_t::k_mode_stabilize:172set_mode(Mode::Number::STABILIZE, ModeReason::RC_COMMAND);173break;174case JSButton::button_function_t::k_mode_depth_hold:175set_mode(Mode::Number::ALT_HOLD, ModeReason::RC_COMMAND);176break;177case JSButton::button_function_t::k_mode_auto:178set_mode(Mode::Number::AUTO, ModeReason::RC_COMMAND);179break;180case JSButton::button_function_t::k_mode_guided:181set_mode(Mode::Number::GUIDED, ModeReason::RC_COMMAND);182break;183case JSButton::button_function_t::k_mode_circle:184set_mode(Mode::Number::CIRCLE, ModeReason::RC_COMMAND);185break;186case JSButton::button_function_t::k_mode_acro:187set_mode(Mode::Number::ACRO, ModeReason::RC_COMMAND);188break;189case JSButton::button_function_t::k_mode_poshold:190set_mode(Mode::Number::POSHOLD, ModeReason::RC_COMMAND);191break;192#if AP_RANGEFINDER_ENABLED193case JSButton::button_function_t::k_mode_surftrak:194set_mode(Mode::Number::SURFTRAK, ModeReason::RC_COMMAND);195break;196#endif197198case JSButton::button_function_t::k_mount_center:199#if HAL_MOUNT_ENABLED200camera_mount.set_angle_target(0, 0, 0, false);201// for some reason the call to set_angle_targets changes the mode to mavlink targeting!202camera_mount.set_mode(MAV_MOUNT_MODE_RC_TARGETING);203#endif204break;205case JSButton::button_function_t::k_mount_tilt_up:206cam_tilt = 1900;207break;208case JSButton::button_function_t::k_mount_tilt_down:209cam_tilt = 1100;210break;211case JSButton::button_function_t::k_camera_trigger:212break;213case JSButton::button_function_t::k_camera_source_toggle:214if (!held) {215static bool video_toggle = false;216video_toggle = !video_toggle;217if (video_toggle) {218video_switch = 1900;219gcs().send_text(MAV_SEVERITY_INFO,"Video Toggle: Source 2");220} else {221video_switch = 1100;222gcs().send_text(MAV_SEVERITY_INFO,"Video Toggle: Source 1");223}224}225break;226case JSButton::button_function_t::k_mount_pan_right:227cam_pan = 1900;228break;229case JSButton::button_function_t::k_mount_pan_left:230cam_pan = 1100;231break;232case JSButton::button_function_t::k_lights1_cycle:233if (!held) {234static bool increasing = true;235RC_Channel* chan = RC_Channels::rc_channel(8);236uint16_t min = chan->get_radio_min();237uint16_t max = chan->get_radio_max();238uint16_t step = (max - min) / g.lights_steps;239if (increasing) {240lights1 = constrain_float(lights1 + step, min, max);241} else {242lights1 = constrain_float(lights1 - step, min, max);243}244if (lights1 >= max || lights1 <= min) {245increasing = !increasing;246}247}248break;249case JSButton::button_function_t::k_lights1_brighter:250if (!held) {251RC_Channel* chan = RC_Channels::rc_channel(8);252uint16_t min = chan->get_radio_min();253uint16_t max = chan->get_radio_max();254uint16_t step = (max - min) / g.lights_steps;255lights1 = constrain_float(lights1 + step, min, max);256}257break;258case JSButton::button_function_t::k_lights1_dimmer:259if (!held) {260RC_Channel* chan = RC_Channels::rc_channel(8);261uint16_t min = chan->get_radio_min();262uint16_t max = chan->get_radio_max();263uint16_t step = (max - min) / g.lights_steps;264lights1 = constrain_float(lights1 - step, min, max);265}266break;267case JSButton::button_function_t::k_lights2_cycle:268if (!held) {269static bool increasing = true;270RC_Channel* chan = RC_Channels::rc_channel(9);271uint16_t min = chan->get_radio_min();272uint16_t max = chan->get_radio_max();273uint16_t step = (max - min) / g.lights_steps;274if (increasing) {275lights2 = constrain_float(lights2 + step, min, max);276} else {277lights2 = constrain_float(lights2 - step, min, max);278}279if (lights2 >= max || lights2 <= min) {280increasing = !increasing;281}282}283break;284case JSButton::button_function_t::k_lights2_brighter:285if (!held) {286RC_Channel* chan = RC_Channels::rc_channel(9);287uint16_t min = chan->get_radio_min();288uint16_t max = chan->get_radio_max();289uint16_t step = (max - min) / g.lights_steps;290lights2 = constrain_float(lights2 + step, min, max);291}292break;293case JSButton::button_function_t::k_lights2_dimmer:294if (!held) {295RC_Channel* chan = RC_Channels::rc_channel(9);296uint16_t min = chan->get_radio_min();297uint16_t max = chan->get_radio_max();298uint16_t step = (max - min) / g.lights_steps;299lights2 = constrain_float(lights2 - step, min, max);300}301break;302case JSButton::button_function_t::k_gain_toggle:303if (!held) {304static bool lowGain = false;305lowGain = !lowGain;306if (lowGain) {307gain = 0.5f;308} else {309gain = 1.0f;310}311gcs().send_text(MAV_SEVERITY_INFO,"#Gain: %2.0f%%",(double)gain*100);312}313break;314case JSButton::button_function_t::k_gain_inc:315if (!held) {316// check that our gain parameters are in correct range, update in eeprom and notify gcs if needed317g.minGain.set_and_save(constrain_float(g.minGain, 0.10, 0.80));318g.maxGain.set_and_save(constrain_float(g.maxGain, g.minGain, 1.0));319g.numGainSettings.set_and_save(constrain_int16(g.numGainSettings, 1, 10));320321if (g.numGainSettings == 1) {322gain = constrain_float(g.gain_default, g.minGain, g.maxGain);323} else {324gain = constrain_float(gain + (g.maxGain-g.minGain)/(g.numGainSettings-1), g.minGain, g.maxGain);325}326327gcs().send_text(MAV_SEVERITY_INFO,"#Gain is %2.0f%%",(double)gain*100);328}329break;330case JSButton::button_function_t::k_gain_dec:331if (!held) {332// check that our gain parameters are in correct range, update in eeprom and notify gcs if needed333g.minGain.set_and_save(constrain_float(g.minGain, 0.10, 0.80));334g.maxGain.set_and_save(constrain_float(g.maxGain, g.minGain, 1.0));335g.numGainSettings.set_and_save(constrain_int16(g.numGainSettings, 1, 10));336337if (g.numGainSettings == 1) {338gain = constrain_float(g.gain_default, g.minGain, g.maxGain);339} else {340gain = constrain_float(gain - (g.maxGain-g.minGain)/(g.numGainSettings-1), g.minGain, g.maxGain);341}342343gcs().send_text(MAV_SEVERITY_INFO,"#Gain is %2.0f%%",(double)gain*100);344}345break;346case JSButton::button_function_t::k_trim_roll_inc:347rollTrim = constrain_float(rollTrim+10,-200,200);348break;349case JSButton::button_function_t::k_trim_roll_dec:350rollTrim = constrain_float(rollTrim-10,-200,200);351break;352case JSButton::button_function_t::k_trim_pitch_inc:353pitchTrim = constrain_float(pitchTrim+10,-200,200);354break;355case JSButton::button_function_t::k_trim_pitch_dec:356pitchTrim = constrain_float(pitchTrim-10,-200,200);357break;358case JSButton::button_function_t::k_input_hold_set:359if(!motors.armed()) {360break;361}362if (!held) {363zTrim = abs(z_last-500) > 50 ? z_last-500 : 0;364xTrim = abs(x_last) > 50 ? x_last : 0;365yTrim = abs(y_last) > 50 ? y_last : 0;366bool input_hold_engaged_last = input_hold_engaged;367input_hold_engaged = zTrim || xTrim || yTrim;368if (input_hold_engaged) {369gcs().send_text(MAV_SEVERITY_INFO,"#Input Hold Set");370} else if (input_hold_engaged_last) {371gcs().send_text(MAV_SEVERITY_INFO,"#Input Hold Disabled");372}373controls_reset_since_input_hold = !input_hold_engaged;374}375break;376#if AP_RELAY_ENABLED377case JSButton::button_function_t::k_relay_1_on:378relay.on(0);379break;380case JSButton::button_function_t::k_relay_1_off:381relay.off(0);382break;383case JSButton::button_function_t::k_relay_1_toggle:384if (!held) {385relay.toggle(0);386}387break;388case JSButton::button_function_t::k_relay_1_momentary:389if (!held) {390relay.on(0);391}392break;393case JSButton::button_function_t::k_relay_2_on:394relay.on(1);395break;396case JSButton::button_function_t::k_relay_2_off:397relay.off(1);398break;399case JSButton::button_function_t::k_relay_2_toggle:400if (!held) {401relay.toggle(1);402}403break;404case JSButton::button_function_t::k_relay_2_momentary:405if (!held) {406relay.on(1);407}408break;409case JSButton::button_function_t::k_relay_3_on:410relay.on(2);411break;412case JSButton::button_function_t::k_relay_3_off:413relay.off(2);414break;415case JSButton::button_function_t::k_relay_3_toggle:416if (!held) {417relay.toggle(2);418}419break;420case JSButton::button_function_t::k_relay_3_momentary:421if (!held) {422relay.on(2);423}424break;425case JSButton::button_function_t::k_relay_4_on:426relay.on(3);427break;428case JSButton::button_function_t::k_relay_4_off:429relay.off(3);430break;431case JSButton::button_function_t::k_relay_4_toggle:432if (!held) {433relay.toggle(3);434}435break;436case JSButton::button_function_t::k_relay_4_momentary:437if (!held) {438relay.on(3);439}440break;441#endif442443////////////////////////////////////////////////444// Servo functions445// TODO: initialize446#if AP_SERVORELAYEVENTS_ENABLED447case JSButton::button_function_t::k_servo_1_inc:448{449SRV_Channel* chan = SRV_Channels::srv_channel(SERVO_CHAN_1 - 1); // 0-indexed450uint16_t pwm_out = hal.rcout->read(SERVO_CHAN_1 - 1); // 0-indexed451pwm_out = constrain_int16(pwm_out + 50, chan->get_output_min(), chan->get_output_max());452ServoRelayEvents.do_set_servo(SERVO_CHAN_1, pwm_out); // 1-indexed453}454break;455case JSButton::button_function_t::k_servo_1_dec:456{457SRV_Channel* chan = SRV_Channels::srv_channel(SERVO_CHAN_1 - 1); // 0-indexed458uint16_t pwm_out = hal.rcout->read(SERVO_CHAN_1 - 1); // 0-indexed459pwm_out = constrain_int16(pwm_out - 50, chan->get_output_min(), chan->get_output_max());460ServoRelayEvents.do_set_servo(SERVO_CHAN_1, pwm_out); // 1-indexed461}462break;463case JSButton::button_function_t::k_servo_1_min:464case JSButton::button_function_t::k_servo_1_min_momentary:465{466SRV_Channel* chan = SRV_Channels::srv_channel(SERVO_CHAN_1 - 1); // 0-indexed467ServoRelayEvents.do_set_servo(SERVO_CHAN_1, chan->get_output_min()); // 1-indexed468}469break;470case JSButton::button_function_t::k_servo_1_min_toggle:471if(!held) {472SRV_Channel* chan = SRV_Channels::srv_channel(SERVO_CHAN_1 - 1); // 0-indexed473if(chan->get_output_pwm() != chan->get_output_min()) {474ServoRelayEvents.do_set_servo(SERVO_CHAN_1, chan->get_output_min()); // 1-indexed475} else {476ServoRelayEvents.do_set_servo(SERVO_CHAN_1, chan->get_trim()); // 1-indexed477}478}479break;480case JSButton::button_function_t::k_servo_1_max:481case JSButton::button_function_t::k_servo_1_max_momentary:482{483SRV_Channel* chan = SRV_Channels::srv_channel(SERVO_CHAN_1 - 1); // 0-indexed484ServoRelayEvents.do_set_servo(SERVO_CHAN_1, chan->get_output_max()); // 1-indexed485}486break;487case JSButton::button_function_t::k_servo_1_max_toggle:488if(!held) {489SRV_Channel* chan = SRV_Channels::srv_channel(SERVO_CHAN_1 - 1); // 0-indexed490if(chan->get_output_pwm() != chan->get_output_max()) {491ServoRelayEvents.do_set_servo(SERVO_CHAN_1, chan->get_output_max()); // 1-indexed492} else {493ServoRelayEvents.do_set_servo(SERVO_CHAN_1, chan->get_trim()); // 1-indexed494}495}496break;497case JSButton::button_function_t::k_servo_1_center:498{499SRV_Channel* chan = SRV_Channels::srv_channel(SERVO_CHAN_1 - 1); // 0-indexed500ServoRelayEvents.do_set_servo(SERVO_CHAN_1, chan->get_trim()); // 1-indexed501}502break;503504case JSButton::button_function_t::k_servo_2_inc:505{506SRV_Channel* chan = SRV_Channels::srv_channel(SERVO_CHAN_2 - 1); // 0-indexed507uint16_t pwm_out = hal.rcout->read(SERVO_CHAN_2 - 1); // 0-indexed508pwm_out = constrain_int16(pwm_out + 50, chan->get_output_min(), chan->get_output_max());509ServoRelayEvents.do_set_servo(SERVO_CHAN_2, pwm_out); // 1-indexed510}511break;512case JSButton::button_function_t::k_servo_2_dec:513{514SRV_Channel* chan = SRV_Channels::srv_channel(SERVO_CHAN_2 - 1); // 0-indexed515uint16_t pwm_out = hal.rcout->read(SERVO_CHAN_2 - 1); // 0-indexed516pwm_out = constrain_int16(pwm_out - 50, chan->get_output_min(), chan->get_output_max());517ServoRelayEvents.do_set_servo(SERVO_CHAN_2, pwm_out); // 1-indexed518}519break;520case JSButton::button_function_t::k_servo_2_min:521case JSButton::button_function_t::k_servo_2_min_momentary:522{523SRV_Channel* chan = SRV_Channels::srv_channel(SERVO_CHAN_2 - 1); // 0-indexed524ServoRelayEvents.do_set_servo(SERVO_CHAN_2, chan->get_output_min()); // 1-indexed525}526break;527case JSButton::button_function_t::k_servo_2_min_toggle:528if(!held) {529SRV_Channel* chan = SRV_Channels::srv_channel(SERVO_CHAN_2 - 1); // 0-indexed530if(chan->get_output_pwm() != chan->get_output_min()) {531ServoRelayEvents.do_set_servo(SERVO_CHAN_2, chan->get_output_min()); // 1-indexed532} else {533ServoRelayEvents.do_set_servo(SERVO_CHAN_2, chan->get_trim()); // 1-indexed534}535}536break;537case JSButton::button_function_t::k_servo_2_max:538case JSButton::button_function_t::k_servo_2_max_momentary:539{540SRV_Channel* chan = SRV_Channels::srv_channel(SERVO_CHAN_2 - 1); // 0-indexed541ServoRelayEvents.do_set_servo(SERVO_CHAN_2, chan->get_output_max()); // 1-indexed542}543break;544case JSButton::button_function_t::k_servo_2_max_toggle:545if(!held) {546SRV_Channel* chan = SRV_Channels::srv_channel(SERVO_CHAN_2 - 1); // 0-indexed547if(chan->get_output_pwm() != chan->get_output_max()) {548ServoRelayEvents.do_set_servo(SERVO_CHAN_2, chan->get_output_max()); // 1-indexed549} else {550ServoRelayEvents.do_set_servo(SERVO_CHAN_2, chan->get_trim()); // 1-indexed551}552}553break;554case JSButton::button_function_t::k_servo_2_center:555{556SRV_Channel* chan = SRV_Channels::srv_channel(SERVO_CHAN_2 - 1); // 0-indexed557ServoRelayEvents.do_set_servo(SERVO_CHAN_2, chan->get_trim()); // 1-indexed558}559break;560561case JSButton::button_function_t::k_servo_3_inc:562{563SRV_Channel* chan = SRV_Channels::srv_channel(SERVO_CHAN_3 - 1); // 0-indexed564uint16_t pwm_out = hal.rcout->read(SERVO_CHAN_3 - 1); // 0-indexed565pwm_out = constrain_int16(pwm_out + 50, chan->get_output_min(), chan->get_output_max());566ServoRelayEvents.do_set_servo(SERVO_CHAN_3, pwm_out); // 1-indexed567}568break;569case JSButton::button_function_t::k_servo_3_dec:570{571SRV_Channel* chan = SRV_Channels::srv_channel(SERVO_CHAN_3 - 1); // 0-indexed572uint16_t pwm_out = hal.rcout->read(SERVO_CHAN_3 - 1); // 0-indexed573pwm_out = constrain_int16(pwm_out - 50, chan->get_output_min(), chan->get_output_max());574ServoRelayEvents.do_set_servo(SERVO_CHAN_3, pwm_out); // 1-indexed575}576break;577case JSButton::button_function_t::k_servo_3_min:578case JSButton::button_function_t::k_servo_3_min_momentary:579{580SRV_Channel* chan = SRV_Channels::srv_channel(SERVO_CHAN_3 - 1); // 0-indexed581ServoRelayEvents.do_set_servo(SERVO_CHAN_3, chan->get_output_min()); // 1-indexed582}583break;584case JSButton::button_function_t::k_servo_3_min_toggle:585if(!held) {586SRV_Channel* chan = SRV_Channels::srv_channel(SERVO_CHAN_3 - 1); // 0-indexed587if(chan->get_output_pwm() != chan->get_output_min()) {588ServoRelayEvents.do_set_servo(SERVO_CHAN_3, chan->get_output_min()); // 1-indexed589} else {590ServoRelayEvents.do_set_servo(SERVO_CHAN_3, chan->get_trim()); // 1-indexed591}592}593break;594case JSButton::button_function_t::k_servo_3_max:595case JSButton::button_function_t::k_servo_3_max_momentary:596{597SRV_Channel* chan = SRV_Channels::srv_channel(SERVO_CHAN_3 - 1); // 0-indexed598ServoRelayEvents.do_set_servo(SERVO_CHAN_3, chan->get_output_max()); // 1-indexed599}600break;601case JSButton::button_function_t::k_servo_3_max_toggle:602if(!held) {603SRV_Channel* chan = SRV_Channels::srv_channel(SERVO_CHAN_3 - 1); // 0-indexed604if(chan->get_output_pwm() != chan->get_output_max()) {605ServoRelayEvents.do_set_servo(SERVO_CHAN_3, chan->get_output_max()); // 1-indexed606} else {607ServoRelayEvents.do_set_servo(SERVO_CHAN_3, chan->get_trim()); // 1-indexed608}609}610break;611case JSButton::button_function_t::k_servo_3_center:612{613SRV_Channel* chan = SRV_Channels::srv_channel(SERVO_CHAN_3 - 1); // 0-indexed614ServoRelayEvents.do_set_servo(SERVO_CHAN_3, chan->get_trim()); // 1-indexed615}616break;617#endif // AP_SERVORELAYEVENTS_ENABLED618619case JSButton::button_function_t::k_roll_pitch_toggle:620if (!held) {621roll_pitch_flag = !roll_pitch_flag;622if (roll_pitch_flag) {623gcs().send_text(MAV_SEVERITY_INFO, "#Attitude Control");624}625else {626gcs().send_text(MAV_SEVERITY_INFO, "#Movement Control");627}628}629break;630631case JSButton::button_function_t::k_custom_1:632// Not implemented633break;634case JSButton::button_function_t::k_custom_2:635// Not implemented636break;637case JSButton::button_function_t::k_custom_3:638// Not implemented639break;640case JSButton::button_function_t::k_custom_4:641// Not implemented642break;643case JSButton::button_function_t::k_custom_5:644// Not implemented645break;646case JSButton::button_function_t::k_custom_6:647// Not implemented648break;649650#if AP_SCRIPTING_ENABLED651case JSButton::button_function_t::k_script_1:652sub.script_buttons[0].press();653break;654case JSButton::button_function_t::k_script_2:655sub.script_buttons[1].press();656break;657case JSButton::button_function_t::k_script_3:658sub.script_buttons[2].press();659break;660case JSButton::button_function_t::k_script_4:661sub.script_buttons[3].press();662break;663#endif // AP_SCRIPTING_ENABLED664}665}666667void Sub::handle_jsbutton_release(uint8_t _button, bool shift) {668669// Act based on the function assigned to this button670switch (get_button(_button)->function(shift)) {671#if AP_RELAY_ENABLED672case JSButton::button_function_t::k_relay_1_momentary:673relay.off(0);674break;675case JSButton::button_function_t::k_relay_2_momentary:676relay.off(1);677break;678case JSButton::button_function_t::k_relay_3_momentary:679relay.off(2);680break;681case JSButton::button_function_t::k_relay_4_momentary:682relay.off(3);683break;684#endif685#if AP_SERVORELAYEVENTS_ENABLED686case JSButton::button_function_t::k_servo_1_min_momentary:687case JSButton::button_function_t::k_servo_1_max_momentary:688{689SRV_Channel* chan = SRV_Channels::srv_channel(SERVO_CHAN_1 - 1); // 0-indexed690ServoRelayEvents.do_set_servo(SERVO_CHAN_1, chan->get_trim()); // 1-indexed691}692break;693case JSButton::button_function_t::k_servo_2_min_momentary:694case JSButton::button_function_t::k_servo_2_max_momentary:695{696SRV_Channel* chan = SRV_Channels::srv_channel(SERVO_CHAN_2 - 1); // 0-indexed697ServoRelayEvents.do_set_servo(SERVO_CHAN_2, chan->get_trim()); // 1-indexed698}699break;700case JSButton::button_function_t::k_servo_3_min_momentary:701case JSButton::button_function_t::k_servo_3_max_momentary:702{703SRV_Channel* chan = SRV_Channels::srv_channel(SERVO_CHAN_3 - 1); // 0-indexed704ServoRelayEvents.do_set_servo(SERVO_CHAN_3, chan->get_trim()); // 1-indexed705}706break;707#endif708709#if AP_SCRIPTING_ENABLED710case JSButton::button_function_t::k_script_1:711sub.script_buttons[0].release();712break;713case JSButton::button_function_t::k_script_2:714sub.script_buttons[1].release();715break;716case JSButton::button_function_t::k_script_3:717sub.script_buttons[2].release();718break;719case JSButton::button_function_t::k_script_4:720sub.script_buttons[3].release();721break;722#endif // AP_SCRIPTING_ENABLED723}724}725726JSButton* Sub::get_button(uint8_t index)727{728// Help to access appropriate parameter729switch (index) {730case 0:731return &g.jbtn_0;732case 1:733return &g.jbtn_1;734case 2:735return &g.jbtn_2;736case 3:737return &g.jbtn_3;738case 4:739return &g.jbtn_4;740case 5:741return &g.jbtn_5;742case 6:743return &g.jbtn_6;744case 7:745return &g.jbtn_7;746case 8:747return &g.jbtn_8;748case 9:749return &g.jbtn_9;750case 10:751return &g.jbtn_10;752case 11:753return &g.jbtn_11;754case 12:755return &g.jbtn_12;756case 13:757return &g.jbtn_13;758case 14:759return &g.jbtn_14;760case 15:761return &g.jbtn_15;762763// add 16 more cases for 32 buttons with MANUAL_CONTROL extensions764case 16:765return &g.jbtn_16;766case 17:767return &g.jbtn_17;768case 18:769return &g.jbtn_18;770case 19:771return &g.jbtn_19;772case 20:773return &g.jbtn_20;774case 21:775return &g.jbtn_21;776case 22:777return &g.jbtn_22;778case 23:779return &g.jbtn_23;780case 24:781return &g.jbtn_24;782case 25:783return &g.jbtn_25;784case 26:785return &g.jbtn_26;786case 27:787return &g.jbtn_27;788case 28:789return &g.jbtn_28;790case 29:791return &g.jbtn_29;792case 30:793return &g.jbtn_30;794case 31:795return &g.jbtn_31;796default:797return &g.jbtn_0;798}799}800801void Sub::default_js_buttons()802{803JSButton::button_function_t defaults[16][2] = {804{JSButton::button_function_t::k_none, JSButton::button_function_t::k_none},805{JSButton::button_function_t::k_mode_manual, JSButton::button_function_t::k_none},806{JSButton::button_function_t::k_mode_depth_hold, JSButton::button_function_t::k_none},807{JSButton::button_function_t::k_mode_stabilize, JSButton::button_function_t::k_none},808809{JSButton::button_function_t::k_disarm, JSButton::button_function_t::k_none},810{JSButton::button_function_t::k_shift, JSButton::button_function_t::k_none},811{JSButton::button_function_t::k_arm, JSButton::button_function_t::k_none},812{JSButton::button_function_t::k_mount_center, JSButton::button_function_t::k_none},813814{JSButton::button_function_t::k_input_hold_set, JSButton::button_function_t::k_none},815{JSButton::button_function_t::k_mount_tilt_down, JSButton::button_function_t::k_mount_pan_left},816{JSButton::button_function_t::k_mount_tilt_up, JSButton::button_function_t::k_mount_pan_right},817{JSButton::button_function_t::k_gain_inc, JSButton::button_function_t::k_trim_pitch_dec},818819{JSButton::button_function_t::k_gain_dec, JSButton::button_function_t::k_trim_pitch_inc},820{JSButton::button_function_t::k_lights1_dimmer, JSButton::button_function_t::k_trim_roll_dec},821{JSButton::button_function_t::k_lights1_brighter, JSButton::button_function_t::k_trim_roll_inc},822{JSButton::button_function_t::k_none, JSButton::button_function_t::k_none},823};824825for (int i = 0; i < 16; i++) {826get_button(i)->set_default(defaults[i][0], defaults[i][1]);827}828}829830void Sub::set_neutral_controls()831{832uint32_t tnow = AP_HAL::millis();833834for (uint8_t i = 0; i < 6; i++) {835RC_Channels::set_override(i, 1500, tnow);836}837838// Clear pitch/roll trim settings839pitchTrim = 0;840rollTrim = 0;841}842843void Sub::clear_input_hold()844{845xTrim = 0;846yTrim = 0;847zTrim = 0;848input_hold_engaged = false;849}850851#if AP_SCRIPTING_ENABLED852bool Sub::is_button_pressed(uint8_t index)853{854return script_buttons[index - 1].is_pressed();855}856857uint8_t Sub::get_and_clear_button_count(uint8_t index)858{859return script_buttons[index - 1].get_and_clear_count();860}861#endif // AP_SCRIPTING_ENABLED862863864