Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Гироскоп - помогите
Форум разработчиков электроники ELECTRONIX.ru > Cистемный уровень проектирования > Математика и Физика
alexPec
Всем добрый день.

Господа математики, не могу понять как в расчете положения (динамического) может участвовать акселерометр (магнитомера у меня не будет).
Есть там (проект freeIMU) функция:

Код
void  imu_AHRSupdate(float gx, float gy, float gz, float ax, float ay, float az, float mx, float my, float mz) { //gx,gy,gz - угловые ускорения, рад/сек
  float recipNorm;                                                                                                                                          //ax,ay,az - линейные ускорения
  float q0q0, q0q1, q0q2, q0q3, q1q1, q1q2, q1q3, q2q2, q2q3, q3q3;
  float halfex = 0.0f;
  float halfey = 0.0f;
  float halfez = 0.0f;
  float qa, qb, qc;

  // Auxiliary variables to avoid repeated arithmetic
  q0q0 = q0 * q0;
  q0q1 = q0 * q1;
  q0q2 = q0 * q2;
  q0q3 = q0 * q3;
  q1q1 = q1 * q1;
  q1q2 = q1 * q2;
  q1q3 = q1 * q3;
  q2q2 = q2 * q2;
  q2q3 = q2 * q3;
  q3q3 = q3 * q3;

  // Use magnetometer measurement only when valid (avoids NaN in magnetometer normalisation)
  if((mx != 0.0f) && (my != 0.0f) && (mz != 0.0f)) {                                                          //Магнитомер не интересует
    float hx, hy, bx, bz;
    float halfwx, halfwy, halfwz;

    // Normalise magnetometer measurement
    recipNorm = imu_invSqrt(mx * mx + my * my + mz * mz);
    mx *= recipNorm;
    my *= recipNorm;
    mz *= recipNorm;

    // Reference direction of Earth's magnetic field
    hx = 2.0f * (mx * (0.5f - q2q2 - q3q3) + my * (q1q2 - q0q3) + mz * (q1q3 + q0q2));
    hy = 2.0f * (mx * (q1q2 + q0q3) + my * (0.5f - q1q1 - q3q3) + mz * (q2q3 - q0q1));
    bx = sqrt(hx * hx + hy * hy);
    bz = 2.0f * (mx * (q1q3 - q0q2) + my * (q2q3 + q0q1) + mz * (0.5f - q1q1 - q2q2));

    // Estimated direction of magnetic field
    halfwx = bx * (0.5f - q2q2 - q3q3) + bz * (q1q3 - q0q2);
    halfwy = bx * (q1q2 - q0q3) + bz * (q0q1 + q2q3);
    halfwz = bx * (q0q2 + q1q3) + bz * (0.5f - q1q1 - q2q2);

    // Error is sum of cross product between estimated direction and measured direction of field vectors
    halfex = (my * halfwz - mz * halfwy);
    halfey = (mz * halfwx - mx * halfwz);
    halfez = (mx * halfwy - my * halfwx);
  }

  // Compute feedback only if accelerometer measurement valid (avoids NaN in accelerometer normalisation)
  if((ax != 0.0f) && (ay != 0.0f) && (az != 0.0f)) {
    float halfvx, halfvy, halfvz;

    // Normalise accelerometer measurement                     Нормируем вектор ускорения
    recipNorm = imu_invSqrt(ax * ax + ay * ay + az * az);
    ax *= recipNorm;
    ay *= recipNorm;
    az *= recipNorm;

    // Estimated direction of gravity  //через направляющие косинусы вычисляем вектор гравитации
    halfvx = q1q3 - q0q2;
    halfvy = q0q1 + q2q3;
    halfvz = q0q0 - 0.5f + q3q3;

    // Error is sum of cross product between estimated direction and measured direction of field vectors
    halfex += (ay * halfvz - az * halfvy);     //Непонятно зачем комбинируем вектор гравитации и измеренные ускорения!!!!
    halfey += (az * halfvx - ax * halfvz);
    halfez += (ax * halfvy - ay * halfvx);
  }

  // Apply feedback only when valid data has been gathered from the accelerometer or magnetometer
  if(halfex != 0.0f && halfey != 0.0f && halfez != 0.0f) {                        
    // Compute and apply integral feedback if enabled
    if(twoKi > 0.0f) {
      integralFBx += twoKi * halfex * (1.0f / sampleFreq);  // integral error scaled by Ki
      integralFBy += twoKi * halfey * (1.0f / sampleFreq);  //Интегрируем по времени и добавляем к угловым ускорениям - зачем!!!!!!
      integralFBz += twoKi * halfez * (1.0f / sampleFreq);  //Самое непонятное это!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
      gx += integralFBx;  // apply integral feedback          
      gy += integralFBy;
      gz += integralFBz;
    }
    else {
      integralFBx = 0.0f; // prevent integral windup
      integralFBy = 0.0f;
      integralFBz = 0.0f;
    }

    // Apply proportional feedback
    gx += twoKp * halfex;
    gy += twoKp * halfey;
    gz += twoKp * halfez;
  }

  // Integrate rate of change of quaternion
  gx *= (0.5f * (1.0f / sampleFreq));   // pre-multiply common factors  //Корректируем матрицу направляющих косинусов
  gy *= (0.5f * (1.0f / sampleFreq));
  gz *= (0.5f * (1.0f / sampleFreq));
  qa = q0;
  qb = q1;
  qc = q2;
  q0 += (-qb * gx - qc * gy - q3 * gz);
  q1 += (qa * gx + qc * gz - q3 * gy);
  q2 += (qa * gy - qb * gz + q3 * gx);
  q3 += (qa * gz + qb * gy - qc * gx);

  // Normalise quaternion
  recipNorm = imu_invSqrt(q0 * q0 + q1 * q1 + q2 * q2 + q3 * q3);
  q0 *= recipNorm;
  q1 *= recipNorm;
  q2 *= recipNorm;
  q3 *= recipNorm;
}


Делалось все это как я понял по этой книге (вложение)

В функции написал комментарии, как я понимаю процесс.
Непонятно что делает (принципиально) часть, где участвуют линейные ускорения и почему через линейные ускорения корректируются угловые?
Не похоже что это учет влияния линейных ускорений на ошибку угловых. Или это оно и есть?
Если так, то как-то топорно вроде, там насколько я знаю все индивидуально и нелинейно, я думал для этого таблицы чувствительности гироскопа к линейным ускорениям экспериментально собирают.
Похоже на какой-то ПИ-регулятор, участвует интеграл по времени и пропорциональная часть, но не понятно принципиально как это работает (на пальцах)
В книге это стр.11, если я правильно понял

Конкретно непонятно это (кусок взят из кода выше):
Код
    halfex += (ay * halfvz - az * halfvy);     //Непонятно зачем комбинируем вектор гравитации и измеренные ускорения!!!!
    halfey += (az * halfvx - ax * halfvz);
    halfez += (ax * halfvy - ay * halfvx);
  }

  // Apply feedback only when valid data has been gathered from the accelerometer or magnetometer
  if(halfex != 0.0f && halfey != 0.0f && halfez != 0.0f) {                        
    // Compute and apply integral feedback if enabled
    if(twoKi > 0.0f) {
      integralFBx += twoKi * halfex * (1.0f / sampleFreq);  // integral error scaled by Ki
      integralFBy += twoKi * halfey * (1.0f / sampleFreq);  //Интегрируем по времени и добавляем к угловым ускорениям - зачем!!!!!!
      integralFBz += twoKi * halfez * (1.0f / sampleFreq);  //Самое непонятное это!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
      gx += integralFBx;  // apply integral feedback          
      gy += integralFBy;
      gz += integralFBz;
    }
    else {
      integralFBx = 0.0f; // prevent integral windup
      integralFBy = 0.0f;
      integralFBz = 0.0f;
    }

    // Apply proportional feedback
    gx += twoKp * halfex;
    gy += twoKp * halfey;
    gz += twoKp * halfez;
  }
deeper_79
не очень понятно что это, похоже на кусок алгоритма выработки углов ориентации (бортовая, килевая качка курс). В этом случае интегралы аклсерометры коореткируют кватарнион который определяет положение свзяанной системы координат с географической.

alexPec
Цитата(deeper_79 @ Sep 11 2013, 12:55) *
не очень понятно что это, похоже на кусок алгоритма выработки углов ориентации (бортовая, килевая качка курс). В этом случае интегралы аклсерометры коореткируют кватарнион который определяет положение свзяанной системы координат с географической.


Это гироскоп, как видно из алгоритма, он (алгоритм) корректирует УГЛОВЫЕ СКОРОСТИ в зависимости от линейных ускорений, а не ПОЛОЖЕНИЕ системы координат. Это чистый гироскоп, без учета всяких там линейных перемещений, только углы ориентации в пространстве. Но вот зачем он их корректирует - непонятно. Про это и спрашиваю.

Через ускорения вычисляется какая-то непонятная мне ошибка, и эта ошибка на следующей итерации вычитается из угловых скоростей.
MrAlex
Гироскоп не измеряет углы положения в пространстве, а только их приращения, угловые скорости.
Ориентацию измеряют акселерометр и магнетометр.
Умножая вектора ориентации получают рассогласование и домножают вектор ориентации на часть этой ошибки, устраняя рассогласование.
alexPec
Цитата(MrAlex @ Sep 11 2013, 17:58) *
Гироскоп не измеряет углы положения в пространстве, а только их приращения, угловые скорости.
Ориентацию измеряют акселерометр и магнетометр.
Умножая вектора ориентации получают рассогласование и домножают вектор ориентации на часть этой ошибки, устраняя рассогласование.


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


Цитата
Гироскоп не измеряет углы положения в пространстве, а только их приращения, угловые скорости.


Это датчик, а я подразумеваю под гироскопом систему датчик - программа. Так вот как раз интегрируя их (данные с датчика) во времени через кватерионы и получают текущие углы ориентации в пространстве. По крайней мере я всегда так думал.

Вот например, софт от free imu arduino:



Неужели никто не задумывался над математикой?
DASM
Дрейф сильный у гироскопа. Мне очень видео понравилось http://www.youtube.com/watch?v=C7JQ7Rpwn2k...be_gdata_player Если не откроется, наберите в ютубе Invensense + Android
deeper_79
Цитата(alexPec @ Sep 11 2013, 18:08) *
Может я чего-то не понимаю, но по таким гироскопам модели самолетов летают и стабилизируют свое положение, далеко как не по акселерометру - модельку болтает во все стороны и вычислить через проекции векторов линейного ускорения вертикаль в полете не реально. По магнитомеру больше стабилизируют курс, используя кстати углы ориентации в пространстве, взятые от гироскопа.




Это датчик, а я подразумеваю под гироскопом систему датчик - программа. Так вот как раз интегрируя их (данные с датчика) во времени через кватерионы и получают текущие углы ориентации в пространстве. По крайней мере я всегда так думал.

Вот например, софт от free imu arduino:



Неужели никто не задумывался над математикой?

есть смысл почитать во это http://www.twirpx.com/file/126419/?rand=2257909
это хотя для моря, но можно продолжить и на авиацию
попробую кратко описать алгоритм работы гировертикали построенной на похожем модуле:
1. По гироскопам решая уравнение Пусаона находим кватернион определяющий ориентацию связанной системы координат(ССК) и инерциальной (неподвижной относительно звезд) системой координат(ИСК).
2. Интегрируем показания акселерометров получаем скорости в связанной системе координат
3. Вводим кватернион который определяет ориентацию ИСК относительно географической системы координат (ГСК), неподвижной относительно Земли (на начальном этапе единичный)
4. Перемножаем к. из п.1 и п.3
5. используя кватернион в п.3 проектируем линейные скорости в ГСК (естественно в начале получаем ошибочные должен быть вектор [0 0 0], линейное перемещение объекта пока опускаю)
6. По полученную разницу в п.5 подаем на фильтры (фильтры это отдельная БОЛЬШАЯ тема) и формируем кватернион коррекции который умножаем кватернион в п.3 (замыкаем обратную связь)

как мне кажется в вашем случае скорости как раз из пункта 2 и 4. Это если очень кратко, а так бесплатформенные гировертикали это отдельная большая тема
может проще вы скажете чего вам надо найти? есть кое какие примеры в матлабе
DASM
Серьезно, спасибо. Но кватернионы используют далеко не всегда.Уверены, что это тот случай? Офф какое же строение мозга надо иметь, чтобы это понимать. Всегда уважал математиков более всех.
alexPec
Цитата(deeper_79 @ Sep 13 2013, 15:03) *
попробую кратко описать алгоритм работы гировертикали построенной на похожем модуле:
1. По гироскопам решая уравнение Пусаона находим кватернион определяющий ориентацию связанной системы координат(ССК) и инерциальной (неподвижной относительно звезд) системой координат(ИСК).
2. Интегрируем показания акселерометров получаем скорости в связанной системе координат
3. Вводим кватернион который определяет ориентацию ИСК относительно географической системы координат (ГСК), неподвижной относительно Земли (на начальном этапе единичный)
4. Перемножаем к. из п.1 и п.3
5. используя кватернион в п.3 проектируем линейные скорости в ГСК (естественно в начале получаем ошибочные должен быть вектор [0 0 0], линейное перемещение объекта пока опускаю)
6. По полученную разницу в п.5 подаем на фильтры (фильтры это отдельная БОЛЬШАЯ тема) и формируем кватернион коррекции который умножаем кватернион в п.3 (замыкаем обратную связь)


Спасибо за ответ, очень похоже. Только в этих алгоритмах вижу пока что ССК - объект и ИСК (подразумеваю ГСК). Читаю статейку которую прикладывал уже раз 15-й, начинаю втягиваться.


Цитата
может проще вы скажете чего вам надо найти? есть кое какие примеры в матлабе


В идеале надо бы на ходу корректировать плывущие вертикаль и курс (в следствие дрейфа нулей гироскопа), т.е. компенсировать дрейфы гироскопа по показаниям акселерометра и магнитомера. Магнитомера на плате не имею, но похоже нужен будет.

Цитата
есть смысл почитать во это http://www.twirpx.com/file/126419/?rand=2257909
это хотя для моря, но можно продолжить и на авиацию


Спасибо, почитаю, а пока накопившиеся вопросы, похоже Вы знаете на них ответы (в голове пока путаница, поэтому отнеситесь терпеливо к глупым вопросам sm.gif ):

1. Приводил уже где-то алгоритм на картинке. Переосмыслил. Но до конца пока не понял, что он нам дает, что мы им добиваемся. Коррекцию вертикали? Постоянную? Если не постоянную, то при каких условиях? Или тут ситуация такая: чем стабильнее показания акселерометра (меньще дерганий объекта), тем точнее корректируем вертикаль? А как себя будет вести эта коррекция, если аксерерометр постоянно будет находится в трехмерном хаотическом движении (на модели самолета)?

2. Правильно ли понимание алгоритма: алгоритм решает задачу оптимизации, оптимизация - минимизация функции (2-я картинка), здесь в функции 1-й член - кватерион ориентации ССК(объект) относительно ИСК(земля) , второй - вектор поля (условно, подразумевается поле гравитации+поле магнитное земли, т.е. поле, трехмерно определяющее направление ИСК, третий - кватерион ориентации ИСК относительно ССК. Произведение всего этого дает нам (используя текущие углы гироскопа) положение ИСК относительно ССК, вычитаем из этого положения измеренное положение ИСК в ССК (акселерометрами и магнитомерами). Эту разность и минимизируем. Минимизируем за счет коррекции текущих углов гироскопа.

3. Минимизируем так: умножаем целевую функцию (картинка2) на матрицу Якоби - находим многомерный градиент, затем нормируем его, и с каким-то коэффициентом бета вычитаем из текущих угловых скоростей - я думал корректируем углы? или так и корректируем плавно за счет коррекции скоростей угловых?

Ну а с нижней частью алгоритма вроде все ясно: кватерион текущей ориентации ССК относительно ИСК домножаем итерационно на угловые скорости, интегрируем по времени численно, получаем новый кватерион ориентации.

Вникаю дальше, зреют новые вопросы...

И да, вся математика там построена на кватерионах.
Timmy
Мне кажется, в этом коде содержится серьёзная алгоритмическая ошибка. Гировертикаль должна корректироваться строго по линейному усреднению показаний акселерометров, а не по нормализованному. Например, если летательный аппарат 1/5 времени будет двигаться с вертикальным ускорением 6g, а остальное время, с боковым ускорением 0.05g(выполняя горку и плавный поворот), то нормализованное ускорение в среднем будет смотреть почти вбок, туда же приведётся и гировертикаль lol.gif .
Далее, рассмотрим чисто технические ошибки программирования:
Код
if((ax != 0.0f) && (ay != 0.0f) && (az != 0.0f)) {
    float halfvx, halfvy, halfvz;

    // Normalise accelerometer measurement                     Нормируем вектор ускорения
    recipNorm = imu_invSqrt(ax * ax + ay * ay + az * az)
Здесь возможна ситуация, когда одна из осей выдаст ноль, в результате не будет обработан весь ненулевой вектор. Неравенство нулю всех трёх координат ещё не гарантирует, строго говоря, ненулевую сумму квадратов, так как при малых исходных значениях квадрат даст underflow в 0, что может вынести функцию imu_invSqrt(). Тут логичнее было бы проверять в if именно сумму квадратов. Ну и все кватернионы, вектора и прочие математические объекты надо бы объединить в структуры, а операции над ними оформить отдельными функциями, а то читать невозможно.
Corner
Обычно при помощи ДУС вычисляют/корректируют мгновенные углы и их приращения. А нулевое положение корректируют по ртутному или солевому датчику положения.
alexPec
Цитата
Мне кажется, в этом коде содержится серьёзная алгоритмическая ошибка. Гировертикаль должна корректироваться строго по линейному усреднению показаний акселерометров, а не по нормализованному. Например, если летательный аппарат 1/5 времени будет двигаться с вертикальным ускорением 6g, а остальное время, с боковым ускорением 0.05g(выполняя горку и плавный поворот), то нормализованное ускорение в среднем будет смотреть почти вбок, туда же приведётся и гировертикаль.


Почему по линейному? Нам направление важно, а не модуль. Что нам может в этом случае модуль дать?
Насчет приведения вертикати вбок - ну выровняет, ну наклонит вбок, далее гравитация будет действовать на ось X акселерометра, а не Z. И все выровняется обратно. Но это уж край самый, коэффициент бета я так понимаю должен быть достаточно малым чтоб вертикаль не реагировала на болтанку модели в воздухе и на изменения курса. А постоянно держать ускорение (серьезное, чтоб значительно повлияло на вертикаль) продолжительное время - это еще постараться надо. Разве что кружить, но кружить постоянно по малому радиусу - незачем, а большой радиус серьезного изменения вертикали не даст. Коэффициент бета я так понимаю и определяет время усреднения вертикали.

Цитата
Далее, рассмотрим чисто технические ошибки программирования:
Код
if((ax != 0.0f) && (ay != 0.0f) && (az != 0.0f)) {
    float halfvx, halfvy, halfvz;

    // Normalise accelerometer measurement                     Нормируем вектор ускорения
    recipNorm = imu_invSqrt(ax * ax + ay * ay + az * az)
Здесь возможна ситуация, когда одна из осей выдаст ноль, в результате не будет обработан весь ненулевой вектор. Неравенство нулю всех трёх координат ещё не гарантирует, строго говоря, ненулевую сумму квадратов, так как при малых исходных значениях квадрат даст underflow в 0, что может вынести функцию imu_invSqrt(). Тут логичнее было бы проверять в if именно сумму квадратов.


Тут на мой взгляд как раз все нормально - проверка на ноль проекции проще чем проверка на ноль суммы квадратов. Ну будет одна проекция равна нулю - ничего страшного, функция эта вызывается через каждые 1-10мс, ну отбросится один цикл коррекции, будет коррекция на 10мс дольше, при времени усреднения более 10 с это не так страшно.
Вот с underfollow согласен.

Цитата
Ну и все кватернионы, вектора и прочие математические объекты надо бы объединить в структуры, а операции над ними оформить отдельными функциями, а то читать невозможно.


Писал то не я, я только пытаюсь разобраться как оно работает.

Цитата
Обычно при помощи ДУС вычисляют/корректируют мгновенные углы и их приращения. А нулевое положение корректируют по ртутному или солевому датчику положения.


Что, и в динамике можно по ртутному датчику положения определить вертикаль? А если только в статике - так на это есть акселерометр трехосевой...


PS Ха, посмотрел чему равны пропорциональный и интегральный коэффициенты по умолчанию - twoKi = 0.2, twoKp = 1. Задумался...
deeper_79
1. Приводил уже где-то алгоритм на картинке. Переосмыслил. Но до конца пока не понял, что он нам дает, что мы им добиваемся. Коррекцию вертикали? Постоянную? Если не постоянную, то при каких условиях? Или тут ситуация такая: чем стабильнее показания акселерометра (меньще дерганий объекта), тем точнее корректируем вертикаль? А как себя будет вести эта коррекция, если аксерерометр постоянно будет находится в трехмерном хаотическом движении (на модели самолета)?

2. Правильно ли понимание алгоритма: алгоритм решает задачу оптимизации, оптимизация - минимизация функции (2-я картинка), здесь в функции 1-й член - кватерион ориентации ССК(объект) относительно ИСК(земля) , второй - вектор поля (условно, подразумевается поле гравитации+поле магнитное земли, т.е. поле, трехмерно определяющее направление ИСК, третий - кватерион ориентации ИСК относительно ССК. Произведение всего этого дает нам (используя текущие углы гироскопа) положение ИСК относительно ССК, вычитаем из этого положения измеренное положение ИСК в ССК (акселерометрами и магнитомерами). Эту разность и минимизируем. Минимизируем за счет коррекции текущих углов гироскопа.

3. Минимизируем так: умножаем целевую функцию (картинка2) на матрицу Якоби - находим многомерный градиент, затем нормируем его, и с каким-то коэффициентом бета вычитаем из текущих угловых скоростей - я думал корректируем углы? или так и корректируем плавно за счет коррекции скоростей угловых?

Ну а с нижней частью алгоритма вроде все ясно: кватерион текущей ориентации ССК относительно ИСК домножаем итерационно на угловые скорости, интегрируем по времени численно, получаем новый кватерион ориентации.

Вникаю дальше, зреют новые вопросы...

И да, вся математика там построена на кватерионах.
[/quote]

1. В алгоритме который я приводил выше я указал что опускаю линейное перемещение объекта. Что бы алгриртм работал на линейном движении необходимо наличие внешней линейной скорости от спутников либо лага для моря, ну вообщем что то меряет скорость. Если ее нет то енто есть скоростная погрешность гировертикали. Если есть из полученных интегралов от акселерометров вычитаеться скорость полученная по внешней информации разложенная на соответсаующие оси.
Коррекция должна быть постояной, постоянная времени коррекции (фильтра) выбираеться исходя из дрейфа гисрокопа, для микромеханики это где то 10-15с, для более точных гироскопов 50с и выше, т.е. все высокочастоное будет вырезано.
2 и 3 вопрос я не готов так сходу подумаю может отвечу

есть еще одна статья моя во вложении
alexPec
Цитата(deeper_79 @ Sep 16 2013, 11:51) *
есть еще одна статья моя во вложении


Очень ценная информация, спасибо. А моделирование проводили без информации от спутниковой навигации?
deeper_79
Цитата(alexPec @ Sep 16 2013, 11:57) *
Очень ценная информация, спасибо. А моделирование проводили без информации от спутниковой навигации?

Вы можете это просто проверить, нарисовав схему вертикали в симулинке которая приведена в статьте и подав сокрость. Вообще раньше на кораблях и самолетах такой коррекции небыло, просто на время маневров (опрделялся по гироскопам и акселерометрам) коррекция отключалась. Тут много вариантов постраения системы, например у вас есть магнитометр который не возмущаеться от ускорений объекта, но имеет свои ошибки нужно комплексировать системы т.е. нахождения соотвествующего фильтра в зависимости от спеткра обшибок, например фильтр Винера или как развитие фильтр Калмана.
В книжке это есть
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.