MultiWii

mahowik
Gene:

с какой примерно частотой производится сэмплирование в стандартном софте мультивия?

примерно через 2-5мс, в зависимости от навески… т.е. 200-500гц…

Gene
mahowik:

примерно через 2-5мс, в зависимости от навески… т.е. 200-500гц…

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

mahowik

в Sensors.ino есть все что надо и I2C драйвер и драйвер mpu6050… все в одном и без либ 😉

Gene
mahowik:

в Sensors.ino есть все что надо и I2C драйвер и драйвер mpu6050… все в одном и без либ 😉

Возможно я тупой, но не смог разобраться в коде 😦 Один кусок кода тянет за собой другой, и так до бесконечности… до конца цепочки я добраться не смог. все что мне нужно – считать значение регистра…

mataor
Gene:

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

возьмите хмегу - там аппаратная поддержка 2 шаговых/трехфазных моторов, да и цикл более шустрый получается

Gene:

но не смог разобраться в коде Один кусок кода тянет за собой другой, и так до бесконечности…

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

Gene
mataor:

возьмите хмегу - там аппаратная поддержка 2 шаговых/трехфазных моторов, да и цикл более шустрый получается

Возможно в след. версии 😃

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

Я как Остап Бендер, только он играл в шахматы, а я программирую второй раз в жизни 😃 Не для моего нетренированного мозга разбираться в этом. Код я воспринимаю и имею шанс понять, только когда вижу его целиком перед глазами. Когда он начинает разбегаться по всяческим инклюдам и дефайнам, пиши пропало, нить потеряна – могу только собезьянничать, не понимая что происходит на самом деле.

mataor

хм… ну вообще если нужно чисто и2с и получить 6 данных с датчиков то тебе нужно:

  1. определится с переменными, со знаками и направлениями
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;}
  1. взять основные ф-ции и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;
}
  1. получить данные по акселю и гире
// ************************************************************************************************************
// 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 ф-ции переделать под себя будет чуть геморойнее - они используют больше переменных из других файлов проэкта

Gene

Наверное я изначально неправильно сформулировал задачу. Мне не столько нужно повысить именно СКОРОСТЬ сэмплирования, сколько иметь возможность вставить куски кода по управлению степпером в самые “долгоиграющие” циклы. Проблема состояла в том чтобы найти эти самые циклы (особенно там, где считываются данные с 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. Собственно, если заработает, мне этого будет достаточно…

mataor

слушай… а зачем тебе в код втыкать? почему таймеры не хочеш задействовать с нужной частотой, по таймеру прерывание с циклом управления ШД, а потом меняй частоту таймера/отрубай в тех местах где тебе нужно? для примера управление моторками именно так и осуществлено - на таймере генерим ШИМ а когда нужно меняем значение

П.С. немного не в тему но - kit-e.ru/articles/micro/2008_5_80.php тут есть про AWeX технологию у хмег

Gene

слушай… а зачем тебе в код втыкать?

Просто любопытно. Да и тренировка головы. Тоже своего рода моделирование. А то все вокруг меня все давно программисты, а я как будто только с дерева слез 😃

почему таймеры не хочеш задействовать с нужной частотой, по таймеру прерывание с циклом управления ШД, а потом меняй частоту таймера/отрубай в тех местах где тебе нужно?

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

mataor
Gene:

Вообще на прерывания хотел подвесить читку PWM, но наверное можно и то и другое

вообщет прерывания бывают разных несвязанных типов - от входа, от таймера, от уарта, от TWI (i2c) и проч… в данном случае ты путаеш прерывания со входа с прерыванием по переполнению таймера.
Главное не забывать, что код в прерывании должен быть минимальным и выполнятся макс быстро, чтобы не тормозить прочие прерывания (например в ардуино подсчет времени осуществляется тоже с помощью 0-го таймера и состоит из инкременирования переменной)

Gene

вообщет прерывания бывают разных несвязанных типов - от входа, от таймера, от уарта, от TWI (i2c) и проч… в данном случае ты путаеш прерывания со входа с прерыванием по переполнению таймера.

Я их не путаю, я просто с ними незнаком. Вообще все это железо для меня новость. Что ты хочешь, я только неделю назад первую ардуину купил 😃

Главное не забывать, что код в прерывании должен быть минимальным и выполнятся макс быстро

Это я к счастью помню! (еще с тех древних времен, когда писал на ассемблере под Z80) Если удастся задать прерывание с промежутком в миллисекунду или меньше, то не придется трогать шаг степпера, и весь код будет в три строки с целыми числами.

techalex

Всем добрый вечер.
Подскажите пожалуйста, зеленая платка с ХК www.hobbyking.com/hobbyking/…/uh_viewItem.asp?idPr…
должна хоть как то работать без подключения приемника и регуляторов?
А то что-то она ничего в GUI не посылает…

Gene
techalex:

Всем добрый вечер.
Подскажите пожалуйста, зеленая платка с ХК www.hobbyking.com/hobbyking/…/uh_viewItem.asp?idPr…
должна хоть как то работать без подключения приемника и регуляторов?
А то что-то она ничего в GUI не посылает…

Дык, да, у меня завелась сразу, как только в USB воткнул. Лампочки-то горят?

techalex

при втыкании в usb горит красная и мигают синяя и зеленая на самой wii и зеленая на ftdi - секунд 10 а потом все гаснет. При нажатии start в gui начинает мигать красная на ftdi. и все…
яву обновил, 115200 на порту выставил.

mataor
Gene:

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

тфу блин писал-писал… талмут написал а ток птом увидел что ты про 1 милисекунду а не микросекунду говориш… вообще не проблема - выставляеш делитель 1/8/64/256/1024 от тактовой (16МГц), разрешаеш прерывание по переполнению таймера, выставляеш значение от которого таймер считать будет (обновлять значение по прерыванию) до макс значения (256 для 0 и 2 таймеров и 65535 для таймера 1) и вуаля…

Gene
techalex:

при втыкании в usb горит красная и мигают синяя и зеленая на самой wii и зеленая на ftdi - секунд 10 а потом все гаснет. При нажатии start в gui начинает мигать красная на ftdi. и все…
яву обновил, 115200 на порту выставил.

Может, драйвер COM-порта взглючил?.. Я вообще не спец, но у меня завелась буквально сразу, ничего кроме хвоста USB не втыкал.

mataor:

и вуаля…

Я уже попробовал, вроде работает. Спасибо за наводку!

techalex
Gene:

Может, драйвер 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), не знаю относится это к моей платке или это только к арду…

У вас вообще какие светодиоды горят после включения, чем мигает?

devv
techalex:

Одинаковый результат, т.е. никакого. Не пойму куда копать вообще.

Прошивку залили в платку через Ардуино ИДЕ ?
Может платка пустая пришла ?

techalex
devv:

Прошивку залили в платку через Ардуино ИДЕ ?
Может платка пустая пришла ?

Пока ничего не заливал, хотел так попробовать. Походу раз чем то мигает при включении значит не пустая, просто может версия не та, написано 2.1, но что на самом деле…

Gene
techalex:

У вас вообще какие светодиоды горят после включения, чем мигает?

Я не помню, ибо после проверки с GUI (аксели, гиры и компас работали, судя по графикам, барометр не работал) сразу вытер ему память и начал долбить свою программу. Загрузить обратно сейчас 2.1 попытался, но ничего не вышло, вылетело с ошибкой – вероятно, я еще и в библиотеках намудрил. Так что сорри 😦