Talk:Navigation Module - Mathematical Background

From endrobene wiki :: ITE
Jump to: navigation, search

Наконец-то нашел то, что мне нужно =) --Swinemaker 23:00, 14 November 2011 (EET)

Отлично, если будут вопросы по разделу - пиши сюда. Хорошо что ты зарегистрировался. АЦП еще не купил (AD7328). Во вторник 22/11/11 займусь этим делом. -- Executor 06:47, 21 November 2011 (EET)

ОУ или не ОУ?

Хмм... Вот возникли сомнения по поводу необходимости ОУ в этой системке.. Сие замечательное устройство (MMA7260) выдает довольно-таки пристойный сигнал (порядка от 1 до 3V) [1],верх. граница сигнала - 5V собственно и усиливать там нечего.. вот-с.

З.Ы. как там насчет АЦП?

UPD: К тому же, походу, сам акселерометр пошумливает (см. рисунокъ [2] - до половины чувствительность 800 mV/g, далее - 200 mV/g). И еще его надо как-то калибровать. Блин. Swinemaker 20:33, 23 November 2011 (EET)

UPD2: какой целевой битрейт юарта? Swinemaker 21:11, 23 November 2011 (EET)

Привет.
  • ОУ - как хочешь, согласен что не обязательно (тем более ему желательно еще и отрицательное напряжение для улучшения линейности, которого пока нету), плюс еще и на печатной плате его разводить - согласен, что лучше всего первую версию сделать как можно проще.
  • АЦП - заказываю, еще 1 день и будет готово, модель AD7328 (или AD7327), 8 каналов, интерфейс SPI.
  • по поводу шумов - это был неподвижный акселерометр? если да - предлагаю поставить хороший конденсатор танталовый и параллельно обычный, емкость пока не знаю - можно поставить еще небольшую индуктивность - LC фильтр нижних частот (срезать верхние) на частоту среза около 10 КГц. Тут есть програмная фильтрация: http://www.mdpi.com/1424-8220/8/4/2886/pdf. Взято из коментов к статье: http://habrahabr.ru/blogs/DIY/131502/, там же про фильтры Калмана: http://habrahabr.ru/search/?q=%D1%84%D0%B8%D0%BB%D1%8C%D1%82%D1%80%D1%8B+%D0%9A%D0%B0%D0%BB%D0%BC%D0%B0%D0%BD%D0%B0 - не уверен что поможет, но попробовать стоит. Вот тоже небольшая дискусия: http://roboforum.ru/forum86/topic9320.html
  • Смещение нуля акселерометра - можем по началу вообще не сражаться с ним - просто запомни что является нулем и сделай вокруг этого значения 1-3% (можно даже 5%) зону нечувствительности, все что выходит за эту зону - линейно влияет на выходное ускорение. (то есть игнорировать ускорения до 0.01 g, например).
  • Калибровать акселерометр не просто. Можно калибровать поворачивая акселерометр на разные стороны, по очереди каждую ось вертикально подставляя под вектор ускорения свободного падения - он должен ровно засвечиваться в показаниях оси как 1g, но поставить акселерометр на ребро так ровно - не знаю как. Постоянную скорость поддерживать сложно, но можно определить уровень ошибки акселерометра (а это покажет какая из осей говорит неправду), допустим пройтись с акселерометром по комнате, и затем вернуть его назад на то же место (с точностью до миллиметра). Если интегральная величина - путь - равна нулю - то есть перемещения небыло как фактически, так и по показаниям, - то все хорошо. Если присутствовала ошибка, то её будет четко видно и ты будешь знать в какую сторону плыли значения. Нам акселерометр может быть полезен для определения пройденного пути, думаю в первую очередь, во вторую - для определения текущей скорости. В последнюю - чтобы знать текущее ускорение и направление земли.
  • Целевая скорость UART - 57600 (вообще говоря можно такие скорости: 9600, 19200, 38400, 57600, 115200 - все эти скорости поддерживаются в LINUX/POSIX/Windows). Биты данных - от 6 до 8 (возможно проще всего 8), четность - нет/чет/нечет, стоповые биты: 1 или 2 (1.5 не поддерживается в Linux). Управление потоком отсутствует (хотя можно аппаратное или XON/XOFF - не пробовал). Давай, может, условимся пока-что baud rate = 57600, data bits = 8, parity = none, stop bits = 1 - если такие подойдут - напиши. Нам еще нужно не просто передавать данные будет, а сделать так чтобы ошибки передачи небыло:) Во первых нужен точный кварц, а во вторых - помехоустойчивое кодирование - можно ввести контрольную сумму в пакет данных или кодом Хэмминга кодировать - не сложно - могу написать функцию кодирования (на C). Кодирования (предмета) у вас еще не было и тебе может быть с ним сложно, так что я тебе с этим буду помогать, если надумаешь сделать передачу надежной настолько - можно во второй версии такое сделать, а сейчас просто контрольную сумму бит.
  • Формулу для восстановления вектора направления земли (вектор 1g) из трех выходных координат (от результата акселерометра) - я напишу тебе в ближайшее время.
С уважением, Executor 20:15, 24 November 2011 (EET)
UPD Есть еще один способ борьбы с шумами - поставить еще один акселерометр параллельно, такой-же точно, а значения усреднять. Если интересно попробовать - пиши - я его закажу. Время доставки его около 2 недель, так что говори заранее:) С уважением, Executor 20:18, 24 November 2011 (EET)
  • Ага, я такой алгоритм калибровки примерно и реализовываю, причем значения при +-1g записываются при калибровке в ПЗУ, а при перезагрузке оттуда вынимаются. Управлять калибровкой будем, естественно, через UART.
  • Про интерфейс. ИМХО, 57600 кагбе многоватенько, да и с моим "стендом для изучения сигналов на длинных линиях (тм)" в роли удлинителя для ком-порта всяко проглючивает, поэтому стартовый (при инициализации) битрейт будет 38400 (пока, может потом еще меньше сделаем). А уже дальше можно будет с помощью интерфейса настроить скорость, какая душе угодна. Биты - 8 (не издеваемся над бедными программерами=) ), на всю остальную фигню можно забить; обычно кроме того, что ты написал ничего не применяется (по крайней мере, я на практике не видел). Управление потоком - нах, так как у нас вылезет необходимость отфильтровывать некотроые символы, а это не есть гут. На счет кодирования и проч. - а что џрџ не пойдеть? -_-
  • по поводу шумов Да, он был неподвижный, причем с уменьшением чувствительности до 600мВ/g они пропали. Что очень странно, это то, что меговская АЦП с предделителем 128 шумит больше чем с без него 0_о хотя, возможно, это был мой косяк или что-то еще. Но в принципе, это не так критично, все равно двигатели быудуть жжжжужжжать и платформу будеть трясти )) C мух. Swinemaker 22:29, 24 November 2011 (EET)
  • Допољњењїе. Я пока решил оставить всю математику на float'ах, так как зарылся в реализацию синусов, деления и ко. и немного напугался =). Но оно, походу, и так достаточно быстро соображает. Так вот. В каком виде принято float'ы передавать через UART? Swinemaker 22:35, 24 November 2011 (EET)
  • 38400 - норм. CRC как в качестве контрольной суммы (проверки битов посылки) подходит. В качестве излишка может добавим код Хэмминга (помехоустойчивый) паралельно CRC, чтобы восстанавливать искаженные биты (например два искаженных на 8 бит посылку).
  • шумы - Ок))
  • float - Ок. Можешь передавать их в чистом виде. Как принято - не знаю - не пробовал флоты передавать)). Там 32 битный float?
	// разбираем
	float my_float = 999.99f;
	char f0 = ((char*)&my_float)[0];
	char f1 = ((char*)&my_float)[1];
	char f2 = ((char*)&my_float)[2];
	char f3 = ((char*)&my_float)[3];
	send(f0);
	send(f1);
	send(f2);
	send(f3);
 
	// --------- передача по проводам
 
	// собираем
	char r0,r1,r2,r3;
	receive(r0);
	receive(r1);
	receive(r2);
	receive(r3);
 
	float my_value;
	((char*)&my_value)[0] = r0;
	((char*)&my_value)[1] = r1;
	((char*)&my_value)[2] = r2;
	((char*)&my_value)[3] = r3;
С уважением, Executor 04:43, 25 November 2011 (EET)



Ну да, float обычный, 4-х байтный. Я это к чему: есть стандартная функция преобразования их в текст. строку - но думаю, это немного "неприлично" =) ([3]). Просто передача с таким разбором переает данные эээ.. как бы без смыслы что ли (?). Хотя, в принципе, они так в памяти и хранятся, чего уж тут. С пятницой, Swinemaker 16:45, 25 November 2011 (EET)

Да, показания в строку превращать - вычислительно накладно. Лучше всего их поместить в структуру полей
// эту структуру неплохо-бы расширить так чтобы её потом не менять,
// например добавив пару резервных 
typedef struct ACCELEROMETER_DATA
{
  byte request_id; // номер ответа равен номеру запроса или уникальный
  //номер сообщения (можно до 32 байт)
  float ax,ay,az; // ускорения
  float vx,vy,vz; // текущая скорость
  float sx,sy,sz; // текущий путь от времени запуска или момента сброса пути
 
  unsigned char crc8; 
  // CRC8 http://www.rajivchakravorty.com/source-code/uncertainty/multimedia-sim/html/crc8_8c-source.html
} TAG_ACCELEROMETER_DATA;
 
struct ACCELEROMETER_DATA my_data;
 
// заполняем важными данными
my_data.ax = 999.0f;
 
// функция передачи массива данных через UART
// bool send_uart(void *data_ptr, unsigned char number_of_bytes_to_send);
 
send_uart(&my_data, sizeof(ACCELEROMETER_DATA));
  • Нужно обсудить формат запроса-ответа. Например мы можем ввести режимы когда:
1) твой контроллер просто беспрерывно выдает данные в свободном режиме, и ничего не спрашивает у компа, ждет тот данные или нет - но это плохо, т.к. до того как комп включится данные все-равно будут передаваться (комп включается позже твоего контроллера), а после включения, мы потеряем начало передачи и не будем знать где первый бит пакета, а где последний
2) решить проблему можно начав передачу только после подачи сигнала компом, о том, что теперь можно начать передавать данные, и контроллер каждые 0.05-0.1 секунды будет выдавать пакет с текущими показаниями скорости и ускорения
3) нужно, чтобы в этом режиме (free-mode) комп говорил с какой частотой выдавать данные твоему контроллеру, если он хочет их получать периодически.
4) лучше всего ввести еще один режим, при котором комп сначала делает запрос, в виде пакета. В пакете содержится уникальный номер запроса - например от 0 до 65535. Ты копируешь этот номер в ответ, и говоришь - вот на твой запрос номер 999, я даю тебе ответ, и отправляешь все данные структуры. А комп будет их готов получать. Наподобие режима клиент-сервер, где твое устройство выступает в режиме сервера, а комп - в виде клиента, периодически запрашивая обслуживание.
С уважением, Executor 12:39, 26 November 2011 (EET)

Показания гироскопа (!)

Тут еще такой момент: по расчету, везде показания гироскопа в радианах. Однако, он же возвращает нам величину изменения угла (рад/сек). То есть, нужно сначала преобразовать это изменение в величину отклонения от нормального, которое предварительно задать с помощью указания с контроллера о том, что сейчас позиция модуля горизонтальная, а в самой процедуре readGyro(Vec3 *retVecAccel) мы читаем не сами показания акселерометра, а это предварительно обсчитанное отклонение, или как? Swinemaker 18:32, 25 November 2011 (EET)

Все уже ясно. ТруЪ, Swinemaker 23:43, 26 November 2011 (EET)

Да, измерения гироскопа идут в величинах омега - угловая скорость (смотри ниже, readGyro в коде возвращает сами углы, пока-что). Нам да, вообще надо сначала чтобы комп сказал - вот сейчас "НОЛЬ по всем осям", или "запиши текущий угол осей как такой Фи_X = 0.1 радиана, Фи_Y = 0.02 радиана, Фи_Z = 0.3 радиана". Это можно организовать в виде считывания структуры от компа:
typedef struct GYRO_CALIBRATION
{
  float Phi_X; // на момент приема, считать текущий угол отсчета таким (в радианах)
  float Phi_Y;
  float Phi_Z;
};
readGyro - возвращает нам текущие углы. (в исходнике расписано не удобно для тебя - MY FAIL. Я должен поправить, поскольку чистые значения показаний гироскопа - текущие угловые ускорения. Поэтому туда добавятся функции преобразования текущий данных датчиков, в искомые данные (углы)).
readAccelerometer - чистые показания акселерометра в м/с2, без поворота на угол гироскопа.
Правильно: readGyro(Vec3 *retVecGyro) - то есть угол поворота робота. Я сейчас все распишу в исходном коде на странице статьи.
P.S.>И еще одно, я сам не любитель радианов, если честно. Но мы должны их использовать, поскольку это стандарт СИ, и поскольку все функции математики принимают углы именно в радианах.
С уважением, Executor 06:13, 27 November 2011 (EET)
Эх, пафос-пафос) ... Мы должны их использовать потому, что стандартные функции работают с радианами =). Сейчас вот новая проблема появилась - постоянная аддитивная ошибка... ррррръъъ
Вот возвращаем мы из гироскопа угол:
void QuickConvert(void) {
	// radian
	 //USART_Send_byte(TCNT2);
	CurrentAngle_UnitSystem.x += ( ( (float)Advanced_run_ADC(ADC_SRC_C) - (float)RG30_AxisCalibrationC )/128 ) * (1/(float)GYRO_UPDATE_FREQUENCY);
	CurrentAngle_UnitSystem.y += ( ( (float)Advanced_run_ADC(ADC_SRC_B) - (float)RG30_AxisCalibrationB )/128 ) * (1/(float)GYRO_UPDATE_FREQUENCY);
	CurrentAngle_UnitSystem.z += ( ( (float)Advanced_run_ADC(ADC_SRC_A) - (float)RG30_AxisCalibrationA )/128 ) * (1/(float)GYRO_UPDATE_FREQUENCY);
 
	#ifdef SW_ALPHA_VERSION
	 //USART_Send_Pstring(PSTR("\r\nOK"));
	 //USART_Send_byte(TCNT2);
	#endif
}
А калибровку я уже давно написал, как же без нее, но

Аддитивная ошибка

Во-первых мне нужны кварцЫ. То есть, завтра поеду за ними - 16 000 000 и 32 768. (я как-то думал что Мега 16-я может работать от встроенного генератора на 16МГц =)) Во-вторых вылезла ошибка, нужно ее как-то фильтровать будет... (может, таки нужен внешний АЦП) Вот, что получилось: LOGFILE (это угол) Бррр.. я уже умал, что это модуль поз воздействием какой-то силы немного вращается, но по идее не должен - всю ночь ведь он в состоянии спокойствия лежал, или это у меня дом крутится? 0_о

Это за всю ночь? Не уверен что у гироскопа достаточно точности, но, если это вся ночь - то да, это вращение планеты (ну и шум тоже). Нужно отделить "мухи от котлет". Нужно немного подумать еще (мне). Я завтра буду, кварц точный принесу, и все остальное что давно обещал, включая припой. С уважением, Executor 17:38, 27 November 2011 (EET)
Ыыыыыы... Не, это не вся ночь! это 10 минут... =(
Кварџ в каком корпусе? Swinemaker 17:40, 27 November 2011 (EET)
Кварц стандартный двухвыводный, высокий. http://electrcomponent.90mb.ru/pict/1299318393399632.jpg.
10 минут - мало слишком для планеты, согласен:) Сделай 1% корридор нечувствительности пока-что. С уважением, Executor 17:44, 27 November 2011 (EET)
Personal tools
Namespaces
Variants
Actions
Navigation
Toolbox