MultiWii
с какой примерно частотой производится сэмплирование в стандартном софте мультивия?
примерно через 2-5мс, в зависимости от навески… т.е. 200-500гц…
примерно через 2-5мс, в зависимости от навески… т.е. 200-500гц…
Получается столько же, значит, смысла копать нет. Попробую в таком случае обойти библиотеку и читать нужные данные непосредственно из регистров…
в Sensors.ino есть все что надо и I2C драйвер и драйвер mpu6050… все в одном и без либ 😉
в Sensors.ino есть все что надо и I2C драйвер и драйвер mpu6050… все в одном и без либ 😉
Возможно я тупой, но не смог разобраться в коде 😦 Один кусок кода тянет за собой другой, и так до бесконечности… до конца цепочки я добраться не смог. все что мне нужно – считать значение регистра…
Скорость сэмплирования желательно сделать больше именно из-за количества степов, это сильно упростит код и упростит настройку драйвера степпера
возьмите хмегу - там аппаратная поддержка 2 шаговых/трехфазных моторов, да и цикл более шустрый получается
но не смог разобраться в коде Один кусок кода тянет за собой другой, и так до бесконечности…
там весь код в шапке сенсор.ино, все остальное чего оно хочет - в основном переменные определенные в мультивий.ино и дефайны из деф.н и сонфиг.н
возьмите хмегу - там аппаратная поддержка 2 шаговых/трехфазных моторов, да и цикл более шустрый получается
Возможно в след. версии 😃
там весь код в шапке сенсор.ино, все остальное чего оно хочет - в основном переменные определенные в мультивий.ино и дефайны из деф.н и сонфиг.н
Я как Остап Бендер, только он играл в шахматы, а я программирую второй раз в жизни 😃 Не для моего нетренированного мозга разбираться в этом. Код я воспринимаю и имею шанс понять, только когда вижу его целиком перед глазами. Когда он начинает разбегаться по всяческим инклюдам и дефайнам, пиши пропало, нить потеряна – могу только собезьянничать, не понимая что происходит на самом деле.
хм… ну вообще если нужно чисто и2с и получить 6 данных с датчиков то тебе нужно:
- определится с переменными, со знаками и направлениями
uint8_t rawADC[6];
static int16_t gyroADC[3],accADC[3];
#define MPU6050_ADDRESS 0x68
#define MPU6050
#define ACC_ORIENTATION(Y, X, Z) {accADC[ROLL] = -Y; accADC[PITCH] = -X; accADC[YAW] = Z;}
#define GYRO_ORIENTATION(Y, X, Z) {gyroADC[ROLL] = X; gyroADC[PITCH] = -Y; gyroADC[YAW] = -Z;}
- взять основные ф-ции и2с
// ************************************************************************************************************
// I2C general functions
// ************************************************************************************************************
void i2c_init(void) {
#if defined(INTERNAL_I2C_PULLUPS)
I2C_PULLUPS_ENABLE
#else
I2C_PULLUPS_DISABLE
#endif
TWSR = 0; // no prescaler => prescaler = 1
TWBR = ((F_CPU / I2C_SPEED) - 16) / 2; // change the I2C clock rate
TWCR = 1<<TWEN; // enable twi module, no interrupt
}
void i2c_rep_start(uint8_t address) {
TWCR = (1<<TWINT) | (1<<TWSTA) | (1<<TWEN) ; // send REPEAT START condition
waitTransmissionI2C(); // wait until transmission completed
TWDR = address; // send device address
TWCR = (1<<TWINT) | (1<<TWEN);
waitTransmissionI2C(); // wail until transmission completed
}
void i2c_stop(void) {
TWCR = (1 << TWINT) | (1 << TWEN) | (1 << TWSTO);
// while(TWCR & (1<<TWSTO)); // <- can produce a blocking state with some WMP clones
}
void i2c_write(uint8_t data ) {
TWDR = data; // send data to the previously addressed device
TWCR = (1<<TWINT) | (1<<TWEN);
waitTransmissionI2C();
}
uint8_t i2c_read(uint8_t ack) {
TWCR = (1<<TWINT) | (1<<TWEN) | (ack? (1<<TWEA) : 0);
waitTransmissionI2C();
uint8_t r = TWDR;
if (!ack) i2c_stop();
return r;
}
uint8_t i2c_readAck() {
return i2c_read(1);
}
uint8_t i2c_readNak(void) {
return i2c_read(0);
}
void waitTransmissionI2C() {
uint16_t count = 255;
while (!(TWCR & (1<<TWINT))) {
count--;
if (count==0) { //we are in a blocking state => we don't insist
TWCR = 0; //and we force a reset on TWINT register
neutralizeTime = micros(); //we take a timestamp here to neutralize the value during a short delay
i2c_errors_count++;
break;
}
}
}
size_t i2c_read_to_buf(uint8_t add, void *buf, size_t size) {
i2c_rep_start((add<<1) | 1); // I2C read direction
size_t bytes_read = 0;
uint8_t *b = (uint8_t*)buf;
while (size--) {
/* acknowledge all but the final byte */
*b++ = i2c_read(size > 0);
/* TODO catch I2C errors here and abort */
bytes_read++;
}
return bytes_read;
}
size_t i2c_read_reg_to_buf(uint8_t add, uint8_t reg, void *buf, size_t size) {
i2c_rep_start(add<<1); // I2C write direction
i2c_write(reg); // register selection
return i2c_read_to_buf(add, buf, size);
}
/* transform a series of bytes from big endian to little
endian and vice versa. */
void swap_endianness(void *buf, size_t size) {
/* we swap in-place, so we only have to
* place _one_ element on a temporary tray
*/
uint8_t tray;
uint8_t *from;
uint8_t *to;
/* keep swapping until the pointers have assed each other */
for (from = (uint8_t*)buf, to = &from; from < to; from++, to--) {
tray = *from;
*from = *to;
*to = tray;
}
}
void i2c_getSixRawADC(uint8_t add, uint8_t reg) {
i2c_read_reg_to_buf(add, reg, &rawADC, 6);
}
void i2c_writeReg(uint8_t add, uint8_t reg, uint8_t val) {
i2c_rep_start(add<<1); // I2C write direction
i2c_write(reg); // register selection
i2c_write(val); // value to write in register
i2c_stop();
}
uint8_t i2c_readReg(uint8_t add, uint8_t reg) {
uint8_t val;
i2c_read_reg_to_buf(add, reg, &val, 1);
return val;
}
- получить данные по акселю и гире
// ************************************************************************************************************
// I2C Gyroscope and Accelerometer MPU6050
// ************************************************************************************************************
#if defined(MPU6050)
void Gyro_init() {
TWBR = ((F_CPU / 400000L) - 16) / 2; // change the I2C clock rate to 400kHz
i2c_writeReg(MPU6050_ADDRESS, 0x6B, 0x80); //PWR_MGMT_1 -- DEVICE_RESET 1
delay(5);
i2c_writeReg(MPU6050_ADDRESS, 0x6B, 0x03); //PWR_MGMT_1 -- SLEEP 0; CYCLE 0; TEMP_DIS 0; CLKSEL 3 (PLL with Z Gyro reference)
i2c_writeReg(MPU6050_ADDRESS, 0x1A, MPU6050_DLPF_CFG); //CONFIG -- EXT_SYNC_SET 0 (disable input pin for data sync) ; default DLPF_CFG = 0 => ACC bandwidth = 260Hz GYRO bandwidth = 256Hz)
i2c_writeReg(MPU6050_ADDRESS, 0x1B, 0x18); //GYRO_CONFIG -- FS_SEL = 3: Full scale set to 2000 deg/sec
// enable I2C bypass for AUX I2C
#if defined(MAG)
i2c_writeReg(MPU6050_ADDRESS, 0x37, 0x02); //INT_PIN_CFG -- INT_LEVEL=0 ; INT_OPEN=0 ; LATCH_INT_EN=0 ; INT_RD_CLEAR=0 ; FSYNC_INT_LEVEL=0 ; FSYNC_INT_EN=0 ; I2C_BYPASS_EN=1 ; CLKOUT_EN=0
#endif
}
void Gyro_getADC () {
i2c_getSixRawADC(MPU6050_ADDRESS, 0x43);
GYRO_ORIENTATION( ((rawADC[0]<<8) | rawADC[1])/4 , // range: +/- 8192; +/- 2000 deg/sec
((rawADC[2]<<8) | rawADC[3])/4 ,
((rawADC[4]<<8) | rawADC[5])/4 );
GYRO_Common();
}
void ACC_init () {
i2c_writeReg(MPU6050_ADDRESS, 0x1C, 0x10); //ACCEL_CONFIG -- AFS_SEL=2 (Full Scale = +/-8G) ; ACCELL_HPF=0 //note something is wrong in the spec.
//note: something seems to be wrong in the spec here. With AFS=2 1G = 4096 but according to my measurement: 1G=2048 (and 2048/8 = 256)
//confirmed here:
#if defined(FREEIMUv04)
acc_1G = 255;
#else
acc_1G = 512;
#endif
#if defined(MPU6050_I2C_AUX_MASTER)
//at this stage, the MAG is configured via the original MAG init function in I2C bypass mode
//now we configure MPU as a I2C Master device to handle the MAG via the I2C AUX port (done here for HMC5883)
i2c_writeReg(MPU6050_ADDRESS, 0x6A, 0b00100000); //USER_CTRL -- DMP_EN=0 ; FIFO_EN=0 ; I2C_MST_EN=1 (I2C master mode) ; I2C_IF_DIS=0 ; FIFO_RESET=0 ; I2C_MST_RESET=0 ; SIG_COND_RESET=0
i2c_writeReg(MPU6050_ADDRESS, 0x37, 0x00); //INT_PIN_CFG -- INT_LEVEL=0 ; INT_OPEN=0 ; LATCH_INT_EN=0 ; INT_RD_CLEAR=0 ; FSYNC_INT_LEVEL=0 ; FSYNC_INT_EN=0 ; I2C_BYPASS_EN=0 ; CLKOUT_EN=0
i2c_writeReg(MPU6050_ADDRESS, 0x24, 0x0D); //I2C_MST_CTRL -- MULT_MST_EN=0 ; WAIT_FOR_ES=0 ; SLV_3_FIFO_EN=0 ; I2C_MST_P_NSR=0 ; I2C_MST_CLK=13 (I2C slave speed bus = 400kHz)
i2c_writeReg(MPU6050_ADDRESS, 0x25, 0x80|MAG_ADDRESS);//I2C_SLV0_ADDR -- I2C_SLV4_RW=1 (read operation) ; I2C_SLV4_ADDR=MAG_ADDRESS
i2c_writeReg(MPU6050_ADDRESS, 0x26, MAG_DATA_REGISTER);//I2C_SLV0_REG -- 6 data bytes of MAG are stored in 6 registers. First register address is MAG_DATA_REGISTER
i2c_writeReg(MPU6050_ADDRESS, 0x27, 0x86); //I2C_SLV0_CTRL -- I2C_SLV0_EN=1 ; I2C_SLV0_BYTE_SW=0 ; I2C_SLV0_REG_DIS=0 ; I2C_SLV0_GRP=0 ; I2C_SLV0_LEN=3 (3x2 bytes)
#endif
}
void ACC_getADC () {
i2c_getSixRawADC(MPU6050_ADDRESS, 0x3B);
ACC_ORIENTATION( ((rawADC[0]<<8) | rawADC[1])/8 ,
((rawADC[2]<<8) | rawADC[3])/8 ,
((rawADC[4]<<8) | rawADC[5])/8 );
ACC_Common();
}
GYRO_Common и ACC_Common ф-ции переделать под себя будет чуть геморойнее - они используют больше переменных из других файлов проэкта
Наверное я изначально неправильно сформулировал задачу. Мне не столько нужно повысить именно СКОРОСТЬ сэмплирования, сколько иметь возможность вставить куски кода по управлению степпером в самые “долгоиграющие” циклы. Проблема состояла в том чтобы найти эти самые циклы (особенно там, где считываются данные с MPU6050) и наглядно разместить их в своем скетче. кроме того, желательно было не тратить время на обработку лишних данных, касающихся оси z.
Вот что у меня пока получилось:
.....
//получаем x,y с гир и акселей
getMotion4my(&ax, &ay, &gx, &gy);
.....
void getMotion4my(int16_t* ax, int16_t* ay, int16_t* gx, int16_t* gy) {
int8_t count = 0;
uint16_t timeout = 1000;
uint8_t data[12];
Wire.beginTransmission(0x68);
Wire.write(0x3B);
Wire.endTransmission();
Wire.beginTransmission(0x68);
Wire.requestFrom(0x68, 12);
uint32_t t1 = millis();
for (; Wire.available() && (timeout == 0 || millis() - t1 < timeout); count++) {
data[count] = Wire.read();
//здесь попробую воткнуть управление степперами
}
if (timeout > 0 && millis() - t1 >= timeout && count < 12) count = -1; // timeout
Wire.endTransmission();
*ax = (((int16_t)data[0]) << 8) | data[1];
*ay = (((int16_t)data[2]) << 8) | data[3];
*gx = (((int16_t)data[8]) << 8) | data[9];
*gy = (((int16_t)data[10]) << 8) | data[11];
}
Скорость считки в голом виде примерно 580hz. Собственно, если заработает, мне этого будет достаточно…
слушай… а зачем тебе в код втыкать? почему таймеры не хочеш задействовать с нужной частотой, по таймеру прерывание с циклом управления ШД, а потом меняй частоту таймера/отрубай в тех местах где тебе нужно? для примера управление моторками именно так и осуществлено - на таймере генерим ШИМ а когда нужно меняем значение
П.С. немного не в тему но - kit-e.ru/articles/micro/2008_5_80.php тут есть про AWeX технологию у хмег
слушай… а зачем тебе в код втыкать?
Просто любопытно. Да и тренировка головы. Тоже своего рода моделирование. А то все вокруг меня все давно программисты, а я как будто только с дерева слез 😃
почему таймеры не хочеш задействовать с нужной частотой, по таймеру прерывание с циклом управления ШД, а потом меняй частоту таймера/отрубай в тех местах где тебе нужно?
Не не хочу, а просто пока не сообразил 😃 Так и попробую сделать. Вообще на прерывания хотел подвесить читку PWM, но наверное можно и то и другое
Вообще на прерывания хотел подвесить читку PWM, но наверное можно и то и другое
вообщет прерывания бывают разных несвязанных типов - от входа, от таймера, от уарта, от TWI (i2c) и проч… в данном случае ты путаеш прерывания со входа с прерыванием по переполнению таймера.
Главное не забывать, что код в прерывании должен быть минимальным и выполнятся макс быстро, чтобы не тормозить прочие прерывания (например в ардуино подсчет времени осуществляется тоже с помощью 0-го таймера и состоит из инкременирования переменной)
вообщет прерывания бывают разных несвязанных типов - от входа, от таймера, от уарта, от TWI (i2c) и проч… в данном случае ты путаеш прерывания со входа с прерыванием по переполнению таймера.
Я их не путаю, я просто с ними незнаком. Вообще все это железо для меня новость. Что ты хочешь, я только неделю назад первую ардуину купил 😃
Главное не забывать, что код в прерывании должен быть минимальным и выполнятся макс быстро
Это я к счастью помню! (еще с тех древних времен, когда писал на ассемблере под Z80) Если удастся задать прерывание с промежутком в миллисекунду или меньше, то не придется трогать шаг степпера, и весь код будет в три строки с целыми числами.
Всем добрый вечер.
Подскажите пожалуйста, зеленая платка с ХК www.hobbyking.com/hobbyking/…/uh_viewItem.asp?idPr…
должна хоть как то работать без подключения приемника и регуляторов?
А то что-то она ничего в GUI не посылает…
Всем добрый вечер.
Подскажите пожалуйста, зеленая платка с ХК www.hobbyking.com/hobbyking/…/uh_viewItem.asp?idPr…
должна хоть как то работать без подключения приемника и регуляторов?
А то что-то она ничего в GUI не посылает…
Дык, да, у меня завелась сразу, как только в USB воткнул. Лампочки-то горят?
при втыкании в usb горит красная и мигают синяя и зеленая на самой wii и зеленая на ftdi - секунд 10 а потом все гаснет. При нажатии start в gui начинает мигать красная на ftdi. и все…
яву обновил, 115200 на порту выставил.
Если удастся задать прерывание с промежутком в миллисекунду или меньше, то не придется трогать шаг степпера, и весь код будет в три строки с целыми числами.
тфу блин писал-писал… талмут написал а ток птом увидел что ты про 1 милисекунду а не микросекунду говориш… вообще не проблема - выставляеш делитель 1/8/64/256/1024 от тактовой (16МГц), разрешаеш прерывание по переполнению таймера, выставляеш значение от которого таймер считать будет (обновлять значение по прерыванию) до макс значения (256 для 0 и 2 таймеров и 65535 для таймера 1) и вуаля…
при втыкании в usb горит красная и мигают синяя и зеленая на самой wii и зеленая на ftdi - секунд 10 а потом все гаснет. При нажатии start в gui начинает мигать красная на ftdi. и все…
яву обновил, 115200 на порту выставил.
Может, драйвер COM-порта взглючил?.. Я вообще не спец, но у меня завелась буквально сразу, ничего кроме хвоста USB не втыкал.
и вуаля…
Я уже попробовал, вроде работает. Спасибо за наводку!
Может, драйвер COM-порта взглючил?.. Я вообще не спец, но у меня завелась буквально сразу, ничего кроме хвоста USB не втыкал.
Я уже и на работе и дома попробовал, разные компы и драйвера, на работе винда сама что то поставила, дома с сайта ftdi.
Одинаковый результат, т.е. никакого. Не пойму куда копать вообще.
Нашел вот такое в описании: The blinks at the initialization is very long (more than 5s): it is sometimes the case with a WMP+NK configuration. A way to correct this is to increase the INTERLEAVING DELAY in the sketch. (from 3000 to 3500 or 4000), не знаю относится это к моей платке или это только к арду…
У вас вообще какие светодиоды горят после включения, чем мигает?
Одинаковый результат, т.е. никакого. Не пойму куда копать вообще.
Прошивку залили в платку через Ардуино ИДЕ ?
Может платка пустая пришла ?
Прошивку залили в платку через Ардуино ИДЕ ?
Может платка пустая пришла ?
Пока ничего не заливал, хотел так попробовать. Походу раз чем то мигает при включении значит не пустая, просто может версия не та, написано 2.1, но что на самом деле…
У вас вообще какие светодиоды горят после включения, чем мигает?
Я не помню, ибо после проверки с GUI (аксели, гиры и компас работали, судя по графикам, барометр не работал) сразу вытер ему память и начал долбить свою программу. Загрузить обратно сейчас 2.1 попытался, но ничего не вышло, вылетело с ошибкой – вероятно, я еще и в библиотеках намудрил. Так что сорри 😦