// move_yaw void AP_MotorsHeli_Single::move_yaw(float yaw_out) { // sanity check yaw_out if (yaw_out < -1.0f) { yaw_out = -1.0f; limit.yaw = true; } if (yaw_out > 1.0f) { yaw_out = 1.0f; limit.yaw = true; } rc_write(AP_MOTORS_MOT_4, calc_pwm_output_1to1(yaw_out, _yaw_servo)); if (_tail_type == AP_MOTORS_HELI_SINGLE_TAILTYPE_SERVO_EXTGYRO) { // output gain to exernal gyro if (_acro_tail && _ext_gyro_gain_acro > 0) { write_aux(_ext_gyro_gain_acro/1000.0f); } else { write_aux(_ext_gyro_gain_std/1000.0f); } } else if (_tail_type == AP_MOTORS_HELI_SINGLE_TAILTYPE_DIRECTDRIVE_FIXEDPITCH && _main_rotor.get_desired_speed() > 0.0f) { // output yaw servo to tail rsc // To-Do: fix this messy calculation write_aux(yaw_out*0.5f+1.0f); } }
// move_yaw void AP_MotorsHeli_Single::move_yaw(float yaw_out) { // sanity check yaw_out if (yaw_out < -1.0f) { yaw_out = -1.0f; limit.yaw = true; } if (yaw_out > 1.0f) { yaw_out = 1.0f; limit.yaw = true; } if (_tail_type == AP_MOTORS_HELI_SINGLE_TAILTYPE_DIRECTDRIVE_FIXEDPITCH){ if (_main_rotor.get_desired_speed() > 0.0f && hal.util->get_soft_armed()) { // constrain output so that motor never fully stops yaw_out = constrain_float(yaw_out, -0.9f, 1.0f); // output yaw servo to tail rsc rc_write(AP_MOTORS_MOT_4, calc_pwm_output_1to1(yaw_out, _yaw_servo)); } else { // output zero speed to tail rsc rc_write(AP_MOTORS_MOT_4, calc_pwm_output_1to1(-1.0f, _yaw_servo)); } } else { rc_write(AP_MOTORS_MOT_4, calc_pwm_output_1to1(yaw_out, _yaw_servo)); } if (_tail_type == AP_MOTORS_HELI_SINGLE_TAILTYPE_SERVO_EXTGYRO) { // output gain to exernal gyro if (_acro_tail && _ext_gyro_gain_acro > 0) { write_aux(_ext_gyro_gain_acro/1000.0f); } else { write_aux(_ext_gyro_gain_std/1000.0f); } } }
// tail_ramp - ramps tail motor towards target. Only used for direct drive variable pitch tails // results put into _tail_direct_drive_out and sent to ESC void AP_MotorsHeli::tail_ramp(int16_t tail_target) { // return immediately if not ramping required if (_tail_type != AP_MOTORS_HELI_TAILTYPE_DIRECTDRIVE_VARPITCH) { _tail_direct_drive_out = tail_target; return; } // range check tail_target tail_target = constrain_int16(tail_target,0,1000); // ramp towards target if (_tail_direct_drive_out < tail_target) { _tail_direct_drive_out += AP_MOTORS_HELI_TAIL_RAMP_INCREMENT; if (_tail_direct_drive_out >= tail_target) { _tail_direct_drive_out = tail_target; } }else if(_tail_direct_drive_out > tail_target) { _tail_direct_drive_out -= AP_MOTORS_HELI_TAIL_RAMP_INCREMENT; if (_tail_direct_drive_out < tail_target) { _tail_direct_drive_out = tail_target; } } // output to tail servo write_aux(_tail_direct_drive_out); }
// rsc_control - update value to send to tail and main rotor's ESC // desired_rotor_speed is a desired speed from 0 to 1000 void AP_MotorsHeli::rsc_control() { // if disarmed output minimums if (!armed()) { // shut down tail rotor if (_tail_type == AP_MOTORS_HELI_TAILTYPE_DIRECTDRIVE_VARPITCH || _tail_type == AP_MOTORS_HELI_TAILTYPE_DIRECTDRIVE_FIXEDPITCH) { _tail_direct_drive_out = 0; write_aux(_tail_direct_drive_out); } // shut down main rotor if (_rsc_mode != AP_MOTORS_HELI_RSC_MODE_NONE) { _rotor_out = 0; _rotor_speed_estimate = 0; write_rsc(_rotor_out); } return; } // ramp up or down main rotor and tail if (_rotor_desired > 0) { // ramp up tail rotor (this does nothing if not using direct drive variable pitch tail) tail_ramp(_direct_drive_tailspeed); // note: this always returns true if not using direct drive variable pitch tail if (tail_rotor_runup_complete()) { rotor_ramp(_rotor_desired); } }else{ // shutting down main rotor rotor_ramp(0); // if completed shutting down main motor then shut-down tail rotor. Note: this does nothing if not using direct drive vairable pitch tail if (_rotor_speed_estimate <= 0) { tail_ramp(0); } } // direct drive fixed pitch tail servo gets copy of yaw servo out (ch4) while main rotor is running if (_tail_type == AP_MOTORS_HELI_TAILTYPE_DIRECTDRIVE_FIXEDPITCH) { // output fixed-pitch speed control if Ch8 is high if (_rotor_desired > 0 || _rotor_speed_estimate > 0) { // copy yaw output to tail esc write_aux(_servo_4->servo_out); }else{ write_aux(0); } } }
/* * paux device driver WRITE entry point. * Write characters to the PS/2 mouse. */ rtems_device_driver paux_write( rtems_device_major_number major, rtems_device_minor_number minor, void *arg) { rtems_libio_rw_args_t *rw_args = (rtems_libio_rw_args_t *)arg; char *buffer = rw_args->buffer; int maximum = rw_args->count; rw_args->bytes_moved = write_aux( minor, buffer, maximum ); return RTEMS_SUCCESSFUL; } /* tty_write */
// output_test - wiggle servos in order to show connections are correct void AP_MotorsHeli::output_test() { int16_t i; // Send minimum values to all motors output_min(); // servo 1 for( i=0; i<5; i++ ) { hal.rcout->write(_motor_to_channel_map[AP_MOTORS_MOT_1], _servo_1->radio_trim + 100); hal.scheduler->delay(300); hal.rcout->write(_motor_to_channel_map[AP_MOTORS_MOT_1], _servo_1->radio_trim - 100); hal.scheduler->delay(300); hal.rcout->write(_motor_to_channel_map[AP_MOTORS_MOT_1], _servo_1->radio_trim + 0); hal.scheduler->delay(300); } // servo 2 for( i=0; i<5; i++ ) { hal.rcout->write(_motor_to_channel_map[AP_MOTORS_MOT_2], _servo_2->radio_trim + 100); hal.scheduler->delay(300); hal.rcout->write(_motor_to_channel_map[AP_MOTORS_MOT_2], _servo_2->radio_trim - 100); hal.scheduler->delay(300); hal.rcout->write(_motor_to_channel_map[AP_MOTORS_MOT_2], _servo_2->radio_trim + 0); hal.scheduler->delay(300); } // servo 3 for( i=0; i<5; i++ ) { hal.rcout->write(_motor_to_channel_map[AP_MOTORS_MOT_3], _servo_3->radio_trim + 100); hal.scheduler->delay(300); hal.rcout->write(_motor_to_channel_map[AP_MOTORS_MOT_3], _servo_3->radio_trim - 100); hal.scheduler->delay(300); hal.rcout->write(_motor_to_channel_map[AP_MOTORS_MOT_3], _servo_3->radio_trim + 0); hal.scheduler->delay(300); } // external gyro if (_tail_type == AP_MOTORS_HELI_TAILTYPE_SERVO_EXTGYRO) { write_aux(_ext_gyro_gain); } // servo 4 for( i=0; i<5; i++ ) { hal.rcout->write(_motor_to_channel_map[AP_MOTORS_MOT_4], _servo_4->radio_trim + 100); hal.scheduler->delay(300); hal.rcout->write(_motor_to_channel_map[AP_MOTORS_MOT_4], _servo_4->radio_trim - 100); hal.scheduler->delay(300); hal.rcout->write(_motor_to_channel_map[AP_MOTORS_MOT_4], _servo_4->radio_trim + 0); hal.scheduler->delay(300); } // Send minimum values to all motors output_min(); }
// move_yaw void AP_MotorsHeli_Single::move_yaw(int16_t yaw_out) { _yaw_servo.servo_out = constrain_int16(yaw_out, -4500, 4500); if (_yaw_servo.servo_out != yaw_out) { limit.yaw = true; } _yaw_servo.calc_pwm(); hal.rcout->write(pgm_read_byte(&_motor_to_channel_map[AP_MOTORS_MOT_4]), _yaw_servo.radio_out); if (_tail_type == AP_MOTORS_HELI_SINGLE_TAILTYPE_SERVO_EXTGYRO) { // output gain to exernal gyro write_aux(_ext_gyro_gain); } else if (_tail_type == AP_MOTORS_HELI_SINGLE_TAILTYPE_DIRECTDRIVE_FIXEDPITCH && _main_rotor.get_desired_speed() > 0) { // output yaw servo to tail rsc write_aux(_yaw_servo.servo_out); } }
// output_test - spin a motor at the pwm value specified // motor_seq is the motor's sequence number from 1 to the number of motors on the frame // pwm value is an actual pwm value that will be output, normally in the range of 1000 ~ 2000 void AP_MotorsHeli_Single::output_test(uint8_t motor_seq, int16_t pwm) { // exit immediately if not armed if (!armed()) { return; } // output to motors and servos switch (motor_seq) { case 1: // swash servo 1 rc_write(AP_MOTORS_MOT_1, pwm); break; case 2: // swash servo 2 rc_write(AP_MOTORS_MOT_2, pwm); break; case 3: // swash servo 3 rc_write(AP_MOTORS_MOT_3, pwm); break; case 4: // external gyro & tail servo if (_tail_type == AP_MOTORS_HELI_SINGLE_TAILTYPE_SERVO_EXTGYRO) { if (_acro_tail && _ext_gyro_gain_acro > 0) { write_aux(_ext_gyro_gain_acro/1000.0f); } else { write_aux(_ext_gyro_gain_std/1000.0f); } } rc_write(AP_MOTORS_MOT_4, pwm); break; case 5: // main rotor rc_write(AP_MOTORS_HELI_SINGLE_RSC, pwm); break; default: // do nothing break; } }
// move_yaw void AP_MotorsHeli_Single::move_yaw(int16_t yaw_out) { _yaw_servo.servo_out = constrain_int16(yaw_out, -4500, 4500); if (_yaw_servo.servo_out != yaw_out) { limit.yaw = true; } _yaw_servo.calc_pwm(); rc_write(AP_MOTORS_MOT_4, _yaw_servo.radio_out); if (_tail_type == AP_MOTORS_HELI_SINGLE_TAILTYPE_SERVO_EXTGYRO) { // output gain to exernal gyro if (_acro_tail && _ext_gyro_gain_acro > 0) { write_aux(_ext_gyro_gain_acro); } else { write_aux(_ext_gyro_gain_std); } } else if (_tail_type == AP_MOTORS_HELI_SINGLE_TAILTYPE_DIRECTDRIVE_FIXEDPITCH && _main_rotor.get_desired_speed() > 0) { // output yaw servo to tail rsc write_aux(_yaw_servo.servo_out); } }
// output_test - spin a motor at the pwm value specified // motor_seq is the motor's sequence number from 1 to the number of motors on the frame // pwm value is an actual pwm value that will be output, normally in the range of 1000 ~ 2000 void AP_MotorsHeli::output_test(uint8_t motor_seq, int16_t pwm) { // exit immediately if not armed if (!armed()) { return; } // output to motors and servos switch (motor_seq) { case 1: // swash servo 1 hal.rcout->write(pgm_read_byte(&_motor_to_channel_map[AP_MOTORS_MOT_1]), pwm); break; case 2: // swash servo 2 hal.rcout->write(pgm_read_byte(&_motor_to_channel_map[AP_MOTORS_MOT_2]), pwm); break; case 3: // swash servo 3 hal.rcout->write(pgm_read_byte(&_motor_to_channel_map[AP_MOTORS_MOT_3]), pwm); break; case 4: // external gyro & tail servo if (_tail_type == AP_MOTORS_HELI_TAILTYPE_SERVO_EXTGYRO) { write_aux(_ext_gyro_gain); } hal.rcout->write(pgm_read_byte(&_motor_to_channel_map[AP_MOTORS_MOT_4]), pwm); break; case 5: // main rotor hal.rcout->write(pgm_read_byte(&_motor_to_channel_map[AP_MOTORS_HELI_RSC]), pwm); break; default: // do nothing break; } }
// // heli_move_swash - moves swash plate to attitude of parameters passed in // - expected ranges: // roll : -4500 ~ 4500 // pitch: -4500 ~ 4500 // collective: 0 ~ 1000 // yaw: -4500 ~ 4500 // void AP_MotorsHeli::move_swash(int16_t roll_out, int16_t pitch_out, int16_t coll_in, int16_t yaw_out) { int16_t yaw_offset = 0; int16_t coll_out_scaled; // initialize limits flag limit.roll_pitch = false; limit.yaw = false; limit.throttle_lower = false; limit.throttle_upper = false; if (_servo_manual == 1) { // are we in manual servo mode? (i.e. swash set-up mode)? // check if we need to free up the swash if (_heliflags.swash_initialised) { reset_swash(); } // To-Do: This equation seems to be wrong. It probably restricts swash movement so that swash setup doesn't work right. // _collective_scalar should probably not be used or set to 1? coll_out_scaled = coll_in * _collective_scalar + _throttle_radio_min - 1000; }else{ // regular flight mode // check if we need to reinitialise the swash if (!_heliflags.swash_initialised) { init_swash(); } // rescale roll_out and pitch-out into the min and max ranges to provide linear motion // across the input range instead of stopping when the input hits the constrain value // these calculations are based on an assumption of the user specified roll_max and pitch_max // coming into this equation at 4500 or less, and based on the original assumption of the // total _servo_x.servo_out range being -4500 to 4500. roll_out = roll_out * _roll_scaler; if (roll_out < -_roll_max) { roll_out = -_roll_max; limit.roll_pitch = true; } if (roll_out > _roll_max) { roll_out = _roll_max; limit.roll_pitch = true; } // scale pitch and update limits pitch_out = pitch_out * _pitch_scaler; if (pitch_out < -_pitch_max) { pitch_out = -_pitch_max; limit.roll_pitch = true; } if (pitch_out > _pitch_max) { pitch_out = _pitch_max; limit.roll_pitch = true; } // constrain collective input _collective_out = coll_in; if (_collective_out <= 0) { _collective_out = 0; limit.throttle_lower = true; } if (_collective_out >= 1000) { _collective_out = 1000; limit.throttle_upper = true; } // ensure not below landed/landing collective if (_heliflags.landing_collective && _collective_out < _land_collective_min) { _collective_out = _land_collective_min; limit.throttle_lower = true; } // scale collective pitch coll_out_scaled = _collective_out * _collective_scalar + _collective_min - 1000; // rudder feed forward based on collective // the feed-forward is not required when the motor is shut down and not creating torque // also not required if we are using external gyro if ((_desired_rotor_speed > 0) && _tail_type != AP_MOTORS_HELI_TAILTYPE_SERVO_EXTGYRO) { // sanity check collective_yaw_effect _collective_yaw_effect = constrain_float(_collective_yaw_effect, -AP_MOTOR_HELI_COLYAW_RANGE, AP_MOTOR_HELI_COLYAW_RANGE); yaw_offset = _collective_yaw_effect * abs(_collective_out - _collective_mid_pwm); } } // swashplate servos _servo_1.servo_out = (_rollFactor[CH_1] * roll_out + _pitchFactor[CH_1] * pitch_out)/10 + _collectiveFactor[CH_1] * coll_out_scaled + (_servo_1.radio_trim-1500); _servo_2.servo_out = (_rollFactor[CH_2] * roll_out + _pitchFactor[CH_2] * pitch_out)/10 + _collectiveFactor[CH_2] * coll_out_scaled + (_servo_2.radio_trim-1500); if (_swash_type == AP_MOTORS_HELI_SWASH_H1) { _servo_1.servo_out += 500; _servo_2.servo_out += 500; } _servo_3.servo_out = (_rollFactor[CH_3] * roll_out + _pitchFactor[CH_3] * pitch_out)/10 + _collectiveFactor[CH_3] * coll_out_scaled + (_servo_3.radio_trim-1500); _servo_4.servo_out = yaw_out + yaw_offset; // constrain yaw and update limits if (_servo_4.servo_out < -4500) { _servo_4.servo_out = -4500; limit.yaw = true; } if (_servo_4.servo_out > 4500) { _servo_4.servo_out = 4500; limit.yaw = true; } // use servo_out to calculate pwm_out and radio_out _servo_1.calc_pwm(); _servo_2.calc_pwm(); _servo_3.calc_pwm(); _servo_4.calc_pwm(); // actually move the servos hal.rcout->write(pgm_read_byte(&_motor_to_channel_map[AP_MOTORS_MOT_1]), _servo_1.radio_out); hal.rcout->write(pgm_read_byte(&_motor_to_channel_map[AP_MOTORS_MOT_2]), _servo_2.radio_out); hal.rcout->write(pgm_read_byte(&_motor_to_channel_map[AP_MOTORS_MOT_3]), _servo_3.radio_out); hal.rcout->write(pgm_read_byte(&_motor_to_channel_map[AP_MOTORS_MOT_4]), _servo_4.radio_out); // output gain to exernal gyro if (_tail_type == AP_MOTORS_HELI_TAILTYPE_SERVO_EXTGYRO) { write_aux(_ext_gyro_gain); } }
// // heli_move_swash - moves swash plate to attitude of parameters passed in // - expected ranges: // roll : -4500 ~ 4500 // pitch: -4500 ~ 4500 // collective: 0 ~ 1000 // yaw: -4500 ~ 4500 // void AP_MotorsHeli::move_swash(int16_t roll_out, int16_t pitch_out, int16_t coll_in, int16_t yaw_out) { int16_t yaw_offset = 0; int16_t coll_out_scaled; // initialize limits flag limit.roll_pitch = false; limit.yaw = false; limit.throttle_lower = false; limit.throttle_upper = false; if (_servo_manual == 1) { // are we in manual servo mode? (i.e. swash set-up mode)? // check if we need to free up the swash if (_heliflags.swash_initialised) { reset_swash(); } coll_out_scaled = coll_in * _collective_scalar + _rc_throttle->radio_min - 1000; }else{ // regular flight mode // check if we need to reinitialise the swash if (!_heliflags.swash_initialised) { init_swash(); } // rescale roll_out and pitch-out into the min and max ranges to provide linear motion // across the input range instead of stopping when the input hits the constrain value // these calculations are based on an assumption of the user specified roll_max and pitch_max // coming into this equation at 4500 or less, and based on the original assumption of the // total _servo_x.servo_out range being -4500 to 4500. roll_out = roll_out * _roll_scaler; if (roll_out < -_roll_max) { roll_out = -_roll_max; limit.roll_pitch = true; } if (roll_out > _roll_max) { roll_out = _roll_max; limit.roll_pitch = true; } // scale pitch and update limits pitch_out = pitch_out * _pitch_scaler; if (pitch_out < -_pitch_max) { pitch_out = -_pitch_max; limit.roll_pitch = true; } if (pitch_out > _pitch_max) { pitch_out = _pitch_max; limit.roll_pitch = true; } // constrain collective input _collective_out = coll_in; if (_collective_out <= 0) { _collective_out = 0; limit.throttle_lower = true; } if (_collective_out >= 1000) { _collective_out = 1000; limit.throttle_upper = true; } // ensure not below landed/landing collective if (_heliflags.landing_collective && _collective_out < _land_collective_min) { _collective_out = _land_collective_min; limit.throttle_lower = true; } // scale collective pitch coll_out_scaled = _collective_out * _collective_scalar + _collective_min - 1000; // rudder feed forward based on collective // the feed-forward is not required when the motor is shut down and not creating torque // also not required if we are using external gyro if (motor_runup_complete() && _tail_type != AP_MOTORS_HELI_TAILTYPE_SERVO_EXTGYRO) { yaw_offset = _collective_yaw_effect * abs(_collective_out - _collective_mid_pwm); } } // swashplate servos _servo_1->servo_out = (_rollFactor[CH_1] * roll_out + _pitchFactor[CH_1] * pitch_out)/10 + _collectiveFactor[CH_1] * coll_out_scaled + (_servo_1->radio_trim-1500); _servo_2->servo_out = (_rollFactor[CH_2] * roll_out + _pitchFactor[CH_2] * pitch_out)/10 + _collectiveFactor[CH_2] * coll_out_scaled + (_servo_2->radio_trim-1500); if (_swash_type == AP_MOTORS_HELI_SWASH_H1) { _servo_1->servo_out += 500; _servo_2->servo_out += 500; } _servo_3->servo_out = (_rollFactor[CH_3] * roll_out + _pitchFactor[CH_3] * pitch_out)/10 + _collectiveFactor[CH_3] * coll_out_scaled + (_servo_3->radio_trim-1500); _servo_4->servo_out = yaw_out + yaw_offset; // constrain yaw and update limits if (_servo_4->servo_out < -4500) { _servo_4->servo_out = -4500; limit.yaw = true; } if (_servo_4->servo_out > 4500) { _servo_4->servo_out = 4500; limit.yaw = true; } // use servo_out to calculate pwm_out and radio_out _servo_1->calc_pwm(); _servo_2->calc_pwm(); _servo_3->calc_pwm(); _servo_4->calc_pwm(); // actually move the servos hal.rcout->write(_motor_to_channel_map[AP_MOTORS_MOT_1], _servo_1->radio_out); hal.rcout->write(_motor_to_channel_map[AP_MOTORS_MOT_2], _servo_2->radio_out); hal.rcout->write(_motor_to_channel_map[AP_MOTORS_MOT_3], _servo_3->radio_out); hal.rcout->write(_motor_to_channel_map[AP_MOTORS_MOT_4], _servo_4->radio_out); // output gain to exernal gyro if (_tail_type == AP_MOTORS_HELI_TAILTYPE_SERVO_EXTGYRO) { write_aux(_ext_gyro_gain); } // to be compatible with other frame types motor_out[AP_MOTORS_MOT_1] = _servo_1->radio_out; motor_out[AP_MOTORS_MOT_2] = _servo_2->radio_out; motor_out[AP_MOTORS_MOT_3] = _servo_3->radio_out; motor_out[AP_MOTORS_MOT_4] = _servo_4->radio_out; }