{"id":272850,"date":"2016-01-25T17:55:02","date_gmt":"2016-01-25T14:55:02","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=272850"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=272850","title":{"rendered":"Alt Hold \u0434\u043b\u044f CC3D \u043f\u043e\u043b\u0435\u0442\u043d\u043e\u0433\u043e \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u0430 \u043d\u0430 \u0411\u0430\u0440\u043e"},"content":{"rendered":"<p>       \u0414\u0443\u043c\u0430\u044e, \u044f \u043d\u0435 \u043e\u0442\u043a\u0440\u043e\u044e \u0430\u043c\u0435\u0440\u0438\u043a\u0438. \u041d\u043e \u043a\u043e\u0433\u0434\u0430 \u0443 \u043c\u0435\u043d\u044f \u0432\u043e\u0437\u043d\u0438\u043a\u043b\u0430 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0441\u0442\u044c \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0441\u0442\u0430\u0431\u0438\u043b\u0438\u0437\u0430\u0446\u0438\u044e \u043f\u043e \u0432\u044b\u0441\u043e\u0442\u0435 \u0441 \u0431\u0430\u0440\u043e \u0434\u043b\u044f CC3D, \u0440\u0435\u0448\u0435\u043d\u0438\u0435 \u043d\u0435 \u043d\u0430\u0448\u043b\u043e\u0441\u044c. \u0411\u044b\u043b\u0438 \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u044b \u043f\u0435\u0440\u0435\u043f\u0440\u043e\u0448\u0438\u0442\u044c \u0435\u0433\u043e \u0441 OpenPilot \u043d\u0430 \u0447\u0442\u043e \u0442\u043e \u0434\u0440\u0443\u0433\u043e\u0435, \u0438 \u0442\u0430\u043c \u0435\u0441\u0442\u044c \u0442\u0430\u043a\u0438\u0435 \u0432\u0435\u0449\u0438. \u041d\u043e \u044f \u0440\u0435\u0448\u0438\u043b \u043f\u043e\u0439\u0442\u0438 \u043d\u0435 \u0441\u0430\u043c\u044b\u043c \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u044b\u043c \u0438 \u043b\u0435\u0433\u043a\u0438\u043c \u0441\u043f\u043e\u0441\u043e\u0431\u043e\u043c. \u041c\u043e\u0435 \u0440\u0435\u0448\u0435\u043d\u0438\u0435 \u2014 \u044d\u0442\u043e \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440 \u043c\u0435\u0436\u0434\u0443 \u043f\u0440\u0438\u0435\u043c\u043d\u0438\u043a\u043e\u043c \u0438 CC3D (\u0438\u043b\u0438 \u043b\u044e\u0431\u044b\u043c \u0434\u0440\u0443\u0433\u0438\u043c), \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043c\u0435\u0440\u044f\u0435\u0442 \u0432\u044b\u0441\u043e\u0442\u0443 \u0438 \u0432\u043d\u043e\u0441\u0438\u0442 \u043a\u043e\u0440\u0440\u0435\u043a\u0442\u0438\u0440\u043e\u0432\u043a\u0443 \u0432 \u043a\u0430\u043d\u0430\u043b \u0433\u0430\u0437\u0430, \u0430 \u0437\u0430\u0442\u0435\u043c \u043f\u0435\u0440\u0435\u0434\u0430\u0435\u0442 \u0435\u0435 \u0432 \u043f\u043e\u043b\u0435\u0442\u043d\u044b\u0439 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440. \u0422\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c \u0434\u0435\u0440\u0436\u0438\u0442 \u0432\u044b\u0441\u043e\u0442\u0443.<br \/>  <a name=\"habracut\"><\/a><br \/>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/files\/45f\/8f0\/224\/45f8f0224f5041c489899bb56b81b5d6.jpg\"\/><\/p>\n<p>  \u041a\u0430\u043a \u044d\u0442\u043e \u0432\u0441\u0435 \u0441\u043e\u0431\u0438\u0440\u0430\u0435\u0442\u0441\u044f. \u042f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043b \u0434\u0430\u0442\u0447\u0438\u043a \u0434\u0430\u0432\u043b\u0435\u043d\u0438\u044f BMP085 \u2014 \u043d\u0435 \u0441\u0430\u043c\u044b\u0439 \u0442\u043e\u0447\u043d\u044b\u0439, \u043d\u043e \u0437\u0430\u0442\u043e \u0431\u044b\u043b \u0432 \u043d\u0430\u043b\u0438\u0447\u0438\u0438. \u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u043d\u0430 \u0432\u0438\u0434\u0435\u043e \u0432\u0438\u0434\u043d\u044b \u0437\u043d\u0430\u0447\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0435 \u043a\u043e\u043b\u0435\u0431\u0430\u043d\u0438\u044f. \u0422\u0435\u043c \u043d\u0435 \u043c\u0435\u043d\u0435\u0435, \u0432 \u0440\u0430\u0437\u0431\u0440\u043e\u0441\u0435 1 \u043c\u0435\u0442\u0440 \u0432\u044b\u0441\u043e\u0442\u0430 \u0434\u0435\u0440\u0436\u0438\u0442\u0441\u044f.<\/p>\n<p>  BMP085 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d \u043f\u043e I2C \u043a Arduino. \u0412\u0445\u043e\u0434\u044b \u04104, \u04105 \u0438 \u043f\u0438\u0442\u0430\u043d\u0438\u0435: \u043f\u0440\u0438\u0435\u043c\u043d\u0438\u043a \u0446\u0435\u043f\u043b\u044f\u0435\u043c \u043a\u043e \u0432\u0445\u043e\u0434\u0430\u043c 2 \u0438 3. \u0412\u044b\u0445\u043e\u0434 \u043d\u0430 CC3D 9 \u0438 10: 9 \u2014 \u044d\u0442\u043e \u043a\u0430\u043d\u0430\u043b Aux1, \u0435\u0441\u043b\u0438 \u043e\u043d \u043d\u0435 \u043d\u0443\u0436\u0435\u043d, \u0442\u043e \u043d\u0430 \u043f\u043e\u043b\u0435\u0442\u043d\u044b\u0439 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440 \u0435\u0433\u043e \u043c\u043e\u0436\u043d\u043e \u043d\u0435 \u043f\u0435\u0440\u0435\u0434\u0430\u0432\u0430\u0442\u044c.<\/p>\n<p>  \u0412 \u043c\u043e\u0435\u043c \u0440\u0435\u0448\u0435\u043d\u0438\u0438 \u044d\u0442\u043e \u0434\u0432\u0443\u0445\u043f\u043e\u0437\u0438\u0446\u0438\u043e\u043d\u043d\u044b\u0439 \u043f\u0435\u0440\u0435\u043a\u043b\u044e\u0447\u0430\u0442\u0435\u043b\u044c \u0434\u043b\u044f \u0430\u043a\u0442\u0438\u0432\u0430\u0446\u0438\u0438 \u0440\u0435\u0436\u0438\u043c\u0430 \u0443\u0434\u0435\u0440\u0436\u0430\u043d\u0438\u044f. \u041b\u0438\u0447\u043d\u043e \u0443 \u043c\u0435\u043d\u044f \u0434\u0430\u043b\u0435\u0435 \u0432 \u043a\u043e\u043f\u0442\u0435\u0440\u0435 \u044d\u0442\u043e\u0442 \u043f\u0435\u0440\u0435\u043a\u043b\u044e\u0447\u0430\u0442\u0435\u043b\u044c \u043d\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f.<\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">\u0441\u043a\u0435\u0447 \u0430\u0440\u0434\u0443\u0438\u043d\u043e:<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"cpp\">\/* Alt Holt with BMP095  * by Aleksandr Stroganov 16.01.2016  *   * In from receiver  * PD2 - AUX1 in  * PD3 - Trl in  *   * Out to CC3D  * PB1 Aux1 out  * PB2 Trl out  *\/ #ifndef F_CPU     #define F_CPU 16000000UL #endif  \/\/I2C and BMP085 #define F_I2C          400000UL                 \/\/\u0427\u0430\u0441\u0442\u043e\u0442\u0430 \u0448\u0438\u043d\u044b I2C #define TWBR_VALUE    (((F_CPU)\/(F_I2C)-16)\/2)  \/\/\u0420\u0430\u0441\u0447\u0435\u0442 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u0434\u043b\u044f \u0436\u0435\u043b\u0430\u0435\u043c\u043e\u0439 \u0447\u0438\u0441\u0442\u043e\u0442\u044b #define BMP085_ADDRESS 0x77                     \/\/ I2C address of BMP085 const unsigned char OSS = 3;                    \/\/ Oversampling Setting  \/\/ BMP085 Calibration values int ac1; int ac2; int ac3; unsigned int ac4; unsigned int ac5; unsigned int ac6; int b1; int b2; int mb; int mc; int md; \/\/ b5 is calculated in bmp085GetTemperature(...), this variable is also used in bmp085GetPressure(...) \/\/ so ...Temperature(...) must be called before ...Pressure(...). long b5;  \/\/ Loop Flag #define TRUE  1 #define FALSE 0  \/\/ Flight Mode #define Manual_Mode  0 #define Alt_Hold     1   volatile unsigned int cnt_rising = 0; volatile unsigned int cnt_falling = 0; volatile unsigned int cnt_thro = 0; volatile unsigned int cnt_FMD = 0; volatile unsigned int t_scale = 0; \/\/\u041c\u043d\u043e\u0436\u0438\u0442\u0435\u043b\u044c \u0447\u0442\u043e\u0431 \u0440\u0430\u0441\u0447\u0438\u0442\u0430\u0442\u044c 40\u0413\u0446  \/\/ LPF #define SamplingTime    0.025     \/\/ Control Loop Period 40Hz float CutOffFrequency = 3.0;      \/\/ Hz float LPF_error       = 0.0; float LPF_ee          = 0.0; float LPF_ee1         = 0.0; float LPF_ww          = 0.0;  \/\/ PID int Thro_Neutral       = 3000;      \/\/ Pulse width when throttle is neutral int Thro_Deadband      = 30;        \/\/ throttle zero when it's in between -30~30 float A_outer_Pgain    = 0.5; float A_inner_Pgain    = 1.5; float A_inner_Igain    = 0.25; float A_inner_Dgain    = 0.0; float Hov_Thro         = 0.0; int THRO_CMD_MAX       = 200; int ALT_RATE_ERR_MAX   = 200; int ALT_RATE_I_MAX     = 200; int ALT_PID_MAX        = 400;  byte T_flag = 0; byte FMD_flag = 0;  \/\/\u0420\u0430\u0441\u0447\u0435\u0442 \u043f\u043e \u0432\u044b\u0441\u043e\u0442\u0435 short T;                        \/\/\u0422\u0435\u043c\u043f\u0435\u0440\u0430\u0442\u0443\u0440\u0430 long  P;                        \/\/\u0414\u0430\u0432\u043b\u0435\u043d\u0438\u0435 float H_alt            = 0.0; float H_temp           = 0.0; float Altitude         = 0.0; float Altitude_cm      = 0.0; float Altitude_LPF     = 0.0; float ClimbRate        = 0.0; float pre_Altitude_LPF = 0.0;   int Thro_cmd           = 0;  long Thro_in           = 0; float ALT_ERR          = 0.0; float ALT_RATE_ERR     = 0.0; float ALT_RATE_P       = 0.0; float ALT_RATE_I       = 0.0; float ALT_RATE_D       = 0.0; float pre_ALT_RATE_ERR = 0.0; float ALT_PID          = 0.0; float ALT_cont         = 0.0;   void Port_init() {     \/\/DDRD |= 0x00;         \/\/ INT 0,1 \u043d\u0430\u0441\u0442\u0440\u0430\u0438\u0432\u0430\u0435\u043c \u043d\u0430 \u0432\u0445\u043e\u0434     \/\/PORTD = 0b00001100;   \/\/ INT 0,1 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0430\u0435\u043c \u043f\u043e\u0434\u0442\u044f\u0433\u0438\u0432\u0430\u044e\u0449\u0438\u0435 \u0440\u0435\u0437\u0438\u0441\u0442\u043e\u0440\u044b              DDRD = (0 &lt;&lt; DDD2)|(0 &lt;&lt; DDD3);       \/\/ INT 0,1 \u043d\u0430\u0441\u0442\u0440\u0430\u0438\u0432\u0430\u0435\u043c \u043d\u0430 \u0432\u0445\u043e\u0434     PORTD = (1 &lt;&lt; PORTD2)|(1 &lt;&lt; PORTD3);  \/\/ INT 0,1 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0430\u0435\u043c \u043f\u043e\u0434\u0442\u044f\u0433\u0438\u0432\u0430\u044e\u0449\u0438\u0435 \u0440\u0435\u0437\u0438\u0441\u0442\u043e\u0440\u044b     EIMSK = 0b00000011;                   \/\/ INT 0,1 \u0412\u043d\u0435\u0448\u043d\u0435\u0435 \u043f\u0440\u0435\u0440\u044b\u0432\u0430\u043d\u0438\u0435 \u0438\u043d\u0434\u0438\u0432\u0438\u0434\u0443\u0430\u043b\u044c\u043d\u043e\u0435 \u0440\u0430\u0437\u0440\u0435\u0448\u0435\u043d\u0438\u0435     EICRA = 0b00001111;                   \/\/ INT 0,1 - rising edge \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u0442\u0440\u0438\u0433\u0433\u0435\u0440\u043e\u0432 }   void Timer1_init() {     DDRB |= 0b00000110;\t\t  \/\/ OC1A, OC1B \u0423\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u0435 \u0432\u044b\u0445\u043e\u0434\u043d\u043e\u0439 \u043d\u0430\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0432\u044b\u0432\u043e\u0434\u043e\u0432     TCCR1A = 0b10100010;\t  \/\/ Fast PWM \u0423\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c \u0440\u0435\u0436\u0438\u043c \u0440\u0430\u0431\u043e\u0442\u044b     TCCR1B = 0b00011010;\t  \/\/ Fast PWM 14 mode, 8 sclaer.     ICR1 = 40000;           \/\/ 20ms, 50Hz period }  void Timer2_init() {     TCCR2A = 0b00000011;    \/\/ Fast PWM, No OC output, \u0423\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c \u0440\u0435\u0436\u0438\u043c \u0440\u0430\u0431\u043e\u0442\u044b     TCCR2B = 0b00001100;    \/\/ Fast PWM 7 mode, 64 sclaer.     OCR2A = 250;            \/\/ 1ms, 1000Hz period     TIMSK2 = 0b00000001; }    ISR(INT0_vect)\t\t\t\t\/\/ Flight Mode \u0432\u0445\u043e\u0434 {     if(EICRA == 0b00001111){         cnt_rising = TCNT1;         EICRA = 0b00001110;     }     else{         cnt_falling = TCNT1;         cnt_FMD = (40001 - cnt_rising + cnt_falling) % 40001;         EICRA = 0b00001111; \t} }  ISR(INT1_vect)\t\t\t\t\/\/ Throttle \u0432\u0445\u043e\u0434 {     if(EICRA == 0b00001111){         cnt_rising = TCNT1;         EICRA = 0b00001011;     }     else{         cnt_falling = TCNT1;         cnt_thro = (40001 - cnt_rising + cnt_falling) % 40001;         EICRA = 0b00001111;     } }  ISR(TIMER2_OVF_vect)        \/\/ 1000\u0413\u0446 \u041f\u0440\u0435\u0432\u0440\u0430\u0449\u0430\u0435\u043c \u0432 40\u0413\u0446 \u0438 \u0441\u0442\u0430\u0432\u0438\u043c \u0444\u043b\u0430\u0433 \u0440\u0430\u0441\u0447\u0435\u0442\u0430 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u043e\u0432 {     t_scale ++;     if(t_scale == 25){         t_scale = 0;         T_flag = TRUE;     } }   byte FMD_check(unsigned int FMD_in) \/\/\u0424\u0443\u043d\u043a\u0446\u0438\u044f \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u0440\u0435\u0436\u0438\u043c\u0430 \u043f\u043e\u043b\u0435\u0442\u0430 {     byte FMD_out;     if(FMD_in &gt; 2150 && FMD_in &lt; 2900)     {         FMD_out = 1;     }     else if(FMD_in &gt; 2900 && FMD_in &lt; 3700)     {         FMD_out = 1;             }     else     {         FMD_out = 0;        \/\/ \u0420\u0443\u0447\u043d\u043e\u0439 \u0440\u0435\u0436\u0438\u043c.     }     return FMD_out; }  void Limit_cut(float *ff, int MIN_LIMIT, int MAX_LIMIT) {     if(*ff &lt; MIN_LIMIT)     {         *ff = MIN_LIMIT;     }     else if(*ff &gt; MAX_LIMIT)     {         *ff = MAX_LIMIT;     } }  void Limit_cut_int(int *ff, int MIN_LIMIT, int MAX_LIMIT) {     if(*ff &lt; MIN_LIMIT)     {         *ff = MIN_LIMIT;     }     else if(*ff &gt; MAX_LIMIT)     {         *ff = MAX_LIMIT;     } }  void Limit_cut_long(long *ff, long int MIN_LIMIT, long int MAX_LIMIT) {     if(*ff &lt; MIN_LIMIT)     {         *ff = MIN_LIMIT;     }     else if(*ff &gt; MAX_LIMIT)     {         *ff = MAX_LIMIT;     } }  void Stick_Deadband(int *Stick, int MIN_RANGE, int MAX_RANGE) {     if(*Stick &gt; MIN_RANGE && *Stick &lt; MAX_RANGE)     {         *Stick = 0;     } }  \/\/\u0418\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u0448\u0438\u043d\u044b I2C  void TWI_Init(void) {   TWBR = TWBR_VALUE;   TWSR = 0x00; }  \/\/ Stores all of the bmp085's calibration values into global variables \/\/ Calibration values are required to calculate temp and pressure \/\/ This function should be called at the beginning of the program void bmp085Calibration() {   ac1 = bmp085ReadInt(0xAA);   ac2 = bmp085ReadInt(0xAC);   ac3 = bmp085ReadInt(0xAE);   ac4 = bmp085ReadInt(0xB0);   ac5 = bmp085ReadInt(0xB2);   ac6 = bmp085ReadInt(0xB4);   b1 =  bmp085ReadInt(0xB6);   b2 =  bmp085ReadInt(0xB8);   mb =  bmp085ReadInt(0xBA);   mc =  bmp085ReadInt(0xBC);   md =  bmp085ReadInt(0xBE); }  \/\/ Read 2 bytes from the BMP085 \/\/ First byte will be from 'address' \/\/ Second byte will be from 'address'+1 int bmp085ReadInt(unsigned char address) {   unsigned char msb, lsb;     TWI_Start();   TWI_Start_SLA_W( BMP085_ADDRESS, address, 0 );   TWI_Stop();    TWI_Start();   TWI_Start_SLA_R( BMP085_ADDRESS );    msb = TWI_Read_Byte( 1 );   lsb = TWI_Read_Byte( 2 );    TWI_Stop();    return (int) msb&lt;&lt;8 | lsb; }  void TWI_Start() {   \/*\u0444\u043e\u0440\u043c\u0438\u0440\u0443\u0435\u043c \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u0421\u0422\u0410\u0420\u0422*\/    TWCR = (1&lt;&lt;TWINT)|(1&lt;&lt;TWSTA)|(1&lt;&lt;TWEN);   while(!(TWCR & (1&lt;&lt;TWINT))); }  char TWI_Start_SLA_R( unsigned char address_i2c ) {   \/*\u0432\u044b\u0434\u0430\u0435\u043c\u043d\u0430 \u0448\u0438\u043d\u0443 \u043f\u0430\u043a\u0435\u0442 SLA-R*\/   TWDR = (address_i2c&lt;&lt;1)|1;   TWCR = (1&lt;&lt;TWINT)|(1&lt;&lt;TWEN);    while(!(TWCR & (1&lt;&lt;TWINT))); }  char TWI_Start_SLA_W( unsigned char address_i2c, unsigned char adr, unsigned char data ) {   \/\/\u0432\u044b\u0434\u0430\u0435\u043c\u043d\u0430 \u0448\u0438\u043d\u0443 \u043f\u0430\u043a\u0435\u0442 SLA-W   TWDR = (address_i2c&lt;&lt;1)|0;   TWCR = (1&lt;&lt;TWINT)|(1&lt;&lt;TWEN)|(1&lt;&lt;TWEA);    while(!(TWCR & (1&lt;&lt;TWINT)));    \/\/\u043f\u0435\u0440\u0435\u0434\u0430\u0435\u043c \u0430\u0434\u0440\u0435\u0441 \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430    TWDR = adr;   TWCR = (1&lt;&lt;TWINT)|(1&lt;&lt;TWEN)|(1&lt;&lt;TWEA);    while(!(TWCR & (1&lt;&lt;TWINT)));    if( data )   {     TWDR = data;     TWCR = (1&lt;&lt;TWINT)|(1&lt;&lt;TWEN)|(1&lt;&lt;TWEA);      while(!(TWCR & (1&lt;&lt;TWINT)));   }  }  char TWI_Read_Byte(char n) {   char data;    \/*\u0441\u0447\u0438\u0442\u044b\u0432\u0430\u0435\u043c \u0434\u0430\u043d\u043d\u044b\u0435*\/   if( n &gt; 1 )   {     TWCR = (1&lt;&lt;TWINT)|(1&lt;&lt;TWEN)|(0&lt;&lt;TWEA);       }   else   {     TWCR = (1&lt;&lt;TWINT)|(1&lt;&lt;TWEN)|(1&lt;&lt;TWEA);       }      while(!(TWCR & (1&lt;&lt;TWINT)));   data = TWDR;    return data;  }  void TWI_Stop() {   \/*\u0444\u043e\u0440\u043c\u0438\u0440\u0443\u0435\u043c \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u0421\u0422\u041e\u041f*\/   TWCR = (1&lt;&lt;TWINT)|(1&lt;&lt;TWSTO)|(1&lt;&lt;TWEN); }  \/\/ Read the uncompensated temperature value unsigned int bmp085ReadUT() {   unsigned int ut;     \/\/ Write 0x2E into Register 0xF4   \/\/ This requests a temperature reading    TWI_Start();   TWI_Start_SLA_W( BMP085_ADDRESS, 0xF4, 0x2E );   TWI_Stop();      \/\/ Wait at least 4.5ms   delay(5);    \/\/ Read two bytes from registers 0xF6 and 0xF7   ut = bmp085ReadInt(0xF6);    return ut; }  \/\/ Read the uncompensated pressure value unsigned long bmp085ReadUP() {   unsigned char msb, lsb, xlsb;   unsigned long up = 0;     \/\/ Write 0x34+(OSS&lt;&lt;6) into register 0xF4   \/\/ Request a pressure reading w\/ oversampling setting     TWI_Start();   TWI_Start_SLA_W( BMP085_ADDRESS, 0xF4, 0x34 + (OSS&lt;&lt;6) );   TWI_Stop();    \/\/ Wait for conversion, delay time dependent on OSS   delay(2 + (3&lt;&lt;OSS));     \/\/ Read register 0xF6 (MSB), 0xF7 (LSB), and 0xF8 (XLSB)    TWI_Start();   TWI_Start_SLA_W( BMP085_ADDRESS, 0xF6, 0 );   TWI_Stop();    TWI_Start();   TWI_Start_SLA_R( BMP085_ADDRESS );    msb = TWI_Read_Byte( 1 );   lsb = TWI_Read_Byte( 1 );   xlsb = TWI_Read_Byte( 2 );    TWI_Stop();     up = (((unsigned long) msb &lt;&lt; 16) | ((unsigned long) lsb &lt;&lt; 8) | (unsigned long) xlsb) &gt;&gt; (8-OSS);     return up; }  \/\/ Calculate temperature given ut. \/\/ Value returned will be in units of 0.1 deg C short bmp085GetTemperature(unsigned int ut) {   long x1, x2;     x1 = (((long)ut - (long)ac6)*(long)ac5) &gt;&gt; 15;   x2 = ((long)mc &lt;&lt; 11)\/(x1 + md);   b5 = x1 + x2;    return ((b5 + 8)&gt;&gt;4);   \/\/  return ((b5 + 8)\/pow(2,4));    }  \/\/ Calculate pressure given up \/\/ calibration values must be known \/\/ b5 is also required so bmp085GetTemperature(...) must be called first. \/\/ Value returned will be pressure in units of Pa. long bmp085GetPressure(unsigned long up) {   long x1, x2, x3, b3, b6, p;   unsigned long b4, b7;     b6 = b5 - 4000;   \/\/ Calculate B3   x1 = (b2 * (b6 * b6)&gt;&gt;12)&gt;&gt;11;   x2 = (ac2 * b6)&gt;&gt;11;   x3 = x1 + x2;   b3 = (((((long)ac1)*4 + x3)&lt;&lt;OSS) + 2)&gt;&gt;2;     \/\/ Calculate B4   x1 = (ac3 * b6)&gt;&gt;13;   x2 = (b1 * ((b6 * b6)&gt;&gt;12))&gt;&gt;16;   x3 = ((x1 + x2) + 2)&gt;&gt;2;   b4 = (ac4 * (unsigned long)(x3 + 32768))&gt;&gt;15;     b7 = ((unsigned long)(up - b3) * (50000&gt;&gt;OSS));   if (b7 &lt; 0x80000000)     p = (b7&lt;&lt;1)\/b4;   else     p = (b7\/b4)&lt;&lt;1;        x1 = (p&gt;&gt;8) * (p&gt;&gt;8);   x1 = (x1 * 3038)&gt;&gt;16;   x2 = (-7357 * p)&gt;&gt;16;   p += (x1 + x2 + 3791)&gt;&gt;4;     return p; }  float LPF(float input, float CutOffFrequency) {     float output;       LPF_error = input - LPF_ww;     LPF_ee = LPF_error * CutOffFrequency;     LPF_ww = LPF_ww + (LPF_ee+LPF_ee1)*SamplingTime*0.5;     LPF_ee1 = LPF_ee;     output = LPF_ww;          return output; }  void setup() {     TWI_Init();     bmp085Calibration();         SREG |= 0x80;     Port_init();     Timer1_init();     Timer2_init();       }  void loop() {   if(T_flag == TRUE) \/\/\u0421\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u043d\u0438\u0435 \u043a\u0430\u0436\u0434\u044b\u0435 40\u0413\u0446   {      T = bmp085GetTemperature( bmp085ReadUT() );     P = bmp085GetPressure( bmp085ReadUP() );      H_temp = (P\/100.0f)\/1013.25;     H_alt = (1-pow(H_temp,0.190284)) * 145366.45;     Altitude = 0.3048*H_alt;      Altitude_cm = (float)((long)(Altitude*100));  \/\/ 1cm     Altitude_LPF = LPF(Altitude_cm, CutOffFrequency);      \/\/ LPF \/\/ Altitude_feedback     ClimbRate = (Altitude_LPF - pre_Altitude_LPF)\/SamplingTime;  \/\/ ClimbRate_feedback     pre_Altitude_LPF = Altitude_LPF;       \t   \tFMD_flag = FMD_check(cnt_FMD);     \/\/ FMD \u041f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u043c \u0440\u0435\u0436\u0438\u043c        OCR1A = cnt_FMD;                    \/\/\u041f\u0435\u0440\u0435\u0434\u0430\u0435\u043c \u0432 CC3D \u0440\u0435\u0436\u0438\u043c \u043f\u043e\u043b\u0435\u0442\u0430    \tswitch(FMD_flag){   \t\tcase Manual_Mode:                     \/\/ \u041f\u0440\u0438 \u0440\u0443\u0447\u043d\u043e\u043c \u0440\u0435\u0436\u0438\u043c\u0435          OCR1B = cnt_thro;                   \/\/\u041f\u0435\u0440\u0435\u0434\u0430\u0435\u043c \u0432 CC3D \u043f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0433\u0430\u0437\u0430         Hov_Thro = cnt_thro-2000;         Limit_cut(&Hov_Thro, 800, 1200);         Thro_in = Altitude_LPF;         ALT_RATE_I = 0.0;    \t\tbreak;   \t\tcase Alt_Hold:                              \/\/ \u0420\u0435\u0436\u0438\u043c \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u041a\u043e\u043d\u0442\u0440\u043e\u043b\u044c \u0412\u044b\u0441\u043e\u0442\u044b               Thro_cmd = 0.25 * ((int)cnt_thro-Thro_Neutral);  \/\/ -250~250 means -2.5~2.5         Stick_Deadband(&Thro_cmd, -Thro_Deadband, Thro_Deadband);         Limit_cut_int(&Thro_cmd, -THRO_CMD_MAX, THRO_CMD_MAX);         Thro_in = Thro_in + Thro_cmd*SamplingTime;         Limit_cut_long(&Thro_in, -200000000, 200000000);                ALT_ERR = ((float)Thro_in) - Altitude_LPF;         ALT_RATE_ERR = ALT_ERR * A_outer_Pgain - ClimbRate;         Limit_cut(&ALT_RATE_ERR, -ALT_RATE_ERR_MAX, ALT_RATE_ERR_MAX);         ALT_RATE_P = ALT_RATE_ERR * A_inner_Pgain;         ALT_RATE_I = ALT_RATE_I + (ALT_RATE_ERR * A_inner_Igain) * SamplingTime;         Limit_cut(&ALT_RATE_I, -ALT_RATE_I_MAX, ALT_RATE_I_MAX);         ALT_RATE_D = (ALT_RATE_ERR - pre_ALT_RATE_ERR)\/SamplingTime * A_inner_Dgain;         pre_ALT_RATE_ERR = ALT_RATE_ERR;              ALT_PID = ALT_RATE_P + ALT_RATE_I + ALT_RATE_D;         Limit_cut(&ALT_PID, -ALT_PID_MAX, ALT_PID_MAX);         ALT_cont = ALT_PID + Hov_Thro;              OCR1B = 2000 + (int)(ALT_cont);              \t\t\tbreak;   \t\tdefault:    \t\t\tbreak;   \t}     T_flag = FALSE;   } } <\/code><\/pre>\n<p>  <\/div>\n<\/div>\n<p>  \u0413\u043e\u0442\u043e\u0432\u043e\u0435 \u0440\u0435\u0448\u0435\u043d\u0438\u0435 \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u0442\u0430\u043a:<\/p>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/files\/ded\/cdb\/e11\/dedcdbe119ec4de1a463e7f1c0f006d9.jpg\"\/><\/p>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/files\/383\/d11\/9bc\/383d119bceb84a24b417ce99377252b8.jpg\"\/><\/p>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/files\/858\/06c\/a00\/85806ca009714db980aed069f70d37bc.jpg\"\/><\/p>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/files\/e35\/5e9\/57e\/e355e957ea354ac7bb29d6df8d4c7aa6.jpg\"\/><\/p>\n<p>  \u0422\u0435\u0441\u0442\u043e\u0432\u044b\u0439 \u043f\u043e\u043b\u0435\u0442 (\u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043b\u0441\u044f Arduino Uno). \u0412\u043a\u043b\u044e\u0447\u0435\u043d \u0440\u0435\u0436\u0438\u043c \u0443\u0434\u0435\u0440\u0436\u0430\u043d\u0438\u044f \u0432\u044b\u0441\u043e\u0442\u044b. \u044f \u043a\u043e\u0440\u0440\u0435\u043a\u0442\u0438\u0440\u0443\u044e \u0442\u043e\u043b\u044c\u043a\u043e \u043f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u0435. \u041f\u0440\u043e\u0448\u0443 \u043f\u0440\u043e\u0449\u0435\u043d\u0438\u044f \u0443 \u043f\u0443\u0431\u043b\u0438\u043a\u0438 \u043f\u0438\u043b\u043e\u0442 \u0438\u0437 \u043c\u0435\u043d\u044f \u043d\u0435 \u043e\u0447\u0435\u043d\u044c, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u043a\u043e\u043f\u0442\u0435\u0440 \u0438\u0437\u0440\u044f\u0434\u043d\u043e \u043c\u043e\u0442\u0430\u0435\u0442 \u0438\u0437 \u0441\u0442\u043e\u0440\u043e\u043d\u044b \u0432 \u0441\u0442\u043e\u0440\u043e\u043d\u0443.<\/p>\n<p>  <iframe loading=\"lazy\" width=\"560\" height=\"315\" src=\"https:\/\/www.youtube.com\/embed\/BeFJ6PWgIdM?feature=oembed\" frameborder=\"0\" allowfullscreen><\/iframe><\/p>\n<p>  \u0412\u043e\u043f\u0440\u043e\u0441\u044b, \u043f\u043e\u0436\u0435\u043b\u0430\u043d\u0438\u044f \u0438 \u043f\u0440\u0435\u0434\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0441 \u0440\u0430\u0434\u043e\u0441\u0442\u044c\u044e \u0432\u044b\u0441\u043b\u0443\u0448\u0430\u044e.       <\/p>\n<div class=\"clear\"><\/div>\n<p> \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/geektimes.ru\/post\/269790\/\"> https:\/\/geektimes.ru\/post\/269790\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>       \u0414\u0443\u043c\u0430\u044e, \u044f \u043d\u0435 \u043e\u0442\u043a\u0440\u043e\u044e \u0430\u043c\u0435\u0440\u0438\u043a\u0438. \u041d\u043e \u043a\u043e\u0433\u0434\u0430 \u0443 \u043c\u0435\u043d\u044f \u0432\u043e\u0437\u043d\u0438\u043a\u043b\u0430 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0441\u0442\u044c \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0441\u0442\u0430\u0431\u0438\u043b\u0438\u0437\u0430\u0446\u0438\u044e \u043f\u043e \u0432\u044b\u0441\u043e\u0442\u0435 \u0441 \u0431\u0430\u0440\u043e \u0434\u043b\u044f CC3D, \u0440\u0435\u0448\u0435\u043d\u0438\u0435 \u043d\u0435 \u043d\u0430\u0448\u043b\u043e\u0441\u044c. \u0411\u044b\u043b\u0438 \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u044b \u043f\u0435\u0440\u0435\u043f\u0440\u043e\u0448\u0438\u0442\u044c \u0435\u0433\u043e \u0441 OpenPilot \u043d\u0430 \u0447\u0442\u043e \u0442\u043e \u0434\u0440\u0443\u0433\u043e\u0435, \u0438 \u0442\u0430\u043c \u0435\u0441\u0442\u044c \u0442\u0430\u043a\u0438\u0435 \u0432\u0435\u0449\u0438. \u041d\u043e \u044f \u0440\u0435\u0448\u0438\u043b \u043f\u043e\u0439\u0442\u0438 \u043d\u0435 \u0441\u0430\u043c\u044b\u043c \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u044b\u043c \u0438 \u043b\u0435\u0433\u043a\u0438\u043c \u0441\u043f\u043e\u0441\u043e\u0431\u043e\u043c. \u041c\u043e\u0435 \u0440\u0435\u0448\u0435\u043d\u0438\u0435 \u2014 \u044d\u0442\u043e \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440 \u043c\u0435\u0436\u0434\u0443 \u043f\u0440\u0438\u0435\u043c\u043d\u0438\u043a\u043e\u043c \u0438 CC3D (\u0438\u043b\u0438 \u043b\u044e\u0431\u044b\u043c \u0434\u0440\u0443\u0433\u0438\u043c), \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043c\u0435\u0440\u044f\u0435\u0442 \u0432\u044b\u0441\u043e\u0442\u0443 \u0438 \u0432\u043d\u043e\u0441\u0438\u0442 \u043a\u043e\u0440\u0440\u0435\u043a\u0442\u0438\u0440\u043e\u0432\u043a\u0443 \u0432 \u043a\u0430\u043d\u0430\u043b \u0433\u0430\u0437\u0430, \u0430 \u0437\u0430\u0442\u0435\u043c \u043f\u0435\u0440\u0435\u0434\u0430\u0435\u0442 \u0435\u0435 \u0432 \u043f\u043e\u043b\u0435\u0442\u043d\u044b\u0439 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440. \u0422\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c \u0434\u0435\u0440\u0436\u0438\u0442 \u0432\u044b\u0441\u043e\u0442\u0443.  <\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-272850","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/272850","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=272850"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/272850\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=272850"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=272850"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=272850"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}