Инернционный трекер (ошибка загрузки скетча)

rilintar
Offline
Зарегистрирован: 21.03.2017

Здравствуйте, я с Ардуино вообще впервый раз столкнулся, хотел сделать себе подключаемый к компьютеру датчик положения головы.

В гугле "инерционный трекер своими руками"

Там в инструкции все написано, но на пункте "В IDE нажать круглую кнопку со стрелкой (Upload), дождаться, пока код скомпилируется и загрузится." у меня затык.

Программа ругается:

Короткий код:

Arduino: 1.8.1 (Windows 10), Плата:"Arduino Nano, ATmega328"

sketch\Sensors.cpp:9:21: fatal error: Sensors.h: No such file or directory

 #include <Sensors.h>

                     ^

compilation terminated.

exit status 1
Ошибка компиляции для платы Arduino Nano.

Этот отчёт будет иметь больше информации с
включенной опцией Файл -> Настройки ->
"Показать подробный вывод во время компиляции"

Полный код:

Arduino: 1.8.1 (Windows 10), Плата:"Arduino Nano, ATmega328"

C:\Program Files (x86)\Arduino\arduino-builder -dump-prefs -logger=machine -hardware C:\Program Files (x86)\Arduino\hardware -tools C:\Program Files (x86)\Arduino\tools-builder -tools C:\Program Files (x86)\Arduino\hardware\tools\avr -built-in-libraries C:\Program Files (x86)\Arduino\libraries -libraries D:\Документы\Arduino\libraries -fqbn=arduino:avr:nano:cpu=atmega328 -ide-version=10801 -build-path C:\Users\rilin\AppData\Local\Temp\arduino_build_975651 -warnings=none -prefs=build.warn_data_percentage=75 -prefs=runtime.tools.avr-gcc.path=C:\Program Files (x86)\Arduino\hardware\tools\avr -prefs=runtime.tools.avrdude.path=C:\Program Files (x86)\Arduino\hardware\tools\avr -prefs=runtime.tools.arduinoOTA.path=C:\Program Files (x86)\Arduino\hardware\tools\avr -verbose C:\DIY_headtracker\DIY_headtracker.ino
C:\Program Files (x86)\Arduino\arduino-builder -compile -logger=machine -hardware C:\Program Files (x86)\Arduino\hardware -tools C:\Program Files (x86)\Arduino\tools-builder -tools C:\Program Files (x86)\Arduino\hardware\tools\avr -built-in-libraries C:\Program Files (x86)\Arduino\libraries -libraries D:\Документы\Arduino\libraries -fqbn=arduino:avr:nano:cpu=atmega328 -ide-version=10801 -build-path C:\Users\rilin\AppData\Local\Temp\arduino_build_975651 -warnings=none -prefs=build.warn_data_percentage=75 -prefs=runtime.tools.avr-gcc.path=C:\Program Files (x86)\Arduino\hardware\tools\avr -prefs=runtime.tools.avrdude.path=C:\Program Files (x86)\Arduino\hardware\tools\avr -prefs=runtime.tools.arduinoOTA.path=C:\Program Files (x86)\Arduino\hardware\tools\avr -verbose C:\DIY_headtracker\DIY_headtracker.ino
Using board 'nano' from platform in folder: C:\Program Files (x86)\Arduino\hardware\arduino\avr
Using core 'arduino' from platform in folder: C:\Program Files (x86)\Arduino\hardware\arduino\avr
Detecting libraries used...
"C:\Program Files (x86)\Arduino\hardware\tools\avr/bin/avr-g++" -c -g -Os -w -std=gnu++11 -fpermissive -fno-exceptions -ffunction-sections -fdata-sections -fno-threadsafe-statics  -flto -w -x c++ -E -CC -mmcu=atmega328p -DF_CPU=16000000L -DARDUINO=10801 -DARDUINO_AVR_NANO -DARDUINO_ARCH_AVR   "-IC:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino" "-IC:\Program Files (x86)\Arduino\hardware\arduino\avr\variants\eightanaloginputs" "C:\Users\rilin\AppData\Local\Temp\arduino_build_975651\sketch\DIY_headtracker.ino.cpp" -o "nul"
"C:\Program Files (x86)\Arduino\hardware\tools\avr/bin/avr-g++" -c -g -Os -w -std=gnu++11 -fpermissive -fno-exceptions -ffunction-sections -fdata-sections -fno-threadsafe-statics  -flto -w -x c++ -E -CC -mmcu=atmega328p -DF_CPU=16000000L -DARDUINO=10801 -DARDUINO_AVR_NANO -DARDUINO_ARCH_AVR   "-IC:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino" "-IC:\Program Files (x86)\Arduino\hardware\arduino\avr\variants\eightanaloginputs" "-IC:\Program Files (x86)\Arduino\hardware\arduino\avr\libraries\Wire\src" "C:\Users\rilin\AppData\Local\Temp\arduino_build_975651\sketch\DIY_headtracker.ino.cpp" -o "nul"
"C:\Program Files (x86)\Arduino\hardware\tools\avr/bin/avr-g++" -c -g -Os -w -std=gnu++11 -fpermissive -fno-exceptions -ffunction-sections -fdata-sections -fno-threadsafe-statics  -flto -w -x c++ -E -CC -mmcu=atmega328p -DF_CPU=16000000L -DARDUINO=10801 -DARDUINO_AVR_NANO -DARDUINO_ARCH_AVR   "-IC:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino" "-IC:\Program Files (x86)\Arduino\hardware\arduino\avr\variants\eightanaloginputs" "-IC:\Program Files (x86)\Arduino\hardware\arduino\avr\libraries\Wire\src" "-IC:\Program Files (x86)\Arduino\hardware\arduino\avr\libraries\EEPROM\src" "C:\Users\rilin\AppData\Local\Temp\arduino_build_975651\sketch\DIY_headtracker.ino.cpp" -o "nul"
"C:\Program Files (x86)\Arduino\hardware\tools\avr/bin/avr-g++" -c -g -Os -w -std=gnu++11 -fpermissive -fno-exceptions -ffunction-sections -fdata-sections -fno-threadsafe-statics  -flto -w -x c++ -E -CC -mmcu=atmega328p -DF_CPU=16000000L -DARDUINO=10801 -DARDUINO_AVR_NANO -DARDUINO_ARCH_AVR   "-IC:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino" "-IC:\Program Files (x86)\Arduino\hardware\arduino\avr\variants\eightanaloginputs" "-IC:\Program Files (x86)\Arduino\hardware\arduino\avr\libraries\Wire\src" "-IC:\Program Files (x86)\Arduino\hardware\arduino\avr\libraries\EEPROM\src" "C:\Users\rilin\AppData\Local\Temp\arduino_build_975651\sketch\FaceTrack.cpp" -o "nul"
"C:\Program Files (x86)\Arduino\hardware\tools\avr/bin/avr-g++" -c -g -Os -w -std=gnu++11 -fpermissive -fno-exceptions -ffunction-sections -fdata-sections -fno-threadsafe-statics  -flto -w -x c++ -E -CC -mmcu=atmega328p -DF_CPU=16000000L -DARDUINO=10801 -DARDUINO_AVR_NANO -DARDUINO_ARCH_AVR   "-IC:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino" "-IC:\Program Files (x86)\Arduino\hardware\arduino\avr\variants\eightanaloginputs" "-IC:\Program Files (x86)\Arduino\hardware\arduino\avr\libraries\Wire\src" "-IC:\Program Files (x86)\Arduino\hardware\arduino\avr\libraries\EEPROM\src" "C:\Users\rilin\AppData\Local\Temp\arduino_build_975651\sketch\Functions.cpp" -o "nul"
"C:\Program Files (x86)\Arduino\hardware\tools\avr/bin/avr-g++" -c -g -Os -w -std=gnu++11 -fpermissive -fno-exceptions -ffunction-sections -fdata-sections -fno-threadsafe-statics  -flto -w -x c++ -E -CC -mmcu=atmega328p -DF_CPU=16000000L -DARDUINO=10801 -DARDUINO_AVR_NANO -DARDUINO_ARCH_AVR   "-IC:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino" "-IC:\Program Files (x86)\Arduino\hardware\arduino\avr\variants\eightanaloginputs" "-IC:\Program Files (x86)\Arduino\hardware\arduino\avr\libraries\Wire\src" "-IC:\Program Files (x86)\Arduino\hardware\arduino\avr\libraries\EEPROM\src" "C:\Users\rilin\AppData\Local\Temp\arduino_build_975651\sketch\Sensors.cpp" -o "nul"
"C:\Program Files (x86)\Arduino\hardware\tools\avr/bin/avr-g++" -c -g -Os -w -std=gnu++11 -fpermissive -fno-exceptions -ffunction-sections -fdata-sections -fno-threadsafe-statics  -flto -w -x c++ -E -CC -mmcu=atmega328p -DF_CPU=16000000L -DARDUINO=10801 -DARDUINO_AVR_NANO -DARDUINO_ARCH_AVR   "-IC:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino" "-IC:\Program Files (x86)\Arduino\hardware\arduino\avr\variants\eightanaloginputs" "-IC:\Program Files (x86)\Arduino\hardware\arduino\avr\libraries\Wire\src" "-IC:\Program Files (x86)\Arduino\hardware\arduino\avr\libraries\EEPROM\src" "C:\Users\rilin\AppData\Local\Temp\arduino_build_975651\sketch\Sensors.cpp" -o "C:\Users\rilin\AppData\Local\Temp\arduino_build_975651\preproc\ctags_target_for_gcc_minus_e.cpp"
C:\Users\rilin\AppData\Local\Temp\arduino_build_975651\sketch\Sensors.cpp:9:21: fatal error: Sensors.h: No such file or directory

 #include <Sensors.h>

                     ^

compilation terminated.

Используем библиотеку Wire версии 1.0 из папки: C:\Program Files (x86)\Arduino\hardware\arduino\avr\libraries\Wire 
Используем библиотеку EEPROM версии 2.0 из папки: C:\Program Files (x86)\Arduino\hardware\arduino\avr\libraries\EEPROM 
exit status 1
Ошибка компиляции для платы Arduino Nano.

Говорит что не может найти файл, но до этого я открывал код из диска D:/ потом решил переместить папку вообще в корень диска C:/ но продолжается такая же байда.

Скорее всего лечится это очень легко, но я кроме бейсика и паскаля ничего не видел.

rilintar
Offline
Зарегистрирован: 21.03.2017
ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

А код-то где?

Что за файл Sensor.h ? Он у Вас есть? Где находится? И код давайте.

rilintar
Offline
Зарегистрирован: 21.03.2017

Коды открывать осторожно (очень много строк)

Все файлы находятся в одной папке по адресу C:\DIY_headtracker

Код главного файла:

//-----------------------------------------------------------------------------
// Original project by Dennis Frie - 2012 - Dennis.frie@gmail.com
// Discussion: http://www.rcgroups.com/forums/showthread.php?t=1677559
//
// Other contributors to this code:
//  Mark Mansur (Mangus on rcgroups)
//  
// Version history:
// - 0.01 - 0.08 - Dennis Frie - preliminary releases
// - 1.01 - April 2013 - Mark Mansur - code clean-up and refactoring, comments
//      added. Added pause functionality, added settings retrieval commands.
//      Minor optimizations.
//-----------------------------------------------------------------------------

#include <Wire.h>
#include "config.h"
#include "functions.h"
#include <EEPROM.h>
#include "FaceTrack.h"
#include "sensors.h"
/*
Channel mapping/config for PPM out:

1 = PPM CHANNEL 1
2 = PPM CHANNEL 2
3 = PPM CHANNEL 3
4 = PPM CHANNEL 4
5 = PPM CHANNEL 5
6 = PPM CHANNEL 6
7 = PPM CHANNEL 7
8 = PPM CHANNEL 8
9 = PPM CHANNEL 9
10 = PPM CHANNEL 10
11 = PPM CHANNEL 11
12 = PPM CHANNEL 12

Mapping example:
$123456789111CH
*/


// Local file variables
//
int frameNumber = 0;		    // Frame count since last debug serial output

char serial_data[101];          // Array for serial-data 
unsigned char serial_index = 0; // How many bytes have been received?
char string_started = 0;        // Only saves data if string starts with right byte
unsigned char channel_mapping[13];

char outputMag = 0;             // Stream magnetometer data to host
char outputAcc = 0;             // Stream accelerometer data to host
char outputMagAcc = 0;          // Stream mag and accell data (for calibration on PC)
char outputTrack = 0;	        // Stream angle data to host

// Keep track of button press
char lastButtonState = 0;           // 0 is not pressed, 1 is pressed
unsigned long buttonDownTime = 0;   // the system time of the press
char pauseToggled = 0;              // Used to make sure we toggle pause only once per hold
char ht_paused = 0;

// External variables (defined in other files)
//
extern unsigned char PpmIn_PpmOut[13];
extern char read_sensors;
extern char resetValues;   
extern char tiltInverse;
extern char rollInverse;
extern char panInverse;



// Settings (Defined in sensors.cpp)
//
extern float tiltRollBeta;
extern float panBeta;
extern float gyroWeightTiltRoll;
extern float GyroWeightPan;
extern int servoPanCenter;
extern int servoTiltCenter;
extern int servoRollCenter;
extern int panMaxPulse;
extern int panMinPulse;
extern int tiltMaxPulse;
extern int tiltMinPulse;
extern int rollMaxPulse;
extern int rollMinPulse;
extern float panFactor;
extern float tiltFactor;  
extern float rollFactor;
extern unsigned char servoReverseMask;
extern unsigned char htChannels[];
extern float gyroOff[];
extern float magOffset[];
extern int accOffset[]; 
// End settings   

//--------------------------------------------------------------------------------------
// Func: setup
// Desc: Called by Arduino framework at initialization time. This sets up pins for I/O,
//       initializes sensors, etc.
//--------------------------------------------------------------------------------------
void setup()
{
    Serial.begin(SERIAL_BAUD);

  
    pinMode(9,OUTPUT);
    digitalWrite(2,HIGH);
    digitalWrite(3,HIGH);  
  
    // Set all other pins to input, for safety.
    pinMode(0,INPUT);
    pinMode(1,INPUT);
    pinMode(2,INPUT);
    pinMode(3,INPUT);
    pinMode(6,INPUT);
    pinMode(7,INPUT);  
    pinMode(8,INPUT);    

    // Set button pin to input:
    pinMode(BUTTON_INPUT,INPUT);
  
    // Set internal pull-up resistor. 
    digitalWrite(BUTTON_INPUT,HIGH);
  
    digitalWrite(0,LOW); // pull-down resistor
    digitalWrite(1,LOW);
    digitalWrite(2,HIGH);
    digitalWrite(3,HIGH);  
  
    pinMode(ARDUINO_LED,OUTPUT);    // Arduino LED
    digitalWrite(ARDUINO_LED, HIGH);
    
#if FATSHARK_HT_MODULE
    pinMode(BUZZER,OUTPUT);         // Buzzer
    digitalWrite(BUZZER, HIGH);
#endif

    // Give it time to be noticed, then turn it off
    delay(200); // Note: only use delay here. This won't work when Timer0 is repurposed later.
    digitalWrite(ARDUINO_LED, LOW);

#if FATSHARK_HT_MODULE
    digitalWrite(BUZZER, LOW);
#endif

    InitPWMInterrupt();         // Start PWM interrupt  
    Wire.begin();               // Start I2C

    // If the device have just been programmed, write initial config/values to EEPROM:
    if (EEPROM.read(0) != 8)
    {
//#if (DEBUG)
        Serial.println("New board - saving default values!");
//#endif    
    
        InitSensors();
#if (ALWAYS_CAL_GYRO)    
        SetGyroOffset();
#endif     

        SaveSettings();
        SaveMagData();
        SaveAccelData();
    }
 
    GetSettings();                 // Get settings saved in EEPROM
    InitSensors();                // Initialize I2C sensors
    CalibrateMag();
    ResetCenter();
    InitTimerInterrupt();        // Start timer interrupt (for sensors)  
    FT_Setup();
}

//--------------------------------------------------------------------------------------
// Func: loop
// Desc: Called by the Arduino framework once per frame. Represents main program loop.
//--------------------------------------------------------------------------------------
void loop()
{  
    FTData();
    // Check input button for reset/pause request
    char buttonPressed = (digitalRead(BUTTON_INPUT) == 0);

    if ( buttonPressed && lastButtonState == 0)
    {
        resetValues = 1; 
        buttonDownTime = 0;
        lastButtonState = 1;
    }
    
    if ( buttonPressed )
    {
        if ( !pauseToggled && (buttonDownTime > BUTTON_HOLD_PAUSE_THRESH) )
        {
            // Pause/unpause
            ht_paused = !ht_paused;
            resetValues = 1;
            pauseToggled = 1;
        }
    }
    else
    {
        pauseToggled = 0;
        lastButtonState = 0;
    }
    
    // All this is used for communication with GUI 
    //
    if (Serial.available())
    {
        if (string_started == 1)
        {
            // Read incoming byte
            serial_data[serial_index++] = Serial.read();
           
            // If string ends with "CH" it's channel configuration, that have been received.
            // String must always be 12 chars/bytes and ending with CH to be valid. 
            if (serial_index == 14 &&
                serial_data[serial_index-2] == 'C' &&
                serial_data[serial_index-1] == 'H' )
            {
                // To keep it simple, we will not let the channels be 0-initialized, but
                // start from 1 to match actual channels. 
                for (unsigned char i = 0; i < 13; i++)
                {
                    channel_mapping[i + 1] = serial_data[i] - 48;
                  
                    // Update the dedicated PPM-in -> PPM-out array for faster performance.
                    if ((serial_data[i] - 48) < 14)
                    {
                        PpmIn_PpmOut[serial_data[i]-48] = i + 1;
                    }
                }
               
                Serial.println("Channel mapping received");
               
               // Reset serial_index and serial_started
               serial_index = 0;
               string_started = 0;
            }
            
            // Configure headtracker
            else if (serial_data[serial_index-2] == 'H' &&
                     serial_data[serial_index-1] == 'E')
            {
                // HT parameters are passed in from the PC in this order:
                //
                // 0 tiltRollBeta      
                // 1 panBeta       
                // 2 gyroWeightTiltRoll    
                // 3 GyroWeightPan 
                // 4 tiltFactor        
                // 5 panFactor          
                // 6 rollFactor
                // 7 servoReverseMask
                // 8 servoPanCenter
                // 9 panMinPulse 
                // 10 panMaxPulse
                // 11 servoTiltCenter
                // 12 tiltMinPulse
                // 13 tiltMaxPulse
                // 14 servoRollCenter
                // 15 rollMinPulse
                // 16 rollMaxPulse
                // 17 htChannels[0]  // pan            
                // 18 htChannels[1]  // tilt 
                // 19 htChannels[2]  // roll         
             
                // Parameters from the PC client need to be scaled to match our local
                // expectations

                Serial.println("HT config received:");
           
                int valuesReceived[20] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
                int comma_index = 0;

                for (unsigned char k = 0; k < serial_index - 2; k++)
                {
                    // Looking for comma
                    if (serial_data[k] == 44)
                    {
                        comma_index++;
                    }
                    else
                    {
                        valuesReceived[comma_index] = valuesReceived[comma_index] * 10 + (serial_data[k] - 48);
                    }
             
#if (DEBUG)
                    Serial.print(serial_data[k]);
#endif
                }

#if (DEBUG)
                Serial.println();
                for (unsigned char k = 0; k < comma_index+1; k++)
                {
                    Serial.print(valuesReceived[k]); 
                    Serial.print(",");           
                }
                Serial.println();
#endif

                tiltRollBeta  = (float)valuesReceived[0] / 100;  
                panBeta       = (float)valuesReceived[1] / 100;
                gyroWeightTiltRoll = (float)valuesReceived[2] / 100;
                GyroWeightPan = (float)valuesReceived[3] / 100;
                tiltFactor    = (float)valuesReceived[4] / 10;         
                panFactor     = (float)valuesReceived[5] / 10;          
                rollFactor    = (float)valuesReceived[6] / 10;   

                servoReverseMask = (unsigned char)valuesReceived[7];

                tiltInverse = 1;
                rollInverse = 1;
                panInverse = 1;           
                
                if ((servoReverseMask & HT_PAN_REVERSE_BIT) != 0)
                {
                    panInverse = -1;
                }
                if ((servoReverseMask & HT_ROLL_REVERSE_BIT) != 0)
                {
                    rollInverse = -1; 
                }
                if ((servoReverseMask & HT_TILT_REVERSE_BIT) != 0)
                {
                    tiltInverse = -1;
                }

                servoPanCenter = valuesReceived[8];
                panMinPulse = valuesReceived[9];
                panMaxPulse = valuesReceived[10];         
         
                servoTiltCenter = valuesReceived[11];
                tiltMinPulse = valuesReceived[12];
                tiltMaxPulse = valuesReceived[13];         

                servoRollCenter = valuesReceived[14];
                rollMinPulse = valuesReceived[15];
                rollMaxPulse = valuesReceived[16];              
     
                htChannels[0] = valuesReceived[17];                   
                htChannels[1] = valuesReceived[18];              
                htChannels[2] = valuesReceived[19];                       

                Serial.println(htChannels[0]);
                Serial.println(htChannels[1]);
                Serial.println(htChannels[2]);                
        
                SaveSettings();

                serial_index = 0;
                string_started = 0;
            } // end configure headtracker
          
            // Debug info
            else if (serial_data[serial_index-5] == 'D' &&
                     serial_data[serial_index-4] == 'E' &&
                     serial_data[serial_index-3] == 'B' &&
                     serial_data[serial_index-2] == 'U' &&
                     serial_data[serial_index-1] == 'G')
            {  
                DebugOutput();
                serial_index = 0;
                string_started = 0; 
            }

            // Firmware version requested
            else if (serial_data[serial_index-4] == 'V' &&
                     serial_data[serial_index-3] == 'E' &&
                     serial_data[serial_index-2] == 'R' &&
                     serial_data[serial_index-1] == 'S')
            {
                Serial.print("FW: ");
                Serial.println(FIRMWARE_VERSION_FLOAT, 2);
                serial_index = 0;
                string_started = 0; 
            }
          
            // Start mag and accel data stream
            else if (serial_data[serial_index-4] == 'C' &&
                     serial_data[serial_index-3] == 'M' &&
                     serial_data[serial_index-2] == 'A' &&
                     serial_data[serial_index-1] == 'S')
            {  
                outputMagAcc = 1;
                outputMag = 0;
                outputAcc = 0;
                outputTrack = 0;
                serial_index = 0;
                string_started = 0;
            }        

            // Stop mag and accel data stream
            else if (serial_data[serial_index-4] == 'C' &&
                     serial_data[serial_index-3] == 'M' &&
                     serial_data[serial_index-2] == 'A' &&
                     serial_data[serial_index-1] == 'E')
            {  
                outputMagAcc = 0;
                outputMag = 0;
                outputTrack = 0;
                outputAcc = 0;
                serial_index = 0;
                string_started = 0;
            }        

            // Start magnetometer data stream
            else if (serial_data[serial_index-4] == 'C' &&
                     serial_data[serial_index-3] == 'A' &&
                     serial_data[serial_index-2] == 'S' &&
                     serial_data[serial_index-1] == 'T')
            {  
                outputMag = 1;
                outputMagAcc = 0;
                outputAcc = 0;
                outputTrack = 0;
                serial_index = 0;
                string_started = 0; 

            }        
          
            // Stop magnetometer data stream
            else if (serial_data[serial_index-4] == 'C' &&
                     serial_data[serial_index-3] == 'A' &&
                     serial_data[serial_index-2] == 'E' &&
                     serial_data[serial_index-1] == 'N')
            {  
                outputMag = 0;
                outputMagAcc = 0;
                outputAcc = 0;
                outputTrack = 0;
                serial_index = 0;
                string_started = 0; 
            }

            // Start accelerometer data stream
            else if (serial_data[serial_index-4] == 'G' &&
                     serial_data[serial_index-3] == 'R' &&
                     serial_data[serial_index-2] == 'A' &&
                     serial_data[serial_index-1] == 'V')
            {  
                outputAcc = 1;     
                outputMagAcc = 0;
                outputMag = 0;
                outputTrack = 0;
                serial_index = 0;
                string_started = 0; 
            }              
          
            // Stop accelerometer data stream
            else if (serial_data[serial_index-4] == 'G' &&
                     serial_data[serial_index-3] == 'R' &&
                     serial_data[serial_index-2] == 'E' &&
                     serial_data[serial_index-1] == 'N')
            {  
                outputAcc = 0;
                outputMag = 0;
                outputMagAcc = 0;
                outputTrack = 0;
                serial_index = 0;
                string_started = 0; 
            }

            // Start tracking data stream
            else if (serial_data[serial_index-4] == 'P' &&
                     serial_data[serial_index-3] == 'L' &&
                     serial_data[serial_index-2] == 'S' &&
                     serial_data[serial_index-1] == 'T')
            {  
                outputTrack = 1;
                outputMagAcc = 0;
                outputMag = 0;
                outputAcc = 0;
                serial_index = 0;
                string_started = 0; 
            }        

            // Stop tracking data stream          
            else if (serial_data[serial_index-4] == 'P' &&
                     serial_data[serial_index-3] == 'L' &&
                     serial_data[serial_index-2] == 'E' &&
                     serial_data[serial_index-1] == 'N')
            {  
                outputTrack = 0;
                outputMag = 0;
                outputAcc = 0;
                outputMagAcc = 0;
                serial_index = 0;
                string_started = 0; 
            }
          
            // Save RAM settings to EEPROM
            else if (serial_data[serial_index-4] == 'S' &&
                     serial_data[serial_index-3] == 'A' &&
                     serial_data[serial_index-2] == 'V' &&
                     serial_data[serial_index-1] == 'E')
            {  
                SaveSettings();     
                serial_index = 0;
                string_started = 0; 
            }          
          
            // Calibrate gyro
            else if (serial_data[serial_index-4] == 'C' &&
                     serial_data[serial_index-3] == 'A' &&
                     serial_data[serial_index-2] == 'L' &&
                     serial_data[serial_index-1] == 'G')
            { 
                SetGyroOffset();
                SaveSettings();
               
                Serial.print("Gyro offset measured:");
                Serial.print(gyroOff[0]);
                Serial.print(",");   
                Serial.print(gyroOff[1]);
                Serial.print(",");      
                Serial.println(gyroOff[2]);    
               
                serial_index = 0;
                string_started = 0; 
            }

            // Store magnetometer offset
            else if (serial_data[serial_index-3] == 'M' &&
                     serial_data[serial_index-2] == 'A' &&
                     serial_data[serial_index-1] == 'G')
            {
                Serial.println(serial_data);
                int valuesReceived[5] = {0,0,0,0,0};
                int comma_index = 0; 
              
                for (unsigned char k = 0; k < serial_index - 3; k++)
                {
                    // Looking for comma
                    if (serial_data[k] == 44)
                    {
                        comma_index++;
                    }
                    else
                    {
                        valuesReceived[comma_index] = valuesReceived[comma_index] * 10 + (serial_data[k] - 48);
                    }
                }
                
                // Y and Z are swapped on purpose.
                magOffset[0] = valuesReceived[0] - 2000;
                magOffset[1] = valuesReceived[2] - 2000;
                magOffset[2] = valuesReceived[1] - 2000;

                serial_index = 0;
                string_started = 0; 

                SaveMagData();                
            }

            // Store accelerometer offset
            else if (serial_data[serial_index-3] == 'A' &&
                     serial_data[serial_index-2] == 'C' &&
                     serial_data[serial_index-1] == 'C')
            {
                Serial.println(serial_data);
                int valuesReceived[5] = {0,0,0,0,0};
                int comma_index = 0; 
                for (unsigned char k = 0; k < serial_index - 3; k++)
                {
                    // Looking for comma
                    if (serial_data[k] == 44)
                    {
                        comma_index++;
                    }
                    else
                    {
                        valuesReceived[comma_index] = valuesReceived[comma_index] * 10 + (serial_data[k] - 48);
                    }              
                }

                accOffset[0] = valuesReceived[0] - 2000;
                accOffset[1] = valuesReceived[1] - 2000;
                accOffset[2] = valuesReceived[2] - 2000;
                
                serial_index = 0;
                string_started = 0; 

                SaveAccelData();                
            }

            // Retrieve settings
            else if (serial_data[serial_index-4] == 'G' &&
                     serial_data[serial_index-3] == 'S' &&
                     serial_data[serial_index-2] == 'E' &&
                     serial_data[serial_index-1] == 'T' )
            {
                // Get Settings. Scale our local values to
                // real-world values usable on the PC side.
                //
                Serial.print("$SET$"); // something recognizable in the stream

                Serial.print(tiltRollBeta * 100);
                Serial.print(",");   
                Serial.print(panBeta * 100);
                Serial.print(",");
                Serial.print(gyroWeightTiltRoll * 100);  
                Serial.print(",");
                Serial.print(GyroWeightPan * 100);
                Serial.print(",");
                Serial.print(tiltFactor * 10);
                Serial.print(",");
                Serial.print(panFactor * 10);
                Serial.print(",");
                Serial.print(rollFactor * 10);
                Serial.print(",");
                Serial.print(servoReverseMask);
                Serial.print(",");
                Serial.print(servoPanCenter);
                Serial.print(",");
                Serial.print(panMinPulse);
                Serial.print(",");
                Serial.print(panMaxPulse);
                Serial.print(",");
                Serial.print(servoTiltCenter);
                Serial.print(",");
                Serial.print(tiltMinPulse);
                Serial.print(",");
                Serial.print(tiltMaxPulse);
                Serial.print(",");
                Serial.print(servoRollCenter);
                Serial.print(",");
                Serial.print(rollMinPulse);
                Serial.print(",");
                Serial.print(rollMaxPulse);
                Serial.print(",");
                Serial.print(htChannels[0]);
                Serial.print(",");
                Serial.print(htChannels[1]);
                Serial.print(",");
                Serial.println(htChannels[2]);

                Serial.println("Settings Retrieved!");

                serial_index = 0;
                string_started = 0;
            }
            else if (serial_index > 100)
            {
                // If more than 100 bytes have been received, the string is not valid.
                // Reset and "try again" (wait for $ to indicate start of new string). 
                serial_index = 0;
                string_started = 0;
            }
        }
        else if (Serial.read() == '$')
        {
            string_started = 1;
        }
    } // serial port input

    // if "read_sensors" flag is set high, read sensors and update
    if (read_sensors == 1 && ht_paused == 0)
    {
        UpdateSensors();
        GyroCalc();
        AccelCalc();
        MagCalc();
        FilterSensorData();    
               
        // Only output this data every X frames.
        if (frameNumber++ >= SERIAL_OUTPUT_FRAME_INTERVAL)
        {
            if (outputTrack == 1)
            {
                trackerOutput();
            }
            else if (outputMagAcc == 1)
            {
                calMagAccOutput();
            }
            else if (outputMag == 1)
            {
                calMagOutput(); 
            }
            else if (outputAcc == 1)
            {
                calAccOutput();
            }
            frameNumber = 0; 
        }

        // Will first update read_sensors when everything is done.  
        read_sensors = 0;
    }
}

//--------------------------------------------------------------------------------------
// Func: SaveSettings
// Desc: Saves device settings to EEPROM for retrieval at boot-up.
//--------------------------------------------------------------------------------------
void SaveSettings()
{  
    EEPROM.write(1, (unsigned char)(tiltRollBeta * 100));
    EEPROM.write(2, (unsigned char)(panBeta * 100));
    EEPROM.write(3, (unsigned char)(gyroWeightTiltRoll * 100));
    EEPROM.write(4, (unsigned char)(GyroWeightPan * 100));
  
    EEPROM.write(5, (unsigned char)servoReverseMask);
    
    // 6 unused
  
    EEPROM.write(7, (unsigned char)servoPanCenter);
    EEPROM.write(8, (unsigned char)(servoPanCenter >> 8));  
  
    EEPROM.write(9, (unsigned char)(tiltFactor * 10));
    EEPROM.write(10, (int)((tiltFactor * 10)) >> 8);  

    EEPROM.write(11, (unsigned char) (panFactor * 10));
    EEPROM.write(12, (int)((panFactor * 10)) >> 8);  

    EEPROM.write(13, (unsigned char) (rollFactor * 10));
    EEPROM.write(14, (int)((rollFactor * 10)) >> 8);  

    // 15 unused

    EEPROM.write(16, (unsigned char)servoTiltCenter);
    EEPROM.write(17, (unsigned char)(servoTiltCenter >> 8));  

    EEPROM.write(18, (unsigned char)servoRollCenter);
    EEPROM.write(19, (unsigned char)(servoRollCenter >> 8));  


    EEPROM.write(20, (unsigned char)panMaxPulse);
    EEPROM.write(21, (unsigned char)(panMaxPulse >> 8));  
  
    EEPROM.write(22, (unsigned char)panMinPulse);
    EEPROM.write(23, (unsigned char)(panMinPulse >> 8));    

    EEPROM.write(24, (unsigned char)tiltMaxPulse);
    EEPROM.write(25, (unsigned char)(tiltMaxPulse >> 8));    

    EEPROM.write(26, (unsigned char)tiltMinPulse);
    EEPROM.write(27, (unsigned char)(tiltMinPulse >> 8));

    EEPROM.write(28, (unsigned char)rollMaxPulse);
    EEPROM.write(29, (unsigned char)(rollMaxPulse >> 8));    

    EEPROM.write(30, (unsigned char)rollMinPulse);
    EEPROM.write(31, (unsigned char)(rollMinPulse >> 8)); 
  
    EEPROM.write(32, (unsigned char)htChannels[0]);
    EEPROM.write(33, (unsigned char)htChannels[1]);
    EEPROM.write(34, (unsigned char)htChannels[2]);
  
    // Saving gyro calibration values
    int temp = (int)(gyroOff[0] + 500.5);
    EEPROM.write(35, (unsigned char)temp);
    EEPROM.write(36, (unsigned char)(temp >> 8));   
  
    temp = (int)(gyroOff[1] + 500.5);
    EEPROM.write(37, (unsigned char)temp);
    EEPROM.write(38, (unsigned char)(temp >> 8));     

    temp = (int)(gyroOff[2] + 500.5);
    EEPROM.write(39, (unsigned char)temp);
    EEPROM.write(40, (unsigned char)(temp >> 8));    
  
    // Mark the memory to indicate that it has been
    // written. Used to determine if board is newly flashed
    // or not.
    EEPROM.write(0,8); 

    Serial.println("Settings saved!");
}

//--------------------------------------------------------------------------------------
// Func: GetSettings
// Desc: Retrieves device settings from EEPROM.
//--------------------------------------------------------------------------------------
void GetSettings()
{  
    tiltRollBeta    = (float)EEPROM.read(1) / 100;
    panBeta         = (float)EEPROM.read(2) / 100;
    gyroWeightTiltRoll = (float)EEPROM.read(3) / 100;
    GyroWeightPan   = (float)EEPROM.read(4) / 100;  
  
    tiltInverse = 1;
    rollInverse = 1;
    panInverse = 1;

    unsigned char temp = EEPROM.read(5);
    if ( temp & HT_TILT_REVERSE_BIT )
    {
        tiltInverse = -1;
    }  
    if ( temp & HT_ROLL_REVERSE_BIT )
    {
        rollInverse = -1;
    }
    if ( temp & HT_PAN_REVERSE_BIT )
    {
        panInverse = -1;
    }

    // 6 unused

    servoPanCenter  = EEPROM.read(7) + (EEPROM.read(8) << 8);
    tiltFactor      = (float)(EEPROM.read(9) + (EEPROM.read(10) << 8)) / 10;
    panFactor       = (float)(EEPROM.read(11) + (EEPROM.read(12) << 8)) / 10;
    rollFactor       = (float)(EEPROM.read(13) + (EEPROM.read(14) << 8)) / 10;  

    // 15 unused

    servoTiltCenter = EEPROM.read(16) + (EEPROM.read(17) << 8);
    servoRollCenter = EEPROM.read(18) + (EEPROM.read(19) << 8);  
  
    panMaxPulse   = EEPROM.read(20) + (EEPROM.read(21) << 8);  
    panMinPulse   = EEPROM.read(22) + (EEPROM.read(23) << 8);    
  
    tiltMaxPulse  = EEPROM.read(24) + (EEPROM.read(25) << 8);  
    tiltMinPulse  = EEPROM.read(26) + (EEPROM.read(27) << 8);      
  
    rollMaxPulse  = EEPROM.read(28) + (EEPROM.read(29) << 8);  
    rollMinPulse  = EEPROM.read(30) + (EEPROM.read(31) << 8);        
  
    htChannels[0] = EEPROM.read(32);  
    htChannels[1] = EEPROM.read(33);  
    htChannels[2] = EEPROM.read(34);    
  
    gyroOff[0] = EEPROM.read(35) + (EEPROM.read(36) << 8) - 500; 
    gyroOff[1] = EEPROM.read(37) + (EEPROM.read(38) << 8) - 500; 
    gyroOff[2] = EEPROM.read(39) + (EEPROM.read(40) << 8) - 500;   
  
    magOffset[0] = EEPROM.read(200) + (EEPROM.read(201) << 8) - 2000;     
    magOffset[1] = EEPROM.read(202) + (EEPROM.read(203) << 8) - 2000;     
    magOffset[2] = EEPROM.read(204) + (EEPROM.read(205) << 8) - 2000;       
  
    accOffset[0] = EEPROM.read(206) + (EEPROM.read(207) << 8) - 2000;     
    accOffset[1] = EEPROM.read(208) + (EEPROM.read(209) << 8) - 2000;     
    accOffset[2] = EEPROM.read(210) + (EEPROM.read(211) << 8) - 2000;       
  
 
#if (DEBUG)
    DebugOutput();
#endif
}

//--------------------------------------------------------------------------------------
// Func: SaveMagData
// Desc: Stores magnetometer calibration info to EEPROM.
//--------------------------------------------------------------------------------------
void SaveMagData()
{
    int temp = (int)(magOffset[0] + 2000);
    EEPROM.write(200, (unsigned char)temp);
    EEPROM.write(201, (unsigned char)(temp >> 8));   
  
    temp = (int)(magOffset[1] + 2000);
    EEPROM.write(202, (unsigned char)temp);
    EEPROM.write(203, (unsigned char)(temp >> 8));   
  
    temp = (int)(magOffset[2] + 2000);
    EEPROM.write(204, (unsigned char)temp);
    EEPROM.write(205, (unsigned char)(temp >> 8));   
  
    Serial.println("Mag offset saved!"); 
    Serial.print(magOffset[0]);
    Serial.print(", "); 
    Serial.print(magOffset[1]);
    Serial.print(", ");   
    Serial.println(magOffset[2]); 
}

//--------------------------------------------------------------------------------------
// Func: SaveAccelData
// Desc: Stores accelerometer calibration data to EEPOM.
//--------------------------------------------------------------------------------------
void SaveAccelData()
{
    int temp = (int)(accOffset[0] + 2000);
    EEPROM.write(206, (unsigned char)temp);
    EEPROM.write(207, (unsigned char)(temp >> 8));   
  
    temp = (int)(accOffset[1] + 2000);
    EEPROM.write(208, (unsigned char)temp);
    EEPROM.write(209, (unsigned char)(temp >> 8));   
  
    temp = (int)(accOffset[2] + 2000);
    EEPROM.write(210, (unsigned char)temp);
    EEPROM.write(211, (unsigned char)(temp >> 8));   
  
    Serial.println("Acc offset saved!"); 
    Serial.print(accOffset[0]);
    Serial.print(","); 
    Serial.print(accOffset[1]);
    Serial.print(",");   
    Serial.println(accOffset[2]);  
}

//--------------------------------------------------------------------------------------
// Func: DebugOutput
// Desc: Outputs useful device/debug information to the serial port.
//--------------------------------------------------------------------------------------
void DebugOutput()
{
    Serial.println();  
    Serial.println();
    Serial.println();
    Serial.println("------ Debug info------");

    Serial.print("FW Version: ");
    Serial.println(FIRMWARE_VERSION_FLOAT, 2);
    
    Serial.print("tiltRollBeta: ");
    Serial.println(tiltRollBeta); 

    Serial.print("panBeta: ");
    Serial.println(panBeta); 
 
    Serial.print("gyroWeightTiltRoll: ");
    Serial.println(gyroWeightTiltRoll); 

    Serial.print("GyroWeightPan: ");
    Serial.println(GyroWeightPan); 

    Serial.print("servoPanCenter: ");
    Serial.println(servoPanCenter); 
 
    Serial.print("servoTiltCenter: ");
    Serial.println(servoTiltCenter); 

    Serial.print("servoRollCenter: ");
    Serial.println(servoRollCenter); 

    Serial.print("tiltFactor: ");
    Serial.println(tiltFactor); 

    Serial.print("panFactor: ");
    Serial.println(panFactor);  
 
    Serial.print("Gyro offset stored ");
    Serial.print(gyroOff[0]);
    Serial.print(",");   
    Serial.print(gyroOff[1]);
    Serial.print(",");      
    Serial.println(gyroOff[2]);    
 
    Serial.print("Mag offset stored ");
    Serial.print(magOffset[0]);
    Serial.print(",");   
    Serial.print(magOffset[1]);
    Serial.print(",");      
    Serial.println(magOffset[2]);
 
    Serial.print("Acc offset stored ");
    Serial.print(accOffset[0]);
    Serial.print(",");   
    Serial.print(accOffset[1]);
    Serial.print(",");      
    Serial.println(accOffset[2]);
 
    SensorInfoPrint();    
}


Код Config.h

//-----------------------------------------------------------------------------
// File: Config.h
// Desc: Compilation configuration file. Defines user-configurable settings
//       as well as project-wide development #defines for configuration.
//-----------------------------------------------------------------------------
#ifndef config_h
#define config_h


//-----------------------------------------------------------------------------
// These are things you can change before you compile, to enable/disable
// features.
//

// Set to 1 to enable PPM input, 0 to disable. 
#define PPM_IN  0

// Button hold time for pause/unpause
#define BUTTON_HOLD_PAUSE_THRESH    1500    // 1.5 second button hold required to pause/unpause tracking.

// Set to 1 to enable support for positive shift PPM equipment, 0 for negative.
#define POSITIVE_SHIFT_PPM  1

// Fatshark headset headtracker module support. Set to 1 to enable.
// See: http://www.rcgroups.com/forums/showpost.php?p=23051198&postcount=573
#define FATSHARK_HT_MODULE 0

//
// -- End of user-configurable parameters.
//-----------------------------------------------------------------------------

//=============================================================================

//-----------------------------------------------------------------------------
// The user generally won't need to touch any of the following
//

// Firmware Version, e.g. X.YY
#define FIRMWARE_VERSION_FLOAT  1.04    // 2 decimal places

// Number of PPM channels out. 1 - 12 channels supported. 
#define NUMBER_OF_CHANNELS 8

// Define for extra debug serial info
#define DEBUG 0

// Output serial data to host evern X frames
#define SERIAL_OUTPUT_FRAME_INTERVAL    10

// Serial communication speed. 
//#define SERIAL_BAUD 57600
#define SERIAL_BAUD 115200

// Sensor board update-rate. Not done yet. 
#define UPDATE_RATE 50

// Dead-time between each channel in the PPM-stream. 
#define DEAD_TIME 800

// Sets the frame-length .
#define FRAME_LENGTH (5003 + NUMBER_OF_CHANNELS * 5000)

// TOP (timer rollover) used for PPM pulse time measurement
#define TOP (5003 + NUMBER_OF_CHANNELS * 5000)

// Set to 0, stored gyro calibration is used. If 1, gyro is calibrated at powerup  
#define ALWAYS_CAL_GYRO 0

// Center/pause input button pin number
#define BUTTON_INPUT 11

// Arduino LED
#define  ARDUINO_LED 13

// Pin definition for LED and buzzer (Fatshark goggles)
#if FATSHARK_HT_MODULE
    #define  BUZZER      4
#endif

#define PPM_IN_MIN 1000 // 0.5 ms
#define PPM_IN_MAX 4000 // 2 ms

// Settings stuff
//
#define HT_TILT_REVERSE_BIT     0x01
#define HT_ROLL_REVERSE_BIT     0x02
#define HT_PAN_REVERSE_BIT      0x04

#endif

Код facetrack.cpp

#include <Wire.h>
#include "config.h"
#include "functions.h"
#include "sensors.h"
#include <EEPROM.h>

float XZero,YZero,ZZero;
typedef struct {
  int16_t  Begin  ;   // 2  Debut
  uint16_t Cpt ;      // 2  Compteur trame or Code info or error
  float    gyro[3];   // 12 [Y, P, R]    gyro
  float    acc[3];    // 12 [x, y, z]    Acc
  int16_t  End ;      // 2  Fin
} 
_hat;

uint16_t unit;

extern float panAngle;
extern float tiltAngle;
extern float rollAngle;

typedef struct  {
  int16_t Begin  ;   // 2  Debut
  uint16_t Code ;     // 2  Code info
  char     Msg[24];   // 24 Message
  int16_t End ;      // 2  Fin
} 
_msginfo;

_msginfo msginfo;
_hat hat;
float yaw;
float pitch;
float roll;
int Mag_HardIron_On=0;
int Acc_Calib_On=0;
void PrintCodeSerial(uint16_t code,char Msg[24],bool EOL ) {
  msginfo.Code=code;
  memset(msginfo.Msg,0x00,24);
  strcpy(msginfo.Msg,Msg);
  if (EOL) msginfo.Msg[23]=0x0A;
  // Send HATIRE message to  PC
   Serial.write((byte*)&msginfo,30);
}
//att_t att;
void FT_Setup()
{
  hat.Begin=0xAAAA;
  hat.Cpt=0;
  hat.End=0x5555;
  msginfo.Begin=0xAAAA;
  msginfo.Code=0;
  msginfo.End=0x5555;
  PrintCodeSerial(5000,"HAT BEGIN",true); 
  yaw=panAngle;
  pitch=tiltAngle;
  roll=rollAngle;
  XZero=yaw;
  YZero=pitch;
  ZZero=roll;
}

void serialEvent()
{
  char Commande;
   Commande = (char)Serial.read();
  switch (Commande) 
  {
  case 'Z':
    // last_z_angle=0;
    yaw=panAngle;
    pitch=tiltAngle;
    roll=rollAngle;
    XZero=(yaw);
    YZero=(pitch);
    ZZero=(roll);
    //PrintCodeSerial(5000,"Generated",true); 
    break; 
  }
  if (Commande == 'h')
  {
    Mag_HardIron_On=1; 
  }
  if (Commande == 'a')
  {
    Acc_Calib_On=1; 
    for (int i = 0; i < 3; i++) 
    {
      //   accel_min[i]=0;
      // accel_max[i]=0;
    }
  }
  if (Commande == 's') // _s_ynch request
  {
    // Read ID
    //        byte id[2];
    //        id[0] = readChar();
    //        id[1] = readChar();

    // Reply with synch message
    //        Serial.print("#SYNCH");
    //        Serial.write(id, 2);
    //        Serial.println();
    //        Calib_On=1;
  } 
}


void FTData()
{
  if(Serial.available() > 0)  serialEvent();
//    roll=rollAngle;
//    yaw=panAngle;  
//    pitch=tiltAngle;
  yaw=panAngle;
  pitch=tiltAngle;
  roll=rollAngle;
  hat.gyro[0]=yaw-XZero;
  hat.gyro[1]=pitch-YZero;
  hat.gyro[2]=roll-ZZero;

     Serial.write((byte*)&hat,30);
  hat.Cpt++;
  if (hat.Cpt>999) {
    hat.Cpt=0;
  }
  delay(10); 


}


Код facetrack.h

void FTData();
void FT_Setup();

Код functions.cpp

//-----------------------------------------------------------------------------
// File: Functions.cpp
// Desc: Implementations of PPM-related functions for the project.
//-----------------------------------------------------------------------------
#include "config.h"
#include "Arduino.h"
#include "functions.h"
#include "sensors.h"
#include <Wire.h>

extern long channel_value[];

// Local variables
unsigned int pulseTime = 0; 
unsigned int lastTime = 0; 
unsigned int timeRead; 
int channelsDetected = 0;
char channel = 0;
int channelValues[20]; 
char state = 0; // PPM signal high or Low?
char read_sensors = 0;

// external variables
extern unsigned long buttonDownTime;
extern unsigned char htChannels[];

// Sensor_board,   x,y,z
int acc_raw[3]  = {1,2,3};  
int gyro_raw[3] = {4,5,6};
int mag_raw[3]  = {7,8,9};

unsigned char PpmIn_PpmOut[13] = {0,1,2,3,4,5,6,7,8,9,10,11,12};
long channel_value[13] = {2100,2100,2100,2100,2100,2100,2100,2100,2100,2100,2100,2100,2100};

unsigned char channel_number = 1;
char shift = 0;
char time_out = 0;

//--------------------------------------------------------------------------------------
// Func: PrintPPM
// Desc: Prints the channel value represented in the stream. Debugging assistant. 
//--------------------------------------------------------------------------------------
void PrintPPM()
{
  for (char j = 1; j < 13; j++)
  {
      Serial.print(channel_value[j]);
      Serial.print(",");
  }
  Serial.println();
  
}

//--------------------------------------------------------------------------------------
// Func: InitPWMInterrupt
// Desc: 
//--------------------------------------------------------------------------------------
void InitPWMInterrupt()
{
#if (DEBUG)    
    Serial.println("PWM interrupt initialized");
#endif
  
    TCCR1A = 
       (0 << WGM10) |
       (0 << WGM11) |
       (0 << COM1A1) |
       (1 << COM1A0) | // Toggle pin om compare-match
       (0 << COM1B1) |
       (0 << COM1B0);  
  
    TCCR1B =
        (1 << ICNC1)| // Input capture noise canceler - set to active 
        (1 << ICES1)| // Input capture edge select. 1 = rising, 0 = falling. We will toggle this, doesn't matter what it starts at        
        (0 << CS10) | // Prescale 8  
        (1 << CS11) | // Prescale 8  
        (0 << CS12) | // Prescale 8
        (0 << WGM13)|    
        (1 << WGM12); // CTC mode (Clear timer on compare match) with ICR1 as top.           
    
    // Not used in this case:
    TCCR1C =
        (0 << FOC1A)| // No force output compare (A)
        (0 << FOC1B); // No force output compare (B)
        
    
    TIMSK1 = 
        (PPM_IN << ICIE1) | // Enable input capture interrupt    
        (1 << OCIE1A) | // Interrupt on compare A
        (0 << OCIE1B) | // Disable interrupt on compare B    
        (0 << TOIE1);          

    // OCR1A is used to generate PPM signal and later reset counter (to control frame-length)
    OCR1A = DEAD_TIME;    
}

//--------------------------------------------------------------------------------------
// Func: InitTimerInterrupt
// Desc: Initializes timer interrupts.
//--------------------------------------------------------------------------------------
void InitTimerInterrupt()
{  
#if (DEBUG)    
    Serial.println("Timer interrupt initialized");
#endif
  
    TCCR0A = 
       (0 << WGM00) |
       (1 << WGM01) |
       (0 << COM0A1) |
       (0 << COM0A0) |
       (0 << COM0B1) |
       (0 << COM0B0);  
   
    // 61 hz update-rate:
    TCCR0B =
        (0 << FOC0A)| // 
        (0 << FOC0B)| // 
        (1 << CS00) | // Prescale 1024 
        (0 << CS01) | // Prescale 1024  
        (1 << CS02) | // Prescale 1024
        (0 << WGM02);
  
    TIMSK0 = 
        (0 << OCIE0B) |
        (1 << OCIE0A) |
        (1 << TOIE0);       

    OCR0B = 64 * 2; 
    OCR0A = 64 * 2;
}

//--------------------------------------------------------------------------------------
// Func: TIMER1_OVF_vect
// Desc: Timer 1 overflow vector - only here for debugging/testing, as it should always
//      be reset/cleared before overflow. 
//--------------------------------------------------------------------------------------
ISR(TIMER1_OVF_vect)
{
    Serial.print("Timer 1 OVF");
}

//--------------------------------------------------------------------------------------
// Func: TIMER1_COMPA_vect
// Desc: Timer 1 compare A vector
//--------------------------------------------------------------------------------------
ISR(TIMER1_COMPA_vect)
{
    if (OCR1A == FRAME_LENGTH)
    {
        TCCR1A = 
            (0 << WGM10) |
            (0 << WGM11) |
            (1 << COM1A1) |
            (1 << COM1A0) |
            (0 << COM1B1) |
            (0 << COM1B0);   
  
        channel_number = 1;
        OCR1A = DEAD_TIME;
  
        TCCR1B &= ~(1 << WGM12);
    }
    else
    {
        if (channel_number == 1)
        {
            // After first time, when pin have been set high, we toggle the pin at each interrupt
            TCCR1A = 
                (0 << WGM10) |
                (0 << WGM11) |
                (0 << COM1A1) |
                (POSITIVE_SHIFT_PPM << COM1A0) |
                (0 << COM1B1) |
                (0 << COM1B0);   
        }
                  
        if ((channel_number - 1) < NUMBER_OF_CHANNELS * 2)
        {
            if ((channel_number-1) % 2 == 1)
            {
                OCR1A += DEAD_TIME; 
            }
            else
            {
                OCR1A += channel_value[(channel_number + 1) / 2];
            }
            channel_number++;
        }
        else
        {
            // We have to use OCR1A as top too, as ICR1 is used for input capture and OCR1B can't be
            // used as top. 
            OCR1A = FRAME_LENGTH;
            TCCR1B |= (1 << WGM12);
        }
    }
}  

//--------------------------------------------------------------------------------------
// Func: TIMER0_COMPA_vect
// Desc: Timer 0 compare A vector Sensor-interrupt. We query sensors on a timer, not
//          during every loop.
//--------------------------------------------------------------------------------------
ISR(TIMER0_COMPA_vect)
{
    // Reset counter - should be changed to CTC timer mode. 
    TCNT0 = 0;

/*
    // Used to check timing - have the previous calculations been done?
    // Will always show in start, but should stop when initialized. 
    if (shift == 1)
    {
        //digitalWrite(7,HIGH); 
        shift = 0;
    }
    else
    {
        //digitalWrite(7,LOW);
        shift = 1; 
    }
 */

#if (DEBUG == 1)  
    if (read_sensors == 1)
    {
        time_out++;
        if (time_out > 10)
        {
            //Serial.println("Timing problem!!!"); 
            time_out = 0;  
        }
    }
#endif
    read_sensors = 1;
    buttonDownTime += 16; // every 16 milliseconds, at 61 hz.
}

//--------------------------------------------------------------------------------------
// Func: DetectPPM
// Desc: 
//--------------------------------------------------------------------------------------
void DetectPPM()
{  
    // If a new frame is detected
    if (pulseTime > 5500)
    {
        // Save total channels detected
        channelsDetected = channel; 
     
        // Reset channel-count
        channel = 0; 
    }
    else if (channel < 20 && pulseTime > PPM_IN_MIN && pulseTime < PPM_IN_MAX)
    {
        // If the pulse is recognized as servo-pulse
        if ( (channel + 1) != htChannels[0] &&
             (channel + 1) != htChannels[1] &&
             (channel + 1) != htChannels[2] )
        {
            channelValues[channel++] = pulseTime;
            channel_value[PpmIn_PpmOut[channel]] = pulseTime;
        }
    }  
    else if (pulseTime > PPM_IN_MIN)
    {
        channel++;
    }
}  

//--------------------------------------------------------------------------------------
// Func: TIMER1_CAPT_vect
// Desc: The interrupt vector used when an edge is detected Interrupt vector, see page
//      57 Interrupt for input capture
//--------------------------------------------------------------------------------------
ISR(TIMER1_CAPT_vect)
{
    // Disable interrupt first, to avoid multiple interrupts causing hanging/restart,
    // or just weird behavior:
    TIMSK1 &= ~(1 << ICIE1);
    
    state = TCCR1B & (1 << ICES1);
    
    // Toggle interrupt to detect falling/rising edge:
    TCCR1B ^= (1<<ICES1);
    
    // Read the time-value stored in ICR1 register (will be the time copied from TCNT1 at input-capture event). 
    timeRead = ICR1;    
    
    pulseTime = timeRead; 
    
    // Check if the timer have reached top/started over:
    if (lastTime > pulseTime)
    {
        pulseTime += (TOP - lastTime); 
    }
    else
    {
        // Subtract last time to get the time:
        pulseTime -= lastTime;
    }
    
    // Save current timer-value to be used in next interrupt:
    lastTime = timeRead;
    
    // If we are detecting a PPM input signal
    DetectPPM(); 
    
    // Enable interrupt again:
    TIMSK1 |= (1 << ICIE1); 
}

Код functions.h

//-----------------------------------------------------------------------------
// File: Functions.h
// Desc: Declares PPM-related functions for the project.
//-----------------------------------------------------------------------------
#ifndef functions_h
#define functions_h

void InitTimerInterrupt();
void InitPWMInterrupt();
void DetectPPM();
void PrintPPM();
void DetectPPM();

#endif

Код sensors.cpp

//-----------------------------------------------------------------------------
// File: Sensors.cpp
// Desc: Implementations sensor board functionality.
//-----------------------------------------------------------------------------
#include "config.h"
#include "Arduino.h"
#include "functions.h"
#include <Wire.h>
#include <Sensors.h>
/*
Reference for basic sensor/IMU understanding/calculation:
http://www.starlino.com/imu_guide.html
http://www.sparkfun.com/datasheets/Sensors/Magneto/Tilt%20Compensated%20Compass.pdf
https://www.loveelectronics.co.uk/Tutorials/13/tilt-compensated-compass-arduino-tutorial
http://www.pololu.com/file/download/LSM303DLH-compass-app-note.pdf?file_id=0J434
*/


 //   att_t att;

// Gyro
//
#define ITG3205_ADDR 0x68    // The address of ITG3205
#define ITG3205_X_ADDR 0x1D  // Start address for x-axis
#define SCALING_FACTOR 13     // Scaling factor - used when converting to angle

// Accelerometer
//
#define ADXL345_ADDR (0x53)  // The adress of ADXL345 
#define ADXL345_X_ADDR (0x32)// Start address for x-axis
#define ACC_SENS 256         // Sensitivity. 13 bit adc, +/- 16 g. Calculated as: (2^13)/(16*2)
#define ASSUME_1G_ACC 0      // Assuming the total gravitation is 1. True if only earth gravitation has influence.  


// Magnetometer
//
#define HMC_ADDR 0x1E        // The address of HMC5883
#define HMC_X_ADDR (0x03)    // Start address for x-axis. 

#define SAMPLERATE 128       // Samplerate of sensors (in hz, samples per second)

unsigned char ADXL345_ID = 0;
unsigned char ITG3205_ID = 0;
unsigned char HMC_ID = 0;

// Variables defined elsewhere
//
extern long channel_value[];

// Local variables
//
byte sensorBuffer[10];       // Buffer for bytes read from sensors
char resetValues = 1;        // Used to reset headtracker/re-center. 

long accRaw[3];              // Raw readings from accelerometer
float accG[3];               // G-force in each direction
float accAngle[3];           // Measured angle from accelerometer
float R;                     // Unit vector - total G.

float gyroRaw[3];            // Raw readings from gyro
float angle[3];              // Angle from gyro 
float angleRaw[3];           // Temp for angle-calculation

float magRaw[3];             // Raw readings from magnetometer
float magAngle[3];           // Measured angles from magnetometer
float mx = 0;                // Calculated magnetometer value in x-direction with pan/tilt compensation
float my = 0;                // Calculated magnetometer value in y-direction with pan/tilt compensation

int magPosOff[3];
int magNegOff[3];
float magGain[3];

#define MAG0MAX 625
#define MAG1MAX 625
#define MAG2MAX 625
#define MAG0MIN -625
#define MAG1MIN -625
#define MAG2MIN -625


// Final angles for headtracker:
float tiltAngle = 90;       // Tilt angle
float tiltAngleLP = 90;     // Tilt angle with low pass FilterSensorData
float lastTiltAngle = 90;   // Used in low pass FilterSensorData.

float rollAngle = 0;        // Roll angle
float rollAngleLP = 90;     // Roll angle with low pass FilterSensorData
float lastRollAngle = 90;   // Used in low pass FilterSensorData

float panAngle = 90;        // Pan angle
float panAngleLP = 90;      // Pan angle with low pass FilterSensorData
float lastPanAngle = 90;    // Used in low pass FilterSensorData

// Start values - center position for head tracker
float tiltStart = 0;
float panStart = 0;
float rollStart = 0;

char TrackerStarted = 0;

// Servo reversing
char tiltInverse = -1;
char rollInverse = -1;
char panInverse = -1;


// Settings
//
float tiltRollBeta = 0.75;
float panBeta = 0.75;
float gyroWeightTiltRoll = 0.98;
float GyroWeightPan = 0.98;
int servoPanCenter = 2100;
int servoTiltCenter = 2100;
int servoRollCenter = 2100;
int panMaxPulse = 1150;
int panMinPulse = 1150;
int tiltMaxPulse = 1150;
int tiltMinPulse = 1150;
int rollMaxPulse = 1150;
int rollMinPulse = 1150;
float panFactor = 17;
float tiltFactor = 17;
float rollFactor = 17;
unsigned char servoReverseMask = 0;
int accOffset[3] = {0, 0, 0}; 
float magOffset[3] = {(MAG0MAX + MAG0MIN) / 2, (MAG1MAX + MAG1MIN) / 2, (MAG2MAX + MAG2MIN) / 2};
float gyroOff[3] = {0, 0, 0};
unsigned char htChannels[3] = {8, 7, 6}; // pan, tilt, roll
//
// End settings


// Function used to write to I2C:
void WriteToI2C(int device, byte address, byte val)
{
    Wire.beginTransmission(device);
    Wire.write(address);
    Wire.write(val);
    Wire.endTransmission();
}

// Function to read from I2C
void ReadFromI2C(int device, char address, char bytesToRead)
{
    Wire.beginTransmission(device);
    Wire.write(address);
    Wire.endTransmission();
  
    Wire.beginTransmission(device);
    Wire.requestFrom(device, bytesToRead);
   
    char i = 0;   
    while ( Wire.available() )
    {
        sensorBuffer[i++] = Wire.read();
    }   
    Wire.endTransmission();
}

void trackerOutput()
{
  Serial.print(tiltAngleLP - tiltStart + 90);
  Serial.print(",");
  Serial.print(rollAngleLP - rollStart + 90);
  Serial.print(",");  
  Serial.println(panAngleLP + 180);
}

void calMagOutput()
{
    Serial.print((int)magRaw[0] + 3000);
    Serial.print(",");
    Serial.print((int)magRaw[1] + 3000);
    Serial.print(",");    
    Serial.println((int)magRaw[2] + 3000);   
}

void calAccOutput()
{
    Serial.print((int)accRaw[0] + 3000);  
    Serial.print(",");          
    Serial.print((int)accRaw[1] + 3000);  
    Serial.print(",");              
    Serial.println((int)accRaw[2] + 3000);  
}

void calMagAccOutput()
{
    Serial.print((int)magRaw[0] + 3000);
    Serial.print(",");
    Serial.print((int)magRaw[1] + 3000);
    Serial.print(",");    
    Serial.print((int)magRaw[2] + 3000);
    Serial.print(","); 
    Serial.print((int)accRaw[0] + 3000);  
    Serial.print(",");          
    Serial.print((int)accRaw[1] + 3000);  
    Serial.print(",");              
    Serial.println((int)accRaw[2] + 3000); 
}

//--------------------------------------------------------------------------------------
// Func: UpdateSensors
// Desc: Retrieves the sensor data from the sensor board via I2C.
//--------------------------------------------------------------------------------------
void UpdateSensors()
{

    // Read x, y, z acceleration, pack the data.
    ReadFromI2C(ADXL345_ADDR, ADXL345_X_ADDR, 6);
    accRaw[0] = ((int)sensorBuffer[0] | ((int)sensorBuffer[1] << 8)) * -1;
    accRaw[1] = ((int)sensorBuffer[2] | ((int)sensorBuffer[3] << 8)) * -1;       
    accRaw[2] = (int)sensorBuffer[4] | ((int)sensorBuffer[5] << 8);       
   
   
    // Read x, y, z from gyro, pack the data
    ReadFromI2C(ITG3205_ADDR, ITG3205_X_ADDR, 6);
    gyroRaw[0] = (int)sensorBuffer[1] | ((int)sensorBuffer[0] << 8);
    gyroRaw[1] = ( (int)sensorBuffer[3] | ((int)sensorBuffer[2] << 8) ) * -1;
    gyroRaw[2] = ( (int)sensorBuffer[5] | ((int)sensorBuffer[4] << 8) ) * -1;
   
   
    // Read x, y, z from magnetometer;
    ReadFromI2C(HMC_ADDR, HMC_X_ADDR, 6);
    for (unsigned char i =0; i < 3; i++)
    {
       magRaw[i] = (int)sensorBuffer[(i * 2) + 1] | ((int)sensorBuffer[i * 2] << 8);
    }    
}

//--------------------------------------------------------------------------------------
// Func: SetGyroOffset
// Desc: Sets the gyro offset.
//--------------------------------------------------------------------------------------
void SetGyroOffset()
{
    // Not sure what the outer loops are for, Dennis. Stabilization time?
    //
    for (unsigned int i = 0; i < 100; i++)
    {
        UpdateSensors();
        for (unsigned char k = 0; k < 3; k++)
        {
            gyroOff[k] += gyroRaw[k];
        }
    }
 
    for (unsigned char k = 0; k < 3; k++)
    {
        gyroOff[k] = gyroOff[k] / 100;
    }
     
#if (DEBUG)     
    Serial.print("Gyro offset measured:");
    Serial.print(gyroOff[0]);
    Serial.print(",");   
    Serial.print(gyroOff[1]);
    Serial.print(",");      
    Serial.println(gyroOff[2]);    
#endif 
}

//--------------------------------------------------------------------------------------
// Func: CalibrateMag
// Desc: 
//--------------------------------------------------------------------------------------
void CalibrateMag()
{  
    WriteToI2C(HMC_ADDR, 0x00, 0b00010001);

    // MM: Again with the loops. Not sure what purpose this serves, Dennis.
    for (unsigned char i = 0; i < 40; i++)
    {
        UpdateSensors(); 
    }
    magPosOff[0] = magRaw[0];
    magPosOff[1] = magRaw[1];
    magPosOff[2] = magRaw[2];  
  
  
    WriteToI2C(HMC_ADDR, 0x00, 0b00010010);

    for (unsigned char i = 0; i < 40; i++)
    {
        UpdateSensors(); 
    }
    magNegOff[0] = magRaw[0];
    magNegOff[1] = magRaw[1];
    magNegOff[2] = magRaw[2];  
    
    WriteToI2C(HMC_ADDR, 0x00, 0b00010000);

    magGain[0] = -2500 / float(magNegOff[0] - magPosOff[0]);
    magGain[1] = -2500 / float(magNegOff[1] - magPosOff[1]);
    magGain[2] = -2500 / float(magNegOff[2] - magPosOff[2]); 
  
    for (unsigned char i = 0; i < 40; i++)
    {
        UpdateSensors(); 
    }  
  
#if (DEBUG)
    Serial.print("Mag cal:");
    Serial.print(magNegOff[0] - magPosOff[0]);
    Serial.print(",");   
    Serial.print(magNegOff[1] - magPosOff[1]);
    Serial.print(",");      
    Serial.print(magNegOff[2] - magPosOff[2]);
   
    Serial.print(",");      
    Serial.print(magGain[0]);
    Serial.print(",");   
    Serial.print(magGain[1]);
    Serial.print(",");      
    Serial.println(magGain[2]);   
   
   
    Serial.print("Mag offset:");
    Serial.print(magOffset[0]);
    Serial.print(",");   
    Serial.print(magOffset[1]);
    Serial.print(",");      
    Serial.println(magOffset[2]);    
#endif          
}


//--------------------------------------------------------------------------------------
// Func: GyroCalc
// Desc: Calculate angle from gyro-data
//--------------------------------------------------------------------------------------
void GyroCalc()
{    
#if (DEBUG)
    for (unsigned char i=0; i<3; i++)
    {
        angleRaw[i]+=((gyroRaw[i]-gyroOff[i]));
        angle[i] = angleRaw[i]/(SAMPLERATE*SCALING_FACTOR);
    }
#endif          
}
   
//--------------------------------------------------------------------------------------
// Func: AccelCalc
// Desc: Calculate angle from accelerometer data
//--------------------------------------------------------------------------------------
void AccelCalc()
{
    accRaw[0] += accOffset[0];
    accRaw[1] += accOffset[1];
    accRaw[2] += accOffset[2];   
  
    for (unsigned char i = 0; i<3; i++)
    {
        accG[i] = (float)accRaw[i] / ACC_SENS;
    }
     
    // So, lets calculate R
    // R^2 = Rx^2+Ry^2+Rz^2    
    #if (ASSUME_1G_ACC == 0) 
        R = sqrt((accG[0] * accG[0]) + (accG[1] * accG[1]) + (accG[2] * accG[2]));
    #else // Otherwise, just assume total G = 1.
        R = 1;
    #endif
      
    // Calculate final angles:
    if (R < 1.3 && R > 0.7)
    { 
        for (unsigned char i = 0; i<3; i++)
        {
            accAngle[i] = acos(accG[i] / R) * 57.3;
        }  
    }
}

//--------------------------------------------------------------------------------------
// Func: MagCalc
// Desc: Calculates angle from magnetometer data.
//--------------------------------------------------------------------------------------
void MagCalc()
{
    // Invert 2 axis  
    magRaw[1] *= -1;
    magRaw[2] *= -1;
    
    // Set gain:
    magRaw[0] *= magGain[0];
    magRaw[1] *= magGain[1];
    magRaw[2] *= magGain[2];    
    
    magRaw[0] -= magOffset[0];
    magRaw[1] -= magOffset[1];
    magRaw[2] -= magOffset[2];    
  
    float testAngle = tiltAngle - 90;
    mx = magRaw[0] * cos((testAngle) / 57.3)
        + magRaw[1] * sin(testAngle / 57.3);

    my = magRaw[0] * sin((rollAngle - 90) / 57.3)
        * sin((tiltAngle - 90) / 57.3)
        + magRaw[2] * cos((rollAngle - 90) / 57.3)
        - magRaw[1] * sin((rollAngle - 90) / 57.3)
        * cos((tiltAngle - 90) / 57.3);
      
    // Calculate pan-angle from magnetometer. 
    magAngle[2] = (atan(mx / my) * 57.3 + 90);

    // Get full 0-360 degrees. 
    if (my < 0)
    {
        magAngle[2] += 180;
    }
    
    float tempAngle = panStart - magAngle[2];
      
    if (tempAngle > 180)
    {
        tempAngle -= 360; 
    }  
    else if (tempAngle < -180)
    {
        tempAngle += 360; 
    }
      
    magAngle[2] = tempAngle * -1;
}


//--------------------------------------------------------------------------------------
// Func: Filter
// Desc: Filters / merges sensor data. 
//--------------------------------------------------------------------------------------
void FilterSensorData()
{
    int temp = 0;

    // Used to set initial values. 
    if (resetValues == 1)
    {
#if FATSHARK_HT_MODULE
        digitalWrite(BUZZER, HIGH);
#endif
        resetValues = 0; 
      
        tiltStart = 0;
        panStart = 0;
        rollStart = 0;
  
        UpdateSensors();    
        GyroCalc();
        AccelCalc();
        MagCalc();
        
        panAngle = 0;
        tiltStart = accAngle[0];
        panStart = magAngle[2];
        rollStart = accAngle[1];

#if FATSHARK_HT_MODULE
        digitalWrite(BUZZER, LOW);
#endif
    }

    // Simple FilterSensorData, uses mainly gyro-data, but uses accelerometer to compensate for drift
    rollAngle = (rollAngle + ((gyroRaw[0] - gyroOff[0]) * cos((tiltAngle - 90) / 57.3) + (gyroRaw[2] - gyroOff[2]) * sin((tiltAngle - 90) / 57.3)) / (SAMPLERATE * SCALING_FACTOR)) * gyroWeightTiltRoll + accAngle[1] * (1 - gyroWeightTiltRoll);
    tiltAngle = (tiltAngle + ((gyroRaw[1] - gyroOff[1]) * cos((rollAngle - 90) / 57.3) + (gyroRaw[2] - gyroOff[2]) * sin((rollAngle - 90) / 57.3) * -1) / (SAMPLERATE * SCALING_FACTOR)) * gyroWeightTiltRoll + accAngle[0] * (1 - gyroWeightTiltRoll);
    panAngle  = (panAngle + ((gyroRaw[2] - gyroOff[2]) * cos((tiltAngle - 90) / 57.3) + (((gyroRaw[0] - gyroOff[0]) * -1) * (sin((tiltAngle - 90) / 57.3)) ) + ( ((gyroRaw[1] - gyroOff[1]) * 1) * (sin((rollAngle - 90) / 57.3)))) / (SAMPLERATE * SCALING_FACTOR)) * GyroWeightPan + magAngle[2] * (1 - GyroWeightPan);
//    att_t.angle[0]=panAngle;

    if (TrackerStarted)
    {
        // All low-pass filters
        tiltAngleLP = tiltAngle * tiltRollBeta + (1 - tiltRollBeta) * lastTiltAngle;
        lastTiltAngle = tiltAngleLP;
  
        rollAngleLP = rollAngle * tiltRollBeta + (1 - tiltRollBeta) * lastRollAngle;
        lastRollAngle = rollAngleLP;

        panAngleLP = panAngle * panBeta + (1 - panBeta) * lastPanAngle;
        lastPanAngle = panAngleLP;

        float panAngleTemp = panAngleLP * panInverse * panFactor;
        if ( (panAngleTemp > -panMinPulse) && (panAngleTemp < panMaxPulse) )
        {
            temp = servoPanCenter + panAngleTemp;
            channel_value[htChannels[0]] = (int)temp;
        }    

        float tiltAngleTemp = (tiltAngleLP - tiltStart) * tiltInverse * tiltFactor;
        if ( (tiltAngleTemp > -tiltMinPulse) && (tiltAngleTemp < tiltMaxPulse) )
        {
            temp = servoTiltCenter + tiltAngleTemp;
            channel_value[htChannels[1]] = temp;
        }   

        float rollAngleTemp = (rollAngleLP - rollStart) * rollInverse * rollFactor;
        if ( (rollAngleTemp > -rollMinPulse) && (rollAngleTemp < rollMaxPulse) )
        {
            temp = servoRollCenter + rollAngleTemp;
            channel_value[htChannels[2]] = temp;
        }
    }
}

//--------------------------------------------------------------------------------------
// Func: InitSensors
// Desc: Initializes the sensor board sensors.
//--------------------------------------------------------------------------------------
void InitSensors()
{
    ReadFromI2C(ITG3205_ADDR, 0x00, 1);
    ITG3205_ID = sensorBuffer[0];
 
#if (DEBUG)    
    Serial.print("ITG3205: ");
    Serial.print(sensorBuffer[0]);
#endif 
 
    ReadFromI2C(ADXL345_ADDR, 0x00, 1);
    ADXL345_ID = sensorBuffer[0];
 
#if (DEBUG)     
    Serial.print("    ADXL: ");
    Serial.print(sensorBuffer[0]); 
#endif  

    // Accelerometer increase G-range (+/- 16G)
    WriteToI2C(ADXL345_ADDR, 0x31, 0b00001011);        
    ReadFromI2C(HMC_ADDR, 0x00, 1);
    HMC_ID = sensorBuffer[0];
 
#if (DEBUG)     
    Serial.print("    HMC: ");
    Serial.println(sensorBuffer[0]); 
#endif  

    WriteToI2C(ITG3205_ADDR, 22, 24);

    //  ADXL345 POWER_CTL
    WriteToI2C(ADXL345_ADDR, 0x2D, 0); 
    WriteToI2C(ADXL345_ADDR, 0x2D, 16);
    WriteToI2C(ADXL345_ADDR, 0x2D, 8);

    // HMC5883
    // Run in continuous mode
    WriteToI2C(HMC_ADDR, 0x02, 0x00);    
 
#if (ALWAYS_CAL_GYRO)
    // Set sensor offset
    SetGyroOffset();
#endif 
}

//--------------------------------------------------------------------------------------
// Func: ResetCenter
// Desc: Utility for resetting tracker center. This is only called during tracker
//       startup. Button press resets are handled during filtering. (Needs refactor)
//--------------------------------------------------------------------------------------
void ResetCenter()
{
    resetValues = 0; 
    
    // Not sure what Dennis is doing here. Giving it
    // time to stabilize, since this is called at setup time?
    for (unsigned char k = 0; k < 250; k++)
    {
        UpdateSensors();    
        GyroCalc();
        AccelCalc();
        MagCalc();
        FilterSensorData();    
    }
    
    tiltStart = accAngle[0];
    panStart = magAngle[2];
    rollStart = accAngle[1];  
  
    UpdateSensors();    
    GyroCalc();
    AccelCalc();
    MagCalc();
    FilterSensorData();    
  
    panAngle = magAngle[2];
    tiltAngle = accAngle[0];
    rollAngle = accAngle[1];
    
    TrackerStarted = 1;
}

//--------------------------------------------------------------------------------------
// Func: SensorInfoPrint
// Desc: Prints the mag sensor data.
//--------------------------------------------------------------------------------------
void SensorInfoPrint()
{ 
   Serial.print("Mag cal:");
   Serial.print(magNegOff[0] - magPosOff[0]);
   Serial.print(",");   
   Serial.print(magNegOff[1] - magPosOff[1]);
   Serial.print(",");      
   Serial.print(magNegOff[2] - magPosOff[2]);
   
   Serial.print(",");      
   Serial.print(magGain[0]);
   Serial.print(",");   
   Serial.print(magGain[1]);
   Serial.print(",");      
   Serial.println(magGain[2]);   

   Serial.print("ADXL345 ID: ");
   Serial.println((int)ADXL345_ID); 
   Serial.print("ITG3205 ID: ");
   Serial.println((int)ITG3205_ID); 
   Serial.print("HMC ID: ");
   Serial.println((int)HMC_ID);   
}


// ===============================================
//      ---------- Test functions -----------
// ===============================================
/*
void testAccOutput()
{
    Serial.print("RAW: ");  
    Serial.print(accRaw[0]);  
    Serial.print(" ");          
    Serial.print(accRaw[1]);  
    Serial.print(" ");              
    Serial.print(accRaw[2]);  

    Serial.print("\t G: ");        
    Serial.print(accG[0]); 
    Serial.print(" ");    
    Serial.print(accG[1]); 
    Serial.print(" "); 
    Serial.print(accG[2]); 

    Serial.print("\t Ang: ");        
    Serial.print(accAngle[0]); 
    Serial.print(" ");    
    Serial.print(accAngle[1]); 
    Serial.print(" "); 
    Serial.println(accAngle[2]);
}

void testGyroOutput()
{  
    Serial.print("RAW: ");  
    Serial.print(gyroRaw[0]);  
    Serial.print(",");          
    Serial.print(gyroRaw[1]);  
    Serial.print(",");              
    Serial.print(gyroRaw[2]);   

    Serial.print(",");        
    Serial.print(angle[0]);  
    Serial.print(",");          
    Serial.print(angle[1]);  
    Serial.print(",");              
    Serial.println(angle[2]);
}

void testMagOutput()
{
    Serial.print(magRaw[0]);
    Serial.print(",");
    Serial.print(magRaw[1]);
    Serial.print(",");    
    Serial.print(magRaw[2]);    

    Serial.print(",");              
    Serial.print(magAngle[0]);  
    Serial.print(",");          
    Serial.print(magAngle[1]);  
    Serial.print(",");              
    Serial.println(magAngle[2]);      
}

void testTiltOutput()
{ 
    Serial.print(angle[1]);
    Serial.print(",");          
    Serial.print(accAngle[0]-tiltStart);
    Serial.print(",");          
    Serial.println(tiltAngle-tiltStart);
}

void testRollOutput()
{
    Serial.print(angle[0]);
    Serial.print(",");          
    Serial.print(accAngle[1]-rollStart);
    Serial.print(",");          
    Serial.println(rollAngle-rollStart);  
}

void testPanOutput()
{
    Serial.print(angle[2]);
    Serial.print(",");                  
    Serial.print(magAngle[2]);
    Serial.print(",");                  
    Serial.println(panAngle);
}

// output calculated values, output as "csv"
void testAllData()
{  
    // x
  Serial.print(angle[1]);
  Serial.print(",");          
  Serial.print(accAngle[0]-90);
  Serial.print(",");          
  Serial.print(tiltAngle-90);
  Serial.print(",");      
  
    // y
  Serial.print(angle[0]);
  Serial.print(",");          
  Serial.print(accAngle[1]-90);
  Serial.print(",");          
  Serial.print(rollAngle-90);  
  Serial.print(",");     
    
    // z
  Serial.print(angle[2]);
  Serial.print(",");                  
  Serial.print(magAngle[2]-panStart);
  Serial.print(",");                  
  Serial.println(panAngle);
}

// All sensor output as "csv". 
void testAllSensors()
{  
    Serial.print(accRaw[0]);  
    Serial.print(",");          
    Serial.print(accRaw[1]);  
    Serial.print(",");              
    Serial.print(accRaw[2]);  

    Serial.print(",");            
    Serial.print(gyroRaw[0]);  
    Serial.print(",");          
    Serial.print(gyroRaw[1]);  
    Serial.print(",");              
    Serial.print(gyroRaw[2]);  

    Serial.print(",");               
    Serial.print(magRaw[0]);  
    Serial.print(",");          
    Serial.print(magRaw[1]);  
    Serial.print(",");              
    Serial.println(magRaw[2]);      
}
*/

Код sensors.h

//-----------------------------------------------------------------------------
// File: Sensors.h
// Desc: Declares sensor-related functions for the project.
//-----------------------------------------------------------------------------
#ifndef sensors_h
#define sensors_h

#include "Arduino.h"



void InitSensors();
void WriteToI2C(int device, byte address, byte val);
void ReadFromI2C(int device, byte address, char bytesToRead);
void UpdateSensors();
void GyroCalc();
void AccelCalc();
void MagCalc();

void SetGyroOffset();
void testPanOutput();
void trackerOutput();
void calMagOutput();
void calAccOutput(); 
void calMagAccOutput(); // Output both mag and accel in one pass.
void CalibrateMag();
void FilterSensorData();
void ResetCenter();
void SensorInfoPrint();

void testAllSensors();
void testRollOutput();
void testAllData();
void testAccOutput();
void testGyroOutput();
void testMagOutput();

#endif // sensors_h

 

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

rilintar,

1. Где находятся все эти файлы?

2. Вы пытались перемещать файлы после того, как Arduino IDE была загружена?

3. Переместите все файлы в одну папку так, чтобы в пути к ней не было кириллических симворов и пробелов. Запустите среду, откройте ею файл *.ino и попытайтесь его откомпилировать.

rilintar
Offline
Зарегистрирован: 21.03.2017

andriano пишет:

rilintar,

1. Где находятся все эти файлы?

2. Вы пытались перемещать файлы после того, как Arduino IDE была загружена?

3. Переместите все файлы в одну папку так, чтобы в пути к ней не было кириллических симворов и пробелов. Запустите среду, откройте ею файл *.ino и попытайтесь его откомпилировать.

Попытался перенести на корень диска C:/ такая же ошибка

1. Все эти файлы находятся в папке, которая в свою очередь лежит в корне диска C:/

2. Нет

3. Так и пытался.

 

Увидел в расширенном коде ошибки что он обращается к local/temp/arduino_build...

решил очистить темп, запускаю, теперь ему не понравился config.h типа его нет,

захожу в темп/ардуино и вижу что arduino его скопировал добавив расширение .cpp и получился config.h.cpp на 35 кб 

решил удалить расширение .cpp и запустить снова. он снова его переименовал и выдал ошибку на 1200строк,

тогда я просто вручную скопировал config.h в темп и все равно та же ошибка снова вышла:

Arduino: 1.8.1 (Windows 10), Плата:"Arduino Nano, ATmega328"

sketch\Sensors.cpp:9:21: fatal error: Sensors.h: No such file or directory

 #include <Sensors.h>

                     ^

compilation terminated.

exit status 1
Ошибка компиляции для платы Arduino Nano.

Этот отчёт будет иметь больше информации с
включенной опцией Файл -> Настройки ->
"Показать подробный вывод во время компиляции"

Может проблема в том что он не хочет работать в необходимой папке, а лезет в темп?

 

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

ну да - у вас инклюд в угловых скобках а включен локально в папку скетча, должен быть в двойных кавычках
Сдаётся мне , что проект сей надо компилировать исключительно определённой версией IDE, там об этом ничего нет?

rilintar
Offline
Зарегистрирован: 21.03.2017

В этой статье не указана была версия ПО, а вы не подскажете какой возможной версией ide можно прошить?

sadman41
Offline
Зарегистрирован: 19.10.2016

Для начала в #include для всех файлов, которые физически лежат в каталоге со скетчем (см. сообщения компилятора), замените угловые скобки на двойные кавычки. Похоже, что это недосмотр автора скетча.

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

sadman41 пишет:

Для начала в #include для всех файлов, которые физически лежат в каталоге со скетчем (см. сообщения компилятора), замените угловые скобки на двойные кавычки. Похоже, что это недосмотр автора скетча.

там в библиотеках тоже вызовы с угловыми скобками, как-то всё враскорячку, можно попробовать по дате публикации версию IDE подобрать, аналогичный проект у меня компилировался только в 1.6.5, попробуйте

sadman41
Offline
Зарегистрирован: 19.10.2016
Все компилируется нормально в первом попавшемся IDE, если привести в порядок один #include и объявление функций WriteToI2C() / ReadFromI2C(). Автор там накидал вместе с нормальными byte еще и int/char вперемешку.
 
Sketch uses 20,566 bytes (63%) of program storage space. Maximum is 32,256 bytes.
Global variables use 1,487 bytes (72%) of dynamic memory, leaving 561 bytes for local variables. Maximum is 2,048 bytes.
ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

sadman41 пишет:

Все компилируется нормально в первом попавшемся IDE, если привести в порядок один #include и объявление функций WriteToI2C() / ReadFromI2C(). Автор там накидал вместе с нормальными byte еще и int/char вперемешку.
 
Sketch uses 20,566 bytes (63%) of program storage space. Maximum is 32,256 bytes.
Global variables use 1,487 bytes (72%) of dynamic memory, leaving 561 bytes for local variables. Maximum is 2,048 bytes.

выложите PSE поправленные файлы

sadman41
Offline
Зарегистрирован: 19.10.2016

Все прям выкладывать не буду, изменить надо в двух:

sensors.h:

...
void WriteToI2C(byte device, byte address, byte val);
void ReadFromI2C(byte device, byte address, byte bytesToRead);
...

Sensors.cpp:

...
#include "Sensors.h"
...
void WriteToI2C(byte device, byte address, byte val)
...
void ReadFromI2C(byte device, byte address, byte bytesToRead)

Компиляция проходит, но предупреждает, что в одном из циклов может возникнуть неопределенное поведение (выход за границы массива). В алгоритм не вникал, но увеличение его размерности (unsigned char channel_mapping[14]) варнинг снимает.

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

я инклюд то поправил, а вот дальше моих познаний не хватило ))) на Read/Write остановился

sadman41
Offline
Зарегистрирован: 19.10.2016

Просто замените в  sensors.h строчки:

void WriteToI2C(int device, byte address, byte val);
void ReadFromI2C(int device, byte address, char bytesToRead);

на:

void WriteToI2C(byte device, byte address, byte val);
void ReadFromI2C(byte device, byte address, byte bytesToRead);

И для sensors.cpp то же самое - void WriteToI2C(int device, byte address, byte val) на void WriteToI2C(byte device, byte address, byte val) и т.д.

(я просто уже потер скетч - он мне не нужен)

rilintar
Offline
Зарегистрирован: 21.03.2017

Спасибо большое всем кто откликнулся, помогли с советами.

Код после выше указанных манипуляций, скомпилировался и загрузился в штатном режиме без варнингов.