APM1 hardware and Arduplane code Description and Explanation

As I can see on the forum that many people like to understand the code of Arduplane like me. But there's no appropriate documentation on the web because it's hard to understand the software without undrstanding the hardware, so I decide to find out myself. After a lot of code reading and brainstorming I've come to the draft below. For hardware understanding, please look at APM1 block diagram for more information http://diydrones.com/forum/topics/apm-block-diagram?page=1&comm... It's still far from complete however I hope it can help those who likes to understand the code.

ArduPlane.pde -------------- Here only normal flight mode's functions are discussed. HIL modes and telemetry are out of the scope. All the basic system and flight variables and structures are declared at the top of this file. User configurations are in APM_config.h, g defined as Parameter class entity (Parameter.h) static Parameters g; // PID controllers PID pidNavRoll; PID pidServoRoll; PID pidServoPitch; PID pidNavPitchAirspeed; PID pidServoRudder; PID pidTeThrottle; PID pidNavPitchAltitude; From parameters.h it's can be seen that plane's controllers are PID controllers including attitude angle controllers and servo controllers

Outputs from RC receiver are connected to APM1 board inputs (max 8 channel, channel 8 for mode select). From there they are connected to ATMEGA 328 and multiplexer 74LS157. From ATMEGA 328 there's a MUX signal to 74LS157, in case of "HARDWARE MANUAL" mode this signal tells 74LS157 to connect RC receiver's outputs to the servos, otherwise 74LS157 selects signals from ATMEGA 2560. ATMEGA 328 combines 8 PWM channels into 1 PPM output. Due to the fact that PPM channel frequency = sevro update frequency = 50 Hz, so the PPM cycle is 20 ms and the maximum PWM pulsewidth is 1900us = 1.9 ms, so maximum 10 PWM channels can be combined into 1 PPM channel. This PPM channel from ATMEGA 328 is used to interrupt ATMEGA 2560. Each time there's a PPM pulse, an interrupt is generated and APM_RC.cpp ISR(TIMER4) interrupt service routine calculates time intervals between PPM pulses (the ppm pulsewidth) and saves in PPM_RAW[].

As I can see, there's no big change in Arduplane algorithm, so there's not much to update in my description for Arduplane 2.40. May be the obvious change in 2.40 version from 2.26 I can see is that instead of dcm object definition there's ahrs object definition. So in my code description there should be updates: - In fast_loop instead of dcm.update_DCM() it should be ahrs.update(), the same in description of updaing direction cosine matrix with the file libraries/AP_AHRS_DCM.cpp- In calc_bearing_error instead of bearing_error = nav_bearing - dcm.yaw_sensor it should be bearing_error = nav_bearing - ahrs.yaw_sensor; The situation is quite different with APM2 hardware. As this is a completely new hardware, it takes time for me to understand the new hardware. Meanwhile, if someone knows about the new hardware and have time, please share the knowledge. Chris, may I ask you a question? Recently, I raised a question about coding that in get_pid() calls instead of dTnav it should be delta_ms_fast_loop and I got answer from Andrew Tridgell as below:

yep, you're right. Jon Challinger noticed this recently as well. I've been thinking about how to fix it.

It's easy to just fix the deltat of course, but that will change the meaning of the I and D terms in everyones existing configurations (ie. the HDG2RLL_I and HDG2RLL_D values), scaling them by a factor of 5x. That could change how well a plane flies by quite a lot. I'm always reluctant to break existing tuning, but in this case we may have to, with a warning in the release notes.

I'm also thinking about how to ensure this sort of bug doesn't happen again. I think the best way would be to make the PID object compute the deltat itself, rather than passing it in.

Cheers, Tridge ------------

There is still another issue I don't understand, I even rised an issue in DIY Drones but so far got no answer. In calc_nav_pitch() there is a command nav_pitch = -g.pidNavPitchAirspeed.get_pid(airspeed_error, dTnav); (2 parameters call) However, get_pid definition is PID::get_pid(int32_t error, uint16_t dt, float scaler) (3 parameters definition) How can it be like this? Can you explain me?