Акселерометр vs гироскоп

promistrio

И снова здравствуйте. Хотел отправится в тему для новичков, но данная проблема больше касается мультикоптеров, поэтому напишу здесь.

Представим, что нам нужно разработать систему стабилизации, полета и висения готовой многомоторной системы. В ней отсутствует только управляющая электроника. Дальше я буду приводить свои доводы, а вы, если что не так, поправляйте.

В общих словах:

Наша первая задача - осуществить висение. Для этого понадобятся акселерометр, чтобы определять направление силы тяжести, и сонар, для высоты. Дальше идет математика. Аксель показывает нормализованный по G вектор силы тяжести. Для висения необходимо довести двигатели до состояния, когда вектор G будет лежать на оси Z. С помощью сонара читаем высоту и регулирем мощность всех двигателей одновременно.

Добившись разными дополнительными манипуляциями висения, мы заметим, что коптер поступательно вращается в горизонтальной плоскости вокруг оси Z. Для решения этой проблемы нужен гироскоп. Но у меня возник другая мысль. А что если его заменить компасом? На вход контроллера будут поступать значения угла относительно севера, например ЮГ - это 180 градусов. И вот по таким данным устанавливать “курс” коптера. Что я потеряю, заменив гироскоп компасом?

Заранее спасибо.

P.S. Переход на готовую электронику не планируется. Почему? Уже надоело объяснять.

kostya-tin

ИМХО без гироскопа никуда. и тем более - нужно 3 оси. акселерометр во время движения не покажет правельную угловую скорость, особенно при, так сказать, разгоне и торможении. проще уже без акселерометра обойтись

promistrio

ИМХО без гироскопа никуда. и тем более - нужно 3 оси. акселерометр во время движения не покажет правельную угловую скорость, особенно при, так сказать, разгоне и торможении. проще уже без акселерометра обойтись

Угловая скорость вокруг какой оси?

Coreglider

Могу посоветовать почитать темку. Тут рассказывается обо всех сложностях создания велосипеда. В целом тема весьма неблагодарная и КРАЙНЕ мало кому под силу в одиночку создать что-то адекватно работающее. Вкратце гироскоп наш основной датчик, потому что довольно-таки точный, акселерометр и компас используется лишь для докалибровки постепенного ухода гироскопа. Их данные слишком шумные и не годятся для использования напрямую. Вообще, математика довольно сложная, с использованием кватернионов, микшер двигателей считается через матрицы, стоит ещё раз подумать надо ли оно вам.

Lisenok
Coreglider:

кватернионов

Кватернио́ны (от лат. quaterni, по четыре) — система гиперкомплексных чисел, образующая векторное пространство размерностью четыре над полем вещественных чисел. Предложены Уильямом Гамильтоном в 1843 году.

Кватернионы удобны для описания изометрий трёх- и четырёхмерного евклидовых пространств, и поэтому получили широкое распространение в механике. Также их используют в вычислительной математике, например, при создании трёхмерной графики.

promistrio

Кватернио́ны (от лат. quaterni, по четыре) — система гиперкомплексных чисел, образующая векторное пространство размерностью четыре над полем вещественных чисел. Предложены Уильямом Гамильтоном в 1843 году.

Кватернионы удобны для описания изометрий трёх- и четырёхмерного евклидовых пространств, и поэтому получили широкое распространение в механике. Также их используют в вычислительной математике, например, при создании трёхмерной графики.

Опыт работы с кватернионами есть. Занимаюсь трехмерной графикой.

cylllka
promistrio:

Угловая скорость вокруг какой оси?

По всем осям. Стабилизацией в основном занимается гироскоп, а акселерометр лишь помогает исправлять ошибки.

promistrio:

P.S. Переход на готовую электронику не планируется. Почему? Уже надоело объяснять.

А где объяснение то?

Coreglider

Короче, как уже неоднократно говорилось создать с нуля коптер это очень сложно и долго. И те, кто думают что могут сэкономить на этом тоже очень жестоко ошибаются, потому что много аварий (ну да, у меня этого не будет, я же не такой, я всё сделаю по уму, ага), даже на готовых контроллерах то очень много аварий, что уж говорить про самопал. Пропеллеры, движки под замену полетят потоком, раму устанете пересобирать. Если поймёте что вам не хватает ардиуно, то собственный контроллер, заказные платы, розничная стоимость деталей запросто перевалит в несколько раз стоимость бюджетных контроллеров. Создание полностью собственного коптера это не месяц и даже не полгода, это пара лет как минимум. За это время появятся новые контроллеры, новые версии старых, прошивки обрастут новыми функциями, а вы так и будете пилить несчастную стабилизацию.
Вообще какие этапы я вижу, если делать по уму:
1)берете готовую конфигурацию, конкретные моторы, регули, пропеллеры, уже испытанные пилотами. Контроллер с опенсорс прошивкой.
2)собираете коптер и пытаетесь заставить его нормально летать. В этом, казалось бы лёгком, этапе кроется много сложностей и подводных камней. Если всё прекрасно, коптер отрабатывает все режимы, всё как надо, то
3)изменяте текущую прошивку добавлением собственных функций, и наконец
4)создаёте собственный контроллер, пишете свою прошивку или портируете какую-то из оперсорса.
На каждом этапе познаётся очень много дзена и приходит очень много понимания. Денег уйдёт в любом случае немало. И в процессе вы сможете понять хотите ли вы остановиться на каком-то из этих этапов или пройти весь путь джедая до конца.
ЗЫ: на хабре где-то была статья о том как парни создавали свою версию стабилизации на ардуино. И спустя два года оно конечно летает, но, честно говоря, так себе. Можете почитать.

Lisenok
cylllka:

А где объяснение то?

Вот тут: rcopen.com/forum/f20/topic360862/27

Интересует не сам коптер, а работа. Не буду объяснять. Велосипедист. Пока сам не пойму нет смысла меня уговаривать.

Я программированием занимаюсь уже 5 лет, из них 2 особенно адекватно.

С 12 лет!?

promistrio

С 12 лет!?

К сожалению у меня было сложное детство.

Контроллер с опенсорс прошивкой.

Огласите весь список, пожалуйста:)

По всем осям. Стабилизацией в основном занимается гироскоп, а акселерометр лишь помогает исправлять ошибки.

Ясненько. Завтра со свежей головой перечитаю тему.

SergDoc
promistrio:

Добившись разными дополнительными манипуляциями висения, мы заметим, что коптер поступательно вращается в горизонтальной плоскости вокруг оси Z. Для решения этой проблемы нужен гироскоп. Но у меня возник другая мысль. А что если его заменить компасом? На вход контроллера будут поступать значения угла относительно севера, например ЮГ - это 180 градусов. И вот по таким данным устанавливать “курс” коптера. Что я потеряю, заменив гироскоп компасом?

kostya-tin:

ИМХО без гироскопа никуда. и тем более - нужно 3 оси. акселерометр во время движения не покажет правельную угловую скорость, особенно при, так сказать, разгоне и торможении. проще уже без акселерометра обойтись

Смех смехом, а кто-то делал такой проект, к сожалению источник уже не найду, а вот кодятник остался, правда не знаю летало там что или нет:

#include <Wire.h> //Library for I2C implementation using analog pins 4 (SDA) and 5
#include <MegaServo.h>
#define NBR_SERVOS 4 // the maximum number of servos (up to 12 on Arduino Diecimil
#define FIRST_SERVO_PIN 6 // define motor pins on the Arduino board
#define SECOND_SERVO_PIN 9
#define THIRD_SERVO_PIN 10
#define FOURTH_SERVO_PIN 11
MegaServo Servos[NBR_SERVOS] ; // max servos
//Accelerometer variables
float ax,ay,az; //Acceleration values in m/s^2 for all three axis
const float as=0.00488; //Arduino analog resolution = 5Volts/1024 (10bits)
const float zg=1.63; //Sensor zero g bias = Supply Voltage/2 =3.3/2 (V)
const float sR=0.3; //Sensor resolution (V/g)
//Compass variables
int compassAddress = 0x42 >*> 1; // compass I2C slave adress: 0x42
// because the wire.h library only uses the 7 bits most significant bits
// a shift necessary is to get the most significant bits.
int psi = 0; // Compass heading = yaw (direct readings from the compass in degrees)
float psirad; // Compass heading = yaw in radians
//Euler angles Roll and pitch
float phi; // (rad)
float theta; // (rad)
//Kalman filter data
const float A[6][6] = {
{1.0000,0.0000,0.0000,-0.5985,-0.0000,0.0000},
{0.0000,1.0000,-0.0000,-0.0000,-0.5985,0.0000},
{-0.0000,-0.0000,1.0000,-0.0000,-0.0000,-0.0479},
{0.0500,0.0000,0.0000,0.3384,-0.0000,-0.0000},
{0.0000,0.0500,-0.0000,-0.0000,0.3384,0.0000},
{-0.0000,0.0000,0.0500,0.0000,0.0000,0.9147}
};//(Kalman state-space matrix Ak)
const float B[6][10] = {
{-0.0000,-0.0188,-0.0000,0.0188,0.0000,0.0302,-0.0000,0.0031,-0.0000,-0.0000},
{0.0194,0.0006,-0.0194,-0.0006,-0.0302,-0.0000,-0.0000,-0.0000,0.0031,-0.0000},
{0.0009,-0.0009,0.0009,-0.0009,-0.0000,0.0000,0.0000,0.0000,0.0000,0.0479},
{-0.0000,0.0002,-0.0000,-0.0002,0.0000,0.0334,-0.0000,0.0034,-0.0000,0.0000},
{0.0005,0.0006,-0.0005,-0.0006,-0.0334,-0.0000,-0.0000,-0.0000,0.0034,-0.0000},
{0.0000,-0.0000,0.0000,-0.0000,0.0000,0.0000,0.0000,0.0000,-0.0000,0.0853}
}; //(Kalman state-space matrix Bk)
float x[6] = {0,0,0,0,0,0}; //state vector: Roll speed, Pitch Speed, Yaw speed, Roll angle, Pitch angle, Yaw angle
float u[10] = {0,0,0,0,0,0,0,0,0,0}; //input vector: w1 (motor 1 speed),w2,w3,w4,ax,ay,az,phi,theta,yaw
float At[6] = {0,0,0,0,0,0}; //temp variable
float Bt[6] = {0,0,0,-0.01,-0.04,0}; //temp variable
//LQR gain matrix
const float K[4][6] = {
{0.0000,7.1030,20.4163,0.0000,18.2839,14.4659},
{-7.1030,0.0000,-20.4163,-18.2839,0.0000,-14.4659},
{0.0000,-7.1030,20.4163,0.0000,-18.2839,14.4659},
{7.1030,0.0000,-20.4163,18.2839,0.0000,-14.4659}
};
float w1,w2,w3,w4; //Motor inputs from LQR controller (rad.s^-1)
float w0; //Throttle to the motors (from joystick)
//Motor inputs for PWM signal
float wc1=0;
float wc2=0;
float wc3=0;
float wc4=0;
//PWM signals
int p1 = 200;
int p2 = 200;
int p3 = 200;
int p4 = 200;
//Reference
float yr[6]={0,0,0,0,0,0};
void setup()
{
Wire.begin();
Serial.begin(9600); // Initialize serial communications with setup
Servos[0].attach( FIRST_SERVO_PIN, 800, 2200); //Motor 1 - North - Clockwise rotation
Servos[1].attach( SECOND_SERVO_PIN, 800, 2200); //Motor 2 - East - Counterclockwise rotation
Servos[2].attach( THIRD_SERVO_PIN, 800, 2200); //Motor 3 - South - Clockwise rotation
Servos[3].attach( FOURTH_SERVO_PIN, 800, 2200); // Motor 4 - West - Counterclockwise rotation
//Put the motors in full stop
Servos[0].write(0);
Servos[1].write(0);
Servos[2].write(0);
Servos[3].write(0);
}
void loop()
{
// get the most recent acceleration values for all three axis
ax = ((analogRead(0)*as-zg)/sR)*9.81; //acceleration x-axis (m.s^-2)
ay = ((analogRead(1)*as-zg)/sR)*9.81; //acceleration y-axis (m.s^-2)
az = ((analogRead(2)*as-zg)/sR)*9.81; //acceleration z-axis (m.s^-2)
ax=-ax; //This correction allows the accelerometer to provide positive acceleration in the x-axis direction
// Compass task 1: connect to the HMC6352 sensor
Wire.beginTransmission(compassAddress);
Wire.send(’A’); // The ascii character "A" tells the compass sensor to send data
Wire.endTransmission();
// Compass task 2: wait for data processing
delay(50); // Compass datasheet says we need to wait at least 6000 microsegundos (0.006s) for data processing in the sensor
//We can also take this opotunity to implement the sampling time (20Hz)
// Compass task 3: Request heading
Wire.requestFrom(compassAddress, 2); // request 2 bytes of data
// Compass task 4: Get heading data
if(2 <= Wire.available()) // if 2 bytes are available
{
//16bit numbers can be broken in two 8 bit chunks. The first is called high byte and the second low byte
psi = Wire.receive(); // get high byte
psi = psi <*< 8; // shift high byte
psi += Wire.receive(); // get low byte
psi /= 10; // comment this line if you wish to get the heading in decidegrees instead of degrees
}
psirad = deg2rad((float)psi); // Map the compass reading from 0 to 359 degrees to -pi radians to pi radians
phi=atan(ay/az); //Calculate roll angle from the accelerations provided by the accelerometer (rad)
theta=-atan(ax/az); //Calculate pitch angle from the accelerations provided by the accelerometer (rad)
//Perform Kalman filtering
At[0]=A[0][0]*x[0]+A[0][1]*x[1]+A[0][2]*x[2]+A[0][3]*x[3]+A[0][4]*x[4]+A[0][5]*x[5];
At[1]=A[1][0]*x[0]+A[1][1]*x[1]+A[1][2]*x[2]+A[1][3]*x[3]+A[1][4]*x[4]+A[1][5]*x[5];
At[2]=A[2][0]*x[0]+A[2][1]*x[1]+A[2][2]*x[2]+A[2][3]*x[3]+A[2][4]*x[4]+A[2][5]*x[5];
At[3]=A[3][0]*x[0]+A[3][1]*x[1]+A[3][2]*x[2]+A[3][3]*x[3]+A[3][4]*x[4]+A[3][5]*x[5];
At[4]=A[4][0]*x[0]+A[4][1]*x[1]+A[4][2]*x[2]+A[4][3]*x[3]+A[4][4]*x[4]+A[4][5]*x[5];
At[5]=A[5][0]*x[0]+A[5][1]*x[1]+A[5][2]*x[2]+A[5][3]*x[3]+A[5][4]*x[4]+A[5][5]*x[5];
//Get throttle from the joystick
if (Serial.available() > 0)
{
// read the incoming byte:
w0 = map((float)Serial.read(), 0, 100, 0, 500);
w0=constrain(w0,0,500); //Limit maximum velocity to 600 rad/s
Serial.flush();
}
else
{
w0 = 0;
}
//place known inputs and measurements in the input vector u
u[0]=wc1-w0;
u[1]=wc2-w0;
u[2]=wc3-w0;
u[3]=wc4-w0;
u[4]=ax-yr[0];
u[5]=ay-yr[1];
u[6]=az-yr[2];
u[7]=phi-yr[3];
u[8]=theta-yr[4];
u[9]=psirad-yr[5];
Bt[0]=B[0][0]*u[0]+B[0][1]*u[1]+B[0][2]*u[2]+B[0][3]*u[3]+B[0][4]*u[4];
Bt[0]=Bt[0]+B[0][5]*u[5]+B[0][6]*u[6]+B[0][7]*u[7]+B[0][8]*u[8]+B[0][9]*u[9];
Bt[1]=B[1][0]*u[0]+B[1][1]*u[1]+B[1][2]*u[2]+B[1][3]*u[3]+B[1][4]*u[4]
Bt[1]=Bt[1]+B[1][5]*u[5]+B[1][6]*u[6]+B[1][7]*u[7]+B[1][8]*u[8]+B[1][9]*u[9];
Bt[2]=B[2][0]*u[0]+B[2][1]*u[1]+B[2][2]*u[2]+B[2][3]*u[3]+B[2][4]*u[4]
Bt[2]=Bt[2]+B[2][5]*u[5]+B[2][6]*u[6]+B[2][7]*u[7]+B[2][8]*u[8]+B[2][9]*u[9];
Bt[3]=B[3][0]*u[0]+B[3][1]*u[1]+B[3][2]*u[2]+B[3][3]*u[3]+B[3][4]*u[4]
Bt[3]=Bt[3]+B[3][5]*u[5]+B[3][6]*u[6]+B[3][7]*u[7]+B[3][8]*u[8]+B[3][9]*u[9];
Bt[4]=B[4][0]*u[0]+B[4][1]*u[1]+B[4][2]*u[2]+B[4][3]*u[3]+B[4][4]*u[4]
Bt[4]=Bt[4]+B[4][5]*u[5]+B[4][6]*u[6]+B[4][7]*u[7]+B[4][8]*u[8]+B[4][9]*u[9];
Bt[5]=B[5][0]*u[0]+B[5][1]*u[1]+B[5][2]*u[2]+B[5][3]*u[3]+B[5][4]*u[4]
Bt[5]=Bt[5]+B[5][5]*u[5]+B[5][6]*u[6]+B[5][7]*u[7]+B[5][8]*u[8]+B[5][9]*u[9];
//Get estimated states x(k+1)=A.x(k)+B.u(k)
x[0]=At[0]+Bt[0];
x[1]=At[1]+Bt[1];
x[2]=At[2]+Bt[2];
x[3]=At[3]+Bt[3];
x[4]=At[4]+Bt[4];
x[5]=At[5]+Bt[5];
//Controlo LQR
w1=K[0][0]*x[0]+K[0][1]*x[1]+K[0][2]*x[2]+K[0][3]*x[3]+K[0][4]*x[4]+K[0][5]*x[5];
w2=K[1][0]*x[0]+K[1][1]*x[1]+K[1][2]*x[2]+K[1][3]*x[3]+K[1][4]*x[4]+K[1][5]*x[5];
w3=K[2][0]*x[0]+K[2][1]*x[1]+K[2][2]*x[2]+K[2][3]*x[3]+K[2][4]*x[4]+K[2][5]*x[5];
w4=K[3][0]*x[0]+K[3][1]*x[1]+K[3][2]*x[2]+K[3][3]*x[3]+K[3][4]*x[4]+K[3][5]*x[5];
//Adjust speeds with the throttle
wc1=w0-w1;
wc2=w0-w2;
wc3=w0-w3;
wc4=w0-w4;
//Calculate and send pulse width to the motors
p1=(int)((wc1/2.0276)+1252); // (speed of motor 1 (rad/s) / transfer function gain) + Dead-zone pulse width
p2=(int)((wc2/1.8693)+1262);
p3=(int)((wc3/2.0018)+1255);
p4=(int)((wc4/1.9986)+1255);
if(w0==0) //Forçar paragem
{
p1=400;
p2=400;
p3=400;
p4=400;
}
Servos[0].write(p1);
Servos[1].write(p2);
Servos[2].write(p3);
Servos[3].write(p4);
// output states
Serial.print(x[0]);
Serial.print(" ");
Serial.print(x[1]);
Serial.print(" ");
Serial.print(x[2]);
Serial.print(" ");
Serial.print(x[3]);
Serial.print(" ");
Serial.print(x[4]);
Serial.print(" ");
Serial.print(x[5]);
Serial.println("");
}
float deg2rad (float x) //function that receives an angle between 0 and 359 degrees and resturns the same angle between -pi
and pi radians
{
if(x>=0 && x<=180)
{
x=-x*3.14/180;
}
else
{
x = (360-x)*3.14/180;
}
return x;
}
Covax
promistrio:

Огласите весь список, пожалуйста:)

Удивительно не слышать за 5 лет программирования про гугль или яндекс)
Multiwii, ardupilot, например. Я ссылку давал на ФАК неделю назад.

promistrio

Multiwii, ardupilot, например. Я ссылку давал на ФАК неделю назад.

Приходится переваривать слишком много информации.

Удивительно не слышать за 5 лет программирования про гугль или яндекс)

“Много шума”. Не все исходники открыты, приходится перепроверять по каждой системе.

Covax

Какие наши годы, самый френдли это мультивий, причем ранние версии 1.х

SovGVD

А я думал весна мозгоделов закончилась…

  1. не разобрались что и как измеряют MEMS датчики, привет банальные вопросы, которые обсасывали на форуме раза 4 точно в таких темах
  2. делать с нуля самая большая ошибка, если нет команды крутых физиков/математиков/программистов, в 70% закончится тем что не полетит, еще 29% что кого-ниубдь поколечит (если естественный отбор сработает, то на этом всё закончится)
  3. зачем снова делать то что уже и так летает? на да фиг с ним, пусть даже коптер будет стабильно висеть (что умеет даже самый древний multiwii, влезающий на старенькую ардуинку), а дальше что? какие планы для развития?
  4. один сонар - идея на уровне коптера без (MEMS) гироскопа, смотреть надо в сторону точных барометров, а сонаром (как акселерометром) только корректировать ошибки (в данном случае землю)
  5. компас для Z, на сколько я помню медленная штука (т.е. аналогично для корретировки гиры), да и любой проводок рядом и коптер будет совсем не предсказуемо крутиться

если всё это для себя и just4fun, то ИМХО не стоит плодить темы, благо тут есть уже готовые и для новичков, и для тех кто пишет свои прошивки и делает свои контроллеры

зы: что то Сергей добрый последнее время, ни банов, ни блокировок ярых не видно, в соседней ветке человек всё свой сайт с полетами на коптере пиарит и ничего…

promistrio

А я думал весна мозгоделов закончилась…

  1. не разобрались что и как измеряют MEMS датчики, привет банальные вопросы, которые обсасывали на форуме раза 4 точно в таких темах
  2. делать с нуля самая большая ошибка, если нет команды крутых физиков/математиков/программистов, в 70% закончится тем что не полетит, еще 29% что кого-ниубдь поколечит (если естественный отбор сработает, то на этом всё закончится)
  3. зачем снова делать то что уже и так летает? на да фиг с ним, пусть даже коптер будет стабильно висеть (что умеет даже самый древний multiwii, влезающий на старенькую ардуинку), а дальше что? какие планы для развития?
  4. один сонар - идея на уровне коптера без (MEMS) гироскопа, смотреть надо в сторону точных барометров, а сонаром (как акселерометром) только корректировать ошибки (в данном случае землю)
  5. компас для Z, на сколько я помню медленная штука (т.е. аналогично для корретировки гиры), да и любой проводок рядом и коптер будет совсем не предсказуемо крутиться

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

Итак, собрав мозги в кулак я понял, что это все-таки сложное занятие. Вернусь-ка пока к ручному управлению. У знакомого есть игровой штурвал. Предлагаю вот что. Написав драйвер под Linux, я привяжу эту штуку к своей программе, которая с компа будет передавать информацию на коптер. Если не получится нормально использовать штурвал, выведу отдельно потенциометр для регулирования тяги. Тестировать буду как МФТИ-шники по ссылке выше. Благо под двором недопарк с обалденной травой(не для курения:)).

P.S. может вообще все в драйвер засуну. Хоть не Unix-way, зато логично.
[offtop]

программистов

Это те которым я за бабки курсовые пишу? Нафиг они нужны. Покупают дипломы, и парят людям мозги антивирусами. Нынче сложно нормальных программистов найти.[/offtop]