Моделирование и сочетание компьютерных рисунков с движением. Моделирование движения объектов

Продолжаем серию статей по автоматизации выполнения фигур пилотажа на малом ДПЛА. Настоящая статья имеет, прежде всего, образовательную цель: здесь мы покажем, как можно создать простейшую систему автоматического управления (САУ) на примере задачи выполнения фигуры пилотажа «бочка» при управлении летательным аппаратом только элеронами. Статья является второй в цикле публикаций «Пилотажный ДПЛА», рассказывающем о процессе постройки аппаратной и программной частей САУ в обучающей форме.

Введение

Итак, мы решили реализовать «бочку» в автоматическом режиме. Очевидно, что для автоматического выполнения фигуры необходимо сформулировать соответствующий закон управления. Процесс придумывания будет гораздо безболезненнее и быстрее, если использовать математическую модель движения ЛА. Проверка закона управления в лётном эксперименте хоть и возможна, но требует гораздо большего времени, к тому же может оказаться гораздо дороже в случае потери или повреждения аппарата.

Так как при небольших углах атаки и скольжения самолёта его движение по крену практически не связано с движением в двух других каналах: путевом и продольном - для выполнения простой «бочки» достаточно будет построить модель движения только вокруг одной оси - оси ОХ связанной СК. По этой же причине, закон управления элеронами не будет существенно изменяться, когда дело дойдет до создания полной системы управления.

Модель движения

Уравнение движения ЛА вокруг продольной оси ОХ связанной СК крайне простое:

Где - момент инерции относительно оси ОХ , а момент состоит из нескольких составляющих, из которых для реалистичного описания движения нашего самолёта достаточно рассмотреть только две:

Где - момент, обусловленный вращением ЛА вокруг оси ОХ (демпфирующий момент), - момент, обусловленный отклонением элеронов (управляющий момент). Последнее выражение записано в линеаризованной форме: момент крена линейно зависит от угловой скорости и угла отклонения элеронов с постоянными коэффициентами пропорциональности и соответственно.

Как известно (например, из Вики), линейному дифференциальному уравнению

Соответствует апериодическое звено первого порядка

Где - передаточная функция, - оператор дифференцирования, - постоянная времени, а - коэффициент усиления.

Как перейти от дифференциального уравнения к передаточной функции?

В нашем случае от параметров уравнения к параметрам передаточной функции можно перейти следующим образом (зная, что производная отрицательная):




Для апериодического звена постоянная времени равна времени, за которое выходная величина при единичном ступенчатом воздействии входной величины принимает значение, отличающееся от установившегося на величину ~5%, а коэффициент усиления численно равен установившемуся значению выходной величины при единичном ступенчатом воздействии:


В построенной модели движения есть два неизвестных параметра: коэффициент усиления и постоянная времени . Эти параметры выражаются через характеристики физической системы: момент инерции , а также производные момента крена и :

Таким образом, если известен момент инерции , то, определив параметры модели, по ним можно восстановить параметры системы.

Параметры модели. Момент инерции

Наш летательный аппарат состоит из следующих частей: крыло, фюзеляж с оперением, двигатель, аккумулятор (АКБ) и БРЭО:

К БРЭО относятся: плата автопилота, плата приёмника СНС, плата радиомодема, плата приёмника сигнала от управляющей аппаратуры, два регулятора напряжения, регулятор оборотов двигателя, а также соединительные провода.

В силу малого веса БРЭО, его вкладом в общий момент инерции можно пренебречь.

Как проводилась оценка величины момента инерции?

Оценку момента инерции можно провести следующим образом. Посмотрим на самолёт вдоль оси ОХ :

А затем представим его в виде следующей упрощённой модели:


Схема для расчёта момента инерции . Слева вверху - аккумулятор, справа внизу - двигатель. Двигатель и аккумулятор располагаются на оси фюзеляжа

Видно, что для создания модели были отброшены: киль, горизонтальное оперение, винт, а также БРЭО. При этом остались: фюзеляж, крыло, аккумулятор, двигатель. Измерив массы и характерные размеры каждой части, можно вычислить моменты инерции каждой части относительно продольной оси фюзеляжа:


Общее значение момента инерции ЛА относительно оси ОХ получим сложением моментов инерции частей:

Оценив вклад каждой из частей ЛА в общий момент инерции , получилось следующее:

  • крыло - 96.3%,
  • фюзеляж - 1.6 %,
  • двигатель и аккумулятор - 2%,
Видно, что основной вклад в общий момент инерции вносит крыло. Это связано с тем, что крыло имеет довольно большой поперечный размер (размах крыла - 1 м):

Поэтому, несмотря на скромный вес (около 20% от общей взлётной массы ЛА), крыло имеет значительный момент инерции.

Параметры модели. Производные момента крена и

Вычисление производных момента крена – довольно трудная задача, связанная с расчётом аэродинамических характеристик ЛА численными методами или с помощью инженерных методик. Применение первых и вторых требует значительных временных, интеллектуальных и вычислительных затрат, которые оправданы при разработке систем управления большими самолётами, где стоимость ошибки всё же превышает затраты на построение хорошей модели. Для задачи управления БПЛА, масса которого не превосходит 2 кг, такой подход вряд ли оправдан. Другой способ вычисления этих производных - лётный эксперимент. Учитывая дешевизну нашего самолёта, а также близость подходящего поля для проведения такого эксперимента, для нас выбор был очевиден.

Записав в автопилот прошивку для ручного управления и регистрации параметров, мы собрали самолёт и подготовили его к испытаниям:

В лётном эксперименте удалось получить данные по углу отклонения элеронов и угловой скорости вращения ЛА. Пилот управлял самолётом в ручном режиме, выполняя полёт по кругу, развороты и «бочки», а бортовое оборудование регистрировало и отправляло необходимую информацию на наземную станцию. В результате были получены необходимые зависимости: (град/с) и (б/р). Величина представляет собой нормированный угол отклонения элеронов: значение 1 соответствует максимальному отклонению, а значение −1 - минимальному:

Как теперь определить и из полученных данных? Ответ - измерить параметры переходного процесса по графикам и .

Как определялись коэффициенты k и T?

Коэффициент усиления определялся путём отнесения величины установившегося значения угловой скорости к величине отклонения элерона:


Зависимости угла отклонения элеронов и угловой скорости крена от времени, полученные в лётном эксперименте

На предыдущем рисунке участкам установившегося значения угловой скорости приблизительно соответствуют, например, отрезки вблизи моментов времени 422, 425 и 438 с (отмечены тёмно-красным на рисунке).
Постоянная времени определялась из тех же графиков. Для этого найдены участки резкого изменения угла отклонения элерона, а затем измерено время, за которое угловая скорость принимает значение, отличающееся от установившегося значения на 5%.


Результат определения значений постоянной времени и коэффициента усиления следующий: , . Этим значениям коэффициентов при известном значении момента инерции соответствуют следующие значения производных момента крена:

Верификация модели

Итак, построив модель, основой которой является апериодическое звено

Можно провести её верификацию, подав на вход сигнал , полученный из лётного эксперимента, и сравнить выходной сигнал модели с величиной , также полученной в эксперименте.

Как проводилось моделирование?

Инструмент для проведения моделирования мы выбирали, прежде всего, основываясь на возможности повторения результатов широким кругом читателей: это прежде всего означает, что программа должна быть в общественном доступе. В принципе задачу моделирования поведения апериодического звена первого порядка можно решить и создав свой собственный инструмент с нуля. Но так как в дальнейшем модель будет усложняться, то создание своего инструмента может отвлечь от основной задачи - создания САУ пилотажного ДПЛА. С учётом принципа открытости инструмента мы выбрали JSBsim .

В предыдущем разделе мы получили значения коэффициентов и . Используем их для моделирования движения самолета. Из прошлой статьи мы помним, что конфигурация модели самолета в JSBsim задается при помощи XML файла. Создадим собственную модель:
0.2 1.0 0.2 0.03 0.5 0.03 0.5 -0.025 0 0.05 0.018 0.018 0.018 1.2 0 0 0 fcs/aileron-cmd-norm -1 1 Roll_moment_due_to_roll_rate velocities/p-aero-rad_sec -0.24 Roll_moment_due_to_aileron fcs/aileron-cmd-norm 2.4 Velocities/vc-kts Aero/alphadot-deg_sec Aero/betadot-deg_sec Fcs/throttle-cmd-norm OFF OFF OFF ON ON ON OFF OFF ON OFF OFF ON OFF
Так как мы строим модель движения аппарата только по крену, оставим многие из секций файла пустыми. В файле модели последовательно задаются следующие характеристики.

Геометрические размеры самолёта задаются в секции metrics : площадь крыла, размах, длина средней аэродинамической хорды, площадь горизонтального оперения, плечо горизонтального оперения, площадь вертикального оперения, плечо вертикального оперения, положение аэродинамического фокуса.

Массовые характеристики самолёта задаются в секции mass_balance : тензор инерции самолета, вес пустого самолета, положение центра масс.

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

В следующей секции, ответственной за систему управления , заполним канал, ответственный за управление по крену: укажем единственный вход fcs/aileron-cmd-norm , величина которого будет нормирована от -1 до 1.

Аэродинамические характеристики задаются в секции aerodynamics : силы задаются в скоростной системе координат, моменты - в связанной. Нас интересует момент по крену. В секции axis name=«ROLL» задаются функции, которые определяют момент сил от различных составляющих проекции момента аэродинамических сил на ось OX связанной системы координат. В нашей модели таких составляющих две. Первая составляющая - демпфирующий момент, который равен произведению угловой скорости на определенный ранее коэффициент . Вторая составляющая - это момент от элеронов при фиксированной скорости полёта: он равен произведению ранее определенного коэффициента на величину отклонения элеронов.

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

Проверить созданную модель можно на экспериментальных данных, полученных при лётных испытаниях. Для этого создаем скрипт следующего содержания:
sim-time-sec ge 0.0 Provide a time history input for the aileron sim-time-sec ge 0

sim-time-sec 0 0.00075 0.1 0.00374 0.2 -0.00075 0.3 -0.00075 0.4 -0.00075 0.5 -0.00075 0.6 0.00075 0.7 0.00075 ... 48.8 -0.00075 48.9 0.00000 49 -0.00075

где точками обозначены пропущенные данные. В знакомом нам по предыдущей статье файле скрипта появился новый тип события («Time Notif» ), который позволяет задавать непрерывное изменение параметра по времени. Зависимость параметра от времени задана табличной функцией. JSBSim линейно интерполирует значение функции между табличными данными. Процедура верификации модели движения по крену заключается в исполнении данного скрипта на созданной модели и сравнения результатов с экспериментальными.


Результат верификации показан на рисунке:


Как видно из рисунка, совпадение модели с реальностью чуть менее, чем полное.

Синтез управления для выполнения «бочки»

Получив модель, несложно определить, на какую величину и как долго необходимо отклонять элероны, чтобы выполнить «бочку». Одним из вариантов является следующий алгоритм отклонения:



Наличие отрезков длительностью по 0.1 с в начале и в конце алгоритма отклонения элеронов моделирует инертность сервопривода, который не может отклонить поверхности мгновенно. Модель показывает, что при таком законе отклонения элеронов ЛА должен выполнить один полный оборот вокруг оси ОХ , проверим?

Лётный эксперимент

Полученный закон управления элеронами был запрограммирован в автопилот, установленный на самолёт. Идея эксперимента проста: вывести самолёт в горизонтальный полёт, после чего задействовать полученный закон управления. В случае если реальное движение ЛА по крену соответствует созданной модели, то самолёт должен выполнить «бочку» - один полный оборот на 360 градусов.

Отдельно выражаем благодарность нашему верному пилоту за труд, профессионализм и удобный багажник на приоре-универсал!

В процессе проведения эксперимента стало ясно, что модель движения по крену была построена удачно - самолёт выполнял одну «бочку» за другой, как только пилот задействовал запрограммированный закон управления. На следующем рисунке показана угловая скорость , записанная в процессе эксперимента, и полученная по результатам моделирования, а также угол крена и тангажа из лётного эксперимента:


А на следующем рисунке показаны зарегистрированные в лётном эксперименте сигналы на элероны, руль высоты (РВ) и руль направления (РН):


Вертикальными линиями обозначены моменты начала и окончания выполнения «бочки». Из рисунков видно, что в процессе выполнения «бочки» пилот не вмешивается в управление рулём высоты и рулём направления, также видно, что угол тангажа неизменно стремится уменьшиться при выполнении «бочки» - самолёт затягивает в пикирование, как это и было предсказано по результатам моделирования в авиасимуляторе (см. статью «Пилотажный ДПЛА. Как правильно сделать бочку»). Если внимательно рассмотреть предыдущие графики, то станет видно, что третья «бочка» даже не была закончена, потому что пилот вмешался в управление, чтобы вывести самолёт из пикирования: настолько сильно изменяется угол тангажа при выполнении «бочки» одними элеронами.

Замечания

Выводы

В результате проведённой работы мы показали один из способов создания модели движения ДПЛА по угловой скорости . В лётном эксперименте было доказано, что созданная модель движения вполне соответствует моделируемому объекту. На основании разработанной модели получен закон программного управления, позволяющий выполнять «бочку» в автоматическом режиме. Также мы убедились, что выполнить правильную «бочку» одними элеронами не получится, а также наглядно это продемонстрировали.

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

Моделирование движения заключается в искусственном воспроизведении процесса движения физическими или математическими методами, например, с помощью ЭВМ.

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

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

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

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

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

Следует отметить, что в настоящее время область моделирования транспортных потоков находится в стадии формирования. Различные аспекты моделирования исследуются в МАДИ, ВНИИБД, НИИАТ и других организациях.

Допустим, вы двигаетесь на велосипеде, и вдруг кто-то толкает вас сбоку. Чтобы быстро восстановить равновесие и избежать падения, вы повернете руль велосипеда в направлении толчка. Велосипедисты делают это рефлекторно, но удивительно, что велосипед может выполнить это действие самостоятельно. Современные велосипеды могут самостоятельно удерживать равновесие даже при движении без управления. Посмотрим, как этот эффект можно смоделировать в COMSOL Multiphysics.

Что мы знаем о самобалансировании велосипедов

Современный велосипед не очень сильно отличается от безопасного велосипеда — одной из первых конструкций, появившейся в 80-х годах XIX века. По прошествии более ста лет ученые все еще пытаются выяснить, за счет каких эффектов велосипед становится самобалансируемым. Другими словами, как неуправлемый велосипед сохраняет равновесие в вертикальном положении? Описанию движения велосипеда с помощью аналитических уравнений посвящено множество опубликованных работ. Одной из первых важных публикаций по этой теме была статья Фрэнсиса Уиппла, в которой он получил общие нелинейные уравнения динамики велосипеда, управляемого велосипедистом без использования рук.

Принято считать, что устойчивость велосипеда обеспечивается двумя факторами — гироскопической прецессией переднего колеса и стабилизирующим действием продольного наклона оси поворота колеса. Совсем недавно команда исследователей из Делфта и Корнелла (см. ) опубликовала всеобъемлющий обзор линеаризованных уравнений движения для модели велосипеда Уиппла. Они использовали свои результаты для демонстрации самобалансирующегося велосипеда. Их исследование показывает, что этому явлению нельзя дать простое объяснение. Сочетание факторов, в том числе гироскопического и стабилизирующего эффектов, геометрии велосипеда, скорости и распределения массы позволяет неуправляемому велосипеду сохранять вертикальное положение.

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

Положение велосипеда в разные моменты времени.

Многотельная модель велосипеда

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


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

Используются следующие ограничения: Отсутствие проскальзывания в прямом направлении:

{\frac{d\bold{u}}{dt}.\bold{e}_{2}=r\frac{d\bold{\theta}_s}{dt}}

Отсутствие проскальзывания в поперечном направлении:

\frac{d\bold{u}}{dt}.\bold{e}_{3}=r\frac{d\bold{\theta}_{l}}{dt}

Отсутствие проскальзывания перпендикулярно поверхности контакта с землей:

\frac{d\bold{u}}{dt}.\bold{e}_{4}=0

где \bold{e}_{2} , \bold{e}_{3} , and \bold{e}_{4} — мгновенное направление (наклонная ось), поперечное направление (ось вращения) и нормаль к поверхности контакта (\bold{e}_{4}=\bold{e}_{2} \times\bold{e}_{3}) , соответственно;

\frac{d\bold{u}}{dt} — поступательная скорость движения; r — радиус колеса; \frac{d\bold{\theta}_{s}}{dt} — угловая скорость вращения; \frac{d\bold{\theta}_{l}}{dt} — угловая наклонная скорость.

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

(\bold{u}-\bold{u}_{p}).\bold{e}_{2}=r(\bold{\theta}_{s}-\bold{\theta}_{sp})

(\bold{u}-\bold{u}_{p}).\bold{e}_{3}=r(\bold{\theta}_{l}-\bold{\theta}_{lp})

(\bold{u}-\bold{u}_{p}).\bold{e}_{4}=0

где \bold{u}_{p} , \bold{\theta}_{sp} и\bold{\theta}_{lp} — это вектор смещения, угол вращения и наклона в предыдущий момент времени, соответственно.

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

Моделирование движения самобалансирующегося велосипеда

Для анализа мы выбрали велосипед, угол наклона руля которого составляет 18°. Начальное значение скорости велосипеда составляет 4.6 м/с. Через 1 секунду после начала движения на велосипед в течение очень короткого периода времени воздействует сила 500 Н. Под действием силы велосипед отклоняется от прямолинейной траектории движения в заданном направлении.

В течении первой секунды велосипед движется вперед вдоль первоначально заданного направления с постоянной скоростью. Затем боковое усилие вызывает отклонение. Отметим, что велосипедист не держит руки на руле и не может управлять балансом велосипеда. Что происходит дальше? Мы можем заметить, что как только велосипед начинает наклоняться, руль поворачивается в направлении падения. Корректировка положения руля при падении приводит к восстановлению равновесия велосипеда.

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

Движение велосипеда на ровной поверхности при отклонении от прямолинейного движения. Стрелка показывает наклон велосипеда.

Результаты расчета углов наклона и поворота руля (слева) и относительная угловая скорость (справа) велосипеда.

Проведение анализа устойчивости

Таким образом, мы узнали, что велосипед может самобалансироваться. Исследование показало, что невозможно выделить какой-то один параметр, определяющий устойчивость велосипеда. Конструкция велосипеда, распределение массы и скорость движения — все эти факторы влияют на устойчивость. Чтобы лучше понять это явление, мы провели дополнительный анализ для изучения влияния двух параметров — начальной скорости и наклона рулевой оси. Мы использовали описанную выше модель велосипеда с углом наклона оси руля 18° и начальной скоростью 4.6 м/с в качестве исходной конфигурации и провели параметрический анализ влияния этих двух факторов.

Различные значения начальной скорости

Велосипед не может оставаться в строго вертикальном положении, когда стоит на месте. Мы изменяли скорость движения от 2.6 м/с до 6.6 м/с с шагом 1 м/с, чтобы оценить влияние этого параметра. В диапазоне 2.6–3.6 м/с велосипед наклоняется слишком сильно и неустойчив. На скорости 5.6 м/с скорость наклона стремится к нулю, но сам угол наклона приобретает ненулевое значение. Хотя данная конфигурация устойчива, велосипед будет двигаться по кругу с небольшим наклоном. На 6.6 м/с наклон и угол поворота руля увеличиваются со временем, делая движение неустойчивым.

Неустойчивое Устойчивое Неустойчивое
2.6 м/с 3.6 м/с 4.6 м/с 5.6 м/с 6.6 м/с

Устойчивый случай соответствует скорости 5.6 м/с (слева), а неустойчивый — скорости 6.6 м/с (справа).

Угол поворота руля

Узел рулевого управления очень важен для самобалансировки велосипеда. Если велосипедом невозможно управлять (например, если руль заклинило), то велосипед не сможет компенсировать наклон, поэтому он в итоге упадет. В этой связи, поворот оси руля, который контролирует уход вилки, также влияет на самобалансировку велосипеда.

Чтобы проанализировать влияние поворота оси руля на устойчивость велосипеда, мы изменяли углы поворота руля от 15° до 21° с шагом 1°. При угле в 15° наклон и угол поворота руля увеличиваются со временем, что делает данную конфигурацию неустойчивой. Велосипед устойчив в диапазоне от 16° до 19° и неустойчив для больших углов. При значениях поворота больше 19°, наклон и угол поворота колеблются, и эти осцилляции со временем возрастают, что приводит к потере устойчивости.

В этой публикации мы рассказали, как смоделировать движение неуправляемого самобалансирующегося велосипеда с помощью модуля Динамика многотельных систем (Multibody Dynamics) в COMSOL Multiphysics. Мы продемонстрировали, как реализовать ограничения на проскальзывание на жестком колесе через уравнения, а затем объединили эти ограничения с многотельной моделью велосипеда. Затем мы проанализировали влияние начальной скорости и поворота оси на устойчивость велосипеда. Оценив эти параметры, мы увидели, что велосипед может сохранять устойчивость в одной конфигурации и терять ее в другой.

Самобалансировка велосипеда является следствием целого ряда факторов. С помощью нашего анализа и в соответствии с предыдущими исследованиями мы продемонстрировали, что устойчивость велосипеда связана с его способностью "подруливать" в направлении наклона.

Сокращенный перевод-пересказ статьи: .

Введение

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

Физическое моделирование, т. е. моделирование движения персонажей, основанное на законах физики (а точнее - механики), изучается достаточно давно. В литературе (см. и др.) предлагаются различные подходы, много усилий вложено в создание точных и надежных алгоритмов. Точные методы моделирования движения известны в физике уже давно. Однако для игр и систем виртуальной реальности, точность - не самое главное достоинство (хотя хорошо, когда она есть). Гораздо важнее правдоподобие (программист может искажать модель реальности сколько угодно, лишь бы при этом ему удалось увлечь игрока) и скорость выполнения (на выполнение расчетов по моделированию движения отводится лишь часть времени, которое длится кадр анимации). В случае физического моделирования, термин "правдоподобие" подразумевает также устойчивость: нельзя признать удачным метод моделирования, при котором тела проникают сквозь препятствия или подпрыгивают, когда должны лежать неподвижно. Методы, описанные в данной работе, разрабатывались в первую очередь для достижения правдоподобия и скорости расчета. Они имеют высокую производительность и достаточно просты в реализации (по крайней мере, в сравнении с другими методами, решающими те же задачи).

Рассматриваемый метод является итеративным, так что, начиная с определенного шага, он может быть остановлен в любой момент. Это дает возможность выбирать между точностью расчетов и затраченным временем: если некоторая величина погрешности считается приемлемой, коду можно разрешить работать быстрее; причем величина погрешности может подбираться адаптивно во время выполнения. Метод также обрабатывает столкновения и контакты покоя (resting contact) и справляется с моделированием стопки сложенных друг на друга тел, что для многих физических движков является проблемой.

Успех применения метода складывается из правильного комбинирования и использования преимуществ нескольких техник:

  • метода численного интегрирования Верле;
  • обработки столкновений и проникновения тел при помощи проецирования (by projection);
  • простого решателя связей (constraint solver), использующего релаксацию;
  • аппроксимации квадратного корня, повышающей скорость вычислений;
  • моделирования твердых тел, как частиц, соединенных связями.

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

Содержание организовано следующим образом. В разделе 2, описано представление системы частиц без использования скорости. Такое представление имеет ряд преимуществ, из которых наиболее существенными являются устойчивость и простота реализации связей и других ограничений (constraints). В раздел 3 описано, как происходит обработка столкновений. Затем, в разделе 4, система частиц дополняется связями, позволяющими моделировать движение ткани. Раздел 5 объясняет, как настроить систему связанных между собой частиц для моделирования твердого тела. Далее, в разделе 6, показано как реализовать соединения между телами (в частности, шарниры). Раздел 7 содержит различные короткие заметки и некоторый опыт по реализации трения.

В дальнейшем, векторы обозначаются буквами со стрелочками, а их компоненты - нижними индексами: \(\vec{x}=(x_1,x_2,x_3)\) .

Метод интегрирования Верле

Сердцем симуляции (т. е. имитации физического процесса при помощи компьютерной системы) является система частиц. Обычно, при реализации такой системы предполагается, что каждая частица имеет две основные характеристики: координату (положение, position) \(\vec{x}\) и скорость \(\vec{v}\) . Тогда, новые значения координат \(\vec{x}^\prime\) и скорости \(\vec{v}^\prime\) вычисляются по формулам

$$ \begin{aligned} \vec{x}^\prime &= \vec{x} + \vec{v} \Delta t, \\ \vec{v}^\prime &= \vec{v} + \vec{a} \Delta t, \end{aligned} $$

где \(\Delta t\) - шаг по времени, \(\vec{a}\) - ускорение, вычисленное в соответствии со 2-м законом Ньютона \(\vec{f}=m \vec{a}\) (где \(\vec{f}\) - суммарная сила, действующая на частицу). Приведенные формулы реализуют простейший метод численного интегрирования - метод Эйлера.

Мы рассмотрим другое описание частицы, в котором скорость не используется: вместо хранения положения и скорости каждой частицы, мы будем сохранять текущее положение частицы \(\vec{x}\) и ее положение на предыдущем шаге интегрирования \(\vec{x}^{*}\) . Предполагая шаг интегрирования постоянным, получим следующие формулы для вычисления новых значений:

$$ \begin{aligned} \vec{x}^\prime &= 2\vec{x} - \vec{x}^{*} + \vec{a} \Delta t^2, \\ \vec{x}^{*} &= \vec{x}. \end{aligned} $$

Этот способ численного интегрирования называется методом Верле (см. ) и активно используется в молекулярной динамике.

Метод Верле опирается на приближенную формулу вычисления второй производной

$$ \frac{\Delta^2 \vec{x}}{\Delta t^2} = \frac{ \frac{\vec{x}^\prime - \vec{x}}{\Delta t} - \frac{\vec{x} - \vec{x}^{*}}{\Delta t} }{\Delta t} = \frac{\vec{x}^\prime - 2\vec{x} + \vec{x}^{*}}{\Delta t^2} = \vec{a} $$

Такое приближение не является самым точным (есть и более совершенные методы численного интегрирования), зато оно устойчиво и работает быстро. Уменьшая коэффициент 2 до, скажем, 1.99, мы тем самым вводим силу сопротивления, рассеивающую энергию системы. Отметим также, что \(\vec{x}-\vec{x}^{*}\) - это расстояние, пройденное за последний шаг интегрирования (\(\vec{v}\Delta t\) ).

В конце шага интегрирования текущее положение каждой частицы \(\vec{x}\) сохраняется в соответствующей переменной \(\vec{x}^{*}\) для использования на следующем шаге. Если частиц в системе много, то вместо копирования их координат удобно использовать перенаправление указателей.

Код, реализующий описанные выше идеи, может выглядеть так (класс Vector3 содержит все необходимые операции над векторами)

class ParticleSystem { Vector3 m_x [ NUM_PARTICLES ]; // Текущее положение Vector3 m_oldx [ NUM_PARTICLES ]; // Предыдущее положение Vector3 m_a [ NUM_PARTICLES ]; // Суммарная сила (ускорение) Vector3 m_vGravity ; // Гравитация float m_fTimeStep ; public : void TimeStep (); private : void Verlet (); void SatisfyConstraints (); void AccumulateForces (); // (конструкторы, инициализацию полей и т.п. опустим) }; // шаг интегрирования методом Верле void ParticleSystem :: Verlet () { for (int i = 0 ; i < NUM_PARTICLES ; i ++ ) { Vector3 & x = m_x [ i ]; Vector3 temp = x ; Vector3 & oldx = m_oldx [ i ]; Vector3 & a = m_a [ i ]; x += x - oldx + a * fTimeStep * fTimeStep ; oldx = temp ; } } // суммирование сил, действующих на каждую частицу void ParticleSystem :: AccumulateForces () { // Все частицы находятся под действием гравитации for (int i = 0 ; i < NUM_PARTICLES ; i ++ ) m_a [ i ] = m_vGravity ; } // проверка соблюдения наложенных связей void ParticleSystem :: SatisfyConstraints () { // Сейчас нам не важно, как это реализовано. } // шаг расчета void ParticleSystem :: TimeStep () { AccumulateForces (); Verlet (); SatisfyConstraints (); }

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

Попробуйте задать \(\vec{a}=(0,0,1)\) и начальные условия \(\vec{x}=(1,0,0)\) , \(\vec{x}^*=(0,0,0)\) . Вычислите вручную несколько шагов и посмотрите, что получится.

Столкновения и обработка контактов при помощи проецирования

Способы обработки контактов между телами, основанные на использовании штрафных функций (penalty-based schemes), предполагают, что в месте контакта, где возможно проникновение тел друг в друга, нужно вставить пружину для моделирования этого контакта. Такой подход прост в реализации, но приводит к ряду серьезных проблем. В частности, очень трудно подобрать жесткость пружины так, чтобы, с одной стороны, объекты не проникали друг в друга слишком глубоко, а с другой - чтобы система не потеряла устойчивость из-за слишком большой жесткости пружин. Еще один подход к обработке столкновений заключается в том, что при обнаружении столкновения время "отматывается" назад, вплоть до точного момента контакта тел (например, с помощью бинарного поиска), затем корректируются положения и скорости тел (по известным из курса физики формулам для столкновений), после чего расчет начинается заново с этого момента времени. И так - для каждого столкновения. Не слишком экономный подход, если предполагается моделировать в реальном времени движение множества тел.

Здесь мы рассмотрим другой подход. Проникшие в препятствие частицы мы будем проецировать за пределы препятствия. Под проецированием мы понимаем перемещение частицы, настолько малое, чтобы только освободить ее от препятствия. Как правило, это предполагает перемещение частицы по направлению нормали к поверхности контакта (препятствия) - отсюда и происхождение термина "проецирование".

Рассмотрим следующий пример. Пусть наш "мир" представляет собой внутренность куба размером (0,0,0)--(1000,1000,1000) и, кроме того, коэффициент восстановления (restitution coefficient) частиц равен нулю (т. е. столкнувшиеся с поверхностью куба частицы не отражаются от нее). Чтобы координаты частиц оставались внутри куба, запишем следующий код, реализующий проецирование:

// Заставляет частицы оставаться внутри куба void ParticleSystem :: SatisfyConstraints () { for (int i = 0 ; i < NUM_PARTICLES ; i ++ ) { // Для всех частиц Vector3 & x = m_x [ i ]; x = vmin (vmax (x , Vector3 (0 , 0 , 0 )), Vector3 (1000 , 1000 , 1000 )); } }

(vmax представляет собой покомпонентную операцию вычисления максимума, а vmin - аналогичное вычисление минимума). Это код позволяет обработать как столкновения, так и неподвижные контакты (resting contact) (т. е. случаи, когда точка покоится на поверхности куба), и сохраняет положение всех частиц внутри куба. Прелесть метода Верле в том, что соответствующие изменения в значения скоростей вносятся автоматически. В последующих вызовах TimeStep() скорость уже будет скорректирована так, чтобы не содержать составляющей, перпендикулярной поверхности куба (что соответствует нулевому значению коэффициента восстановления). См. рис.1.

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

Обработка нескольких одновременно наложенных связей методом релаксации

Модель ткани обычно представляет собой систему частиц, соединенных пружинами. Дифференциальные уравнения такой системы построить несложно. Но одно дело построить, и совсем другое - решить. При этом всплывают все те проблемы, что мы имели при использовании штрафных функций: слишком жесткие пружины приводят к тому, что система уравнений сама становиться "жесткой" (stiff system), а это приводит к неустойчивости, если используются простейшие методы численного интегрирования или к медленной работе, если используются методы более совершенные - в обоих случаях головная боль обеспечена. И наоборот, слишком мягкие пружины приводят к тому, что ткань будет выглядеть нереалистично упругой.

Однако самое интересное произойдет, если устремить жесткость пружин к бесконечности: система вдруг становится разрешима даже для весьма простого (и быстрого) метода интегрирования, оставаясь при этом устойчивой. Но прежде чем мы продолжим разговор о ткани, давайте вернемся к предыдущему примеру. Куб, с которым мы имели дело, можно рассматривать как совокупность односторонних (unilateral) связей (т. е. связей, записываемых в форме неравенств) - по одной для каждой стороны куба - которые должны выполняться все время моделирования.

\begin{equation} x_i \geq 0 \ \text{and}\ x_i \leq 1000 \quad (i=1,2,3). \label{eq:C1} \end{equation}

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

// Псевдокод, позволяющий выполнить ограничения (1) for i = 1 , 2 , 3 set xi = min { max { xi , 0 }, 1000 }

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

Расширим нашу модель, добавив к ней стержень длиной 100. Для этого нам понадобится задать две частицы (\(\vec{x}_1\) и \(\vec{x}_2\) ) и потребовать, чтобы расстояние между ними всегда было равно 100. Математическая запись этой двухсторонней (bilateral) связи имеет вид:

\begin{equation} |\vec{x}_2-\vec{x}_1| = 100. \label{eq:C2} \end{equation}

Даже если в начальный момент времени положения частиц удовлетворяют условиям \eqref{eq:C2}, то уже в следующий момент эти условия, скорее всего, выполняться не будут. Для того чтобы получить корректное значение расстояния, переместим частицы, проецируя их на множество решений, описанных \eqref{eq:C2}. Для этого частицы либо отодвигаются друг от друга, либо подтягиваются ближе, в зависимости от того, мало или велико расстояние, полученное численным интегрированием. См. рис.2.

Перемещение частиц для исправления расстояния, не удовлетворяющего ограничению \eqref{eq:C2}

Псевдокод, реализующий выполнение условий \eqref{eq:C2}:

Delta = x2 - x1 ; deltalength = sqrt (delta * delta ); diff = (deltalength - restlength ) / deltalength ; x1 -= delta * 0.5 * diff ; x2 += delta * 0.5 * diff ;

Заметим, что delta - вектор, а delta*delta - скалярное произведение. Этот псевдокод будет раздвигать или сдвигать частицы так, чтобы добиться требуемого расстояния между ними. И вновь мы можем рассматривать это как бесконечно жесткую пружину, мгновенно возвращающую себе нормальную длину, равную 100.

Теперь предположим, что, помимо условия \eqref{eq:C2}, должно выполняться и условие \eqref{eq:C1} (частицы обязаны находиться внутри куба). Может оказаться, что при попытке соблюсти условие \eqref{eq:C2}, какая-то из частиц стержня нарушит требования \eqref{eq:C1} (стержень будет торчать из куба). Можно, конечно, снова спроектировать частицу-нарушителя на поверхность куба, выполняя \eqref{eq:C1}, но тогда будет нарушено уже \eqref{eq:C2}.

Чтобы удовлетворить одновременно требованиям \eqref{eq:C1} и \eqref{eq:C2} нам нужно решить систему уравнений. Мы это и сделаем, но не напрямую: просто будем повторять два фрагмента псевдокода друг за другом какое-то количество раз, в надежде, что результат окажется полезным. Такой подход реализован в следующем коде:

// реализация моделирования стержня внутри куба void ParticleSystem :: SatisfyConstraints () { for (int j = 0 ; j < NUM_ITERATIONS ; j ++ ) { // Сначала выполним условия (1) for (int i = 0 ; i < NUM_PARTICLES ; i ++ ) { // Для всех частиц Vector3 & x = m_x [ i ]; x = vmin (vmax (x , Vector3 (0 , 0 , 0 )), Vector3 (1000 , 1000 , 1000 )); } // Теперь удовлетворим (2) Vector3 & x1 = m_x [ 0 ]; Vector3 & x2 = m_x [ 1 ]; Vector3 delta = x2 - x1 ; float deltalength = sqrt (delta * delta ); float diff = (deltalength - restlength ) / deltalength ; x1 -= delta * 0.5 * diff ; x2 += delta * 0.5 * diff ; } }

(здесь опущена инициализация частиц). Хотя такой способ "тупого" повторения и может показаться несколько наивным, тем не менее, он сходится к решению, которое мы ищем! В математике он называется методом релаксации (или Якоби, или Гаусса-Зейделя - в зависимости от того, как именно вы это делаете, см. ). Он работает, последовательно удовлетворяя отдельные ограничения, и сходится к глобальной конфигурации, которая удовлетворяет всем ограничениям одновременно. Этот метод очень полезен в ситуациях, когда должны одновременно выполняться несколько независимых ограничений.

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

Моделирование ткани

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

Функция HandleConstraints() , отвечающая за обработку связей, использует релаксацию по всем ограничениям. Цикл релаксации может повторятся несколько раз. Однако, чтобы получить хорошо выглядящую анимацию, в большинстве случаев достаточно всего одной итерации. Это означает, что расход времени в симуляции ткани зависит в основном от того, как долго выполняются \(N\) операций вычисления квадратного корня и \(N\) делений (где \(N\) - число ребер в сетке, моделирующей ткань). Ниже мы покажем один трюк, позволяющий избавиться от вычисления квадратного корня. Но сначала рассмотрим как выглядит обработка ограничений.

// Реализация моделирования тканей struct Constraint { int particleA , particleB ; float restlength ; }; // Предположим, что массив ограничений m_constraints уже существует void ParticleSystem :: SatisfyConstraints () { for (int j = 0 ; j < NUM_ITERATIONS ; j ++ ) { for (int i = 0 ; i < NUM_CONSTRAINTS ; i ++ ) { Constraint & c = m_constraints [ i ]; Vector3 & x1 = m_x [ c . particleA ]; Vector3 & x2 = m_x [ c . particleB ]; Vector3 delta = x2 - x1 ; float deltalength = sqrt (delta * delta ); float diff = (deltalength - c . restlength ) / deltalength ; x1 -= delta * 0.5 * diff ; x2 += delta * 0.5 * diff ; } // Прикрепим одну из частиц, составляющих ткань, к началу координат m_x [ 0 ] = Vector3 (0 , 0 , 0 ); } }

Теперь обсудим, как избавиться от вычисления квадратного корня. Если все ограничения соблюдены (ну, или почти соблюдены), то, как мы уже знаем, результат вычисления квадратного корня стремится к \(r\) - нормальной длине связи (стержня). Мы используем этот факт чтобы получить приближенное выражение для функции квадратного корня. Заменим функцию \(\sqrt{x}\) членом 1-го порядка из ее разложения в ряд Тейлора в окрестности длины \(r\) (это эквивалентно одной итерации метода Ньютона-Рафсона с начальным приближением \(r\) ). После некоторых преобразований, получим следующий псевдокод:

// Псевдокод для соблюдения ограничений (2), использующий приближение sqrt delta = x2 - x1 ; delta *= restlength * restlength / (delta * delta + restlength * restlength ) - 0.5 ; x1 -= delta ; x2 += delta ;

Обратите внимание, что если расстояние уже удовлетворяет ограничениям (т. е., если |delta|=restlength), то мы получим delta равное (0,0,0) и никаких изменений не произойдет.

Теперь при обработке каждой связи мы больше не используем квадратные корни. Кроме того, квадрат значения restlength * restlength можно вычислить заранее. Трудоемкие операции сокращены до выполнения \(N\) делений за кадр (и доступа к соответствующей памяти) - трудно придумать что-то, работающее существенно быстрее.

Ограничения не обязательно будут удовлетворены за одну итерацию, но, благодаря методу Верле, система быстро сходится к правильному состоянию (когда все ограничения соблюдены) - буквально за несколько кадров. На самом деле, использование только одной итерации и аппроксимации квадратного корня снимает проблему жесткости системы уравнений, которая обязательно проявилась бы у системы с абсолютно жесткими стержнями.

Размещая связи-стержни между парами соседних вершин, можно распространить алгоритм моделирования ткани на моделирование растений.

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

Так, соблюдение ограничения \eqref{eq:C2} для частиц с разными массами реализует следующий псевдокод:

// Псевдокод для соблюдения ограничений (2) delta = x2 - x1 ; deltalength = sqrt (delta * delta ); diff = (deltalength - restlength ) / (deltalength * (invmass1 + invmass2 )); x1 -= invmass1 * delta * diff ; x2 += invmass2 * delta * diff ;

Здесь invmass1 и invmass2 хранят обратные массы частиц \(\vec{x}_1\) и \(\vec{x}_2\) . Если мы хотим, чтобы частица оставаться неподвижной, нужно установить для нее invmass = 0 , что соответствует бесконечной массе. Как и выше, для ускорения расчетов можно использовать приближенное вычисление квадратного корня.

Твердые тела

Уравнения движения твердых тел были предложены задолго до изобретения современных компьютеров. Для того, чтобы в те времена получить какие-то полезные результаты, математики должны были выполнять преобразования формул. Это привело к появлению таких полезных понятий и инструментов, как тензор инерции, момент импульса, момент сил, кватернионы для представления ориентации и т. п. Между тем, имеющиеся сейчас возможности обрабатывать огромные объемы данных в цифровой форме позволяют проводить расчеты для более простых элементов, а в некоторых случаях даже делают такие расчеты более выгодными. В случае трехмерных твердых тел, это означает, что может оказаться удобным моделировать твердое тело с помощью четырех частиц и шести связей (дающих правильное количество степеней свободы: \(4 \cdot 3 - 6 = 6\) ). Это упрощает множество вещей, и именно этим мы займемся далее.

Рассмотрим тетраэдр, в каждую из четырех вершин которого помещена частица. Кроме того, каждое из шести ребер тетраэдра представляет собой ограничение типа стержня, рассмотренное в предыдущем разделе. Этого вполне достаточно, чтобы имитировать твердое тело. Тетраэдр можно поместить внутрь куба, рассмотренного выше, и интегратор Верле обеспечит его правильное движение. Функция SatisfyConstraints() должна позаботиться о двух вещах: 1) чтобы частицы оставались внутри куба, и 2) чтобы были соблюдены шесть ограничений-стержней. Сделать это, как и раньше, можно с использованием релаксации: обычно достаточно 3-х--4-х итераций. Не забывайте также об эффективном вычислении квадратного корня.

Однако ясно, что при столкновениях твердые тела будут вести себя не так как "скелетные" тетраэдры. Существует и другая проблема: до сих пор мы обнаруживали факт столкновения между твердым телом и окружающим "миром" только на основе информации о вершинах: если вершина оказывалась вне куба, она снова проектировалась вовнутрь. Это прекрасно работает, пока внутренняя часть "мира" выпукла. Если же это не так, то тетраэдр сможет проникнуть сквозь границу "мира" даже когда ни одна из его вершин эту границу не пересекала (см. рис.3, где треугольник представляет собой плоский аналог тетраэдра). Рассмотрим, как решается эта проблема.

Сначала разберем более простой вариант задачи. Возьмем стержень, поместим его в кубический "мир" и предположим, что у куба есть небольшой выступ, направленный внутрь. Теперь стержень может пересечь границы "мира", хотя обе частицы на его концах остаются внутри куба (рис.4). Мы не будем вдаваться в тонкости разработки механизма обнаружения столкновений (collision detection), так как это целая отдельная наука. Вместо этого предположим, что подсистема обнаружения столкновений уже существует и делает свое дело: позволяет определить глубину проникновения и координаты точек проникновения для каждого из двух сталкивающихся объектов. Одно из определений точек проникновения и глубины проникновения звучит так: глубина проникновения \(d_p\) - это кратчайшее расстояние, на которое нужно развести два объекта в подходящем направлении, чтобы избежать их столкновения. Точки проникновения - это точки на каждом из объектов, которыми объекты касаются друг друга после того, как упомянутый выше перенос состоялся.

Взгляните еще раз на рис.4. Здесь, после этапа численного интегрирования, стержень проник через границу. Детектор столкновений определил две точки проникновения: \(\vec{p}\) и \(\vec{q}\) . На рис.4а, точка \(\vec{p}\) фактически совпадает с одной из концевых частиц: \(\vec{p}=\vec{x}_1\) . На рис.4б, \(\vec{p}\) лежит между \(\vec{x}_1\) и \(\vec{x}_2\) на расстоянии 1/4 длины стержня от \(\vec{x}_1\) . В обоих случаях, точка \(\vec{p}\) лежит на стержне и, следовательно, ее координаты могут быть выражены в виде линейной комбинации координат точек \(\vec{x}_1\) и \(\vec{x}_2\) : \(\vec{p} = c_1\vec{x}_1 + c_2\vec{x}_2\) такой, что \(c_1 + c_2 = 1\) . В первом случае \(c_1 = 1\) , \(c_2 = 0\) , а во втором - \(c_1 = 0.75\) и \(c_2 = 0.25\) . Эти значения говорят нам, на какое расстояние нужно передвинуть соответствующие частицы.

Чтобы скорректировать положение стержня, переместим его так, чтобы точка \(\vec{p}\) совпала с \(\vec{q}\) . Для этого передвинем частицы \(\vec{x}_1\) и \(\vec{x}_2\) в направлении, заданном вектором, соединяющим \(\vec{p}\) и \(\vec{q}\) : .

В первом случае (рис.4а), мы просто cпроектируем \(\vec{x}_1\) за пределы области, где ей "запрещено" находиться, также как это делали раньше (в направлении \(\vec{q}\) ). Этого будет достаточно, а координаты \(\vec{x}_2\) вообще не нужно изменять. Во втором случае (рис.4б) точку \(\vec{x}_1\) также нужно перенести на большее расстояние, чем \(\vec{x}_2\) , поскольку точка \(\vec{p}\) расположена ближе к \(\vec{x}_1\) (действительно, так как \(\vec{p} = 0.75\vec{x}_1 + 0.25\vec{x}_2\) , то всякий раз перемещая \(\vec{x}_1\) на величину 0.75, мы перемещаем \(\vec{x}_2\) только на 0.25). Другими словами, новые положения частиц \(\vec{x}_1^\prime\) и \(\vec{x}_2^\prime\) задаются соотношениями

\begin{equation} \begin{aligned} \vec{x}_1^\prime &= \vec{x}_1 + 0.75\lambda\cdot\vec{\Delta}, \\ \vec{x}_2^\prime &= \vec{x}_2 + 0.25\lambda\cdot\vec{\Delta}, \end{aligned} \label{eq:x_new} \end{equation}

где \(\lambda\) - неизвестная величина. Новое положение частицы \(\vec{p}\) - \(\vec{p}^\prime\) - вычисляется по формуле

$$ \vec{p}^\prime = c_1\vec{x}_1^\prime + c_2\vec{x}_2^\prime . $$

Вспомним, что мы хотим добиться, чтобы \(\vec{p}^\prime = \vec{q}\) , т. е. должны выбрать \(\lambda\) в точности таким, чтобы \(\vec{p}^\prime\) в результате совпало с \(\vec{q}\) . Так как мы перемещаем частицы только в направлении \(\vec{\Delta}\) , то \(\vec{p}\) также перемещается в направлении \(\vec{\Delta}\) и, следовательно, решение уравнения \(\vec{p}^\prime = \vec{q}\) можно найти, выразив \(\lambda\) из

\begin{equation} \vec{p}^\prime\cdot\vec{\Delta} = \vec{q}\cdot\vec{\Delta} . \label{eq:pq} \end{equation}

Расписывая выражение, стоящее в левой части равенства, получим

$$ \begin{aligned} \vec{p}^\prime\cdot\vec{\Delta} &= (0.75\vec{x}_1^\prime + 0.25\vec{x}_2^\prime) \cdot\vec{\Delta} \\ &= (0.75 (\vec{x}_1 + 0.75\lambda\cdot\vec{\Delta}) + 0.25 (\vec{x}_2 + 0.25\lambda\cdot\vec{\Delta})) \cdot\vec{\Delta} \\ &= ((0.75\vec{x}_1 + 0.25\vec{x}_2)\cdot\vec{\Delta} + \lambda(0.75^2 + 0.25^2)\cdot\Delta^2 \\ &= \vec{p} \cdot\vec{\Delta} + \lambda(0.75^2 + 0.25^2)\cdot\Delta^2 , \end{aligned} $$

что, с учетом правой части \eqref{eq:pq}, дает

$$ \lambda = \frac{(\vec{p}-\vec{q}) \cdot\vec{\Delta}}{(0.75^2 + 0.25^2)\cdot\Delta^2} . $$

Подставляя найденное \(\lambda\) в \eqref{eq:x_new}, получим скорректированные положения частиц \(\vec{x}_1\) и \(\vec{x}_2\) , при которых \(\vec{p}^\prime\) совпадет с \(\vec{q}\) .

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

В случае тетраэдра описанная выше стратегия будет работать аналогично. Сначала находятся точки взаимопроникновения \(\vec{p}\) и \(\vec{q}\) (они также могут находится внутри треугольника) и \(\vec{p}\) представляется линейной комбинацией четырех частиц \(\vec{p}=c_1\vec{x}_1+c_2\vec{x}_2+c_3\vec{x}_3+c_4\vec{x}_4\) таких, что \(c_1+c_2+c_3+c_4=1\) (это потребует решения небольшой системы линейных уравнений). После того, как будет найден \(\vec{\Delta} = \vec{q}-\vec{p}\) , можно будет найти значение \(\lambda\) по формуле

$$ \lambda = \frac{(\vec{p}-\vec{q}) \cdot\vec{\Delta}}{(c_1^2 + c_2^2 + c_3^2 + c_4^2)\cdot\Delta^2} , $$

а исправленные положения частиц определяются как

$$ \begin{align*} \vec{x}_1^\prime &= \vec{x}_1 + c_1\lambda\cdot\vec{\Delta}, \\ \vec{x}_2^\prime &= \vec{x}_2 + c_2\lambda\cdot\vec{\Delta}, \\ \vec{x}_3^\prime &= \vec{x}_3 + c_3\lambda\cdot\vec{\Delta}, \\ \vec{x}_4^\prime &= \vec{x}_4 + c_4\lambda\cdot\vec{\Delta}. \end{align*} $$

Итак, мы рассмотрели столкновение одного твердого тела с неподвижным "миром". Описанный выше метод можно легко обобщить для обработки столкновений нескольких твердых тел. При этом столкновения обрабатываются для одной пары тел в один момент времени и, вместо того, чтобы перемещать только \(\vec{p}\) , понадобится перемещать \(\vec{p}\) и \(\vec{q}\) по направлению друг к другу.

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

Во-первых, куб должен быть каким-то образом прикреплен к тетраэдру. Один из подходов состоит в том, что в качестве центра куба выбирается центр масс тетраэдра \(0.25\cdot (\vec{x}_1 + \vec{x}_2 + \vec{x}_3 + \vec{x}_4)\) , а затем по текущим координатам тетраэдра вычислить координаты вершин куба. При обнаружении столкновения, точка контакта \(\vec{p}\) (которая теперь расположена на кубе) обрабатывается также, как и выше. Аналогично вычисляются и обновленные значения координат частиц. Для ускорения расчетов можно заранее вычислить коэффициенты \(c_1\) --\(c_4\) для всех вершин куба. Если \(\vec{p}\) окажется вершиной, то значения \(c_1\) --\(c_4\) могут быть найдены и использованы непосредственно. В противном случае, \(\vec{p}\) лежит внутри треугольника или на одной из его сторон, и значения \(c_1\) --\(c_4\) можно получить из предварительно вычисленных значений вершин треугольника при помощи интерполяции.

Как правило, для обработки столкновений достаточно 3--4 итераций. Если релаксацию остановить слишком рано, то тела не будут вести себя как абсолютно твердые. Но это даже хорошо, ведь абсолютно твердых тел в природе не существует. Кроме того, это делает систему более устойчивой.

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

По тому же принципу, что и тетраэдр, можно задать другую подобную конфигурацию частиц и связей, расположив частицы в точках с координатами \((0,0,0)\) , \((1,0,0)\) , \((0,1,0)\) и \((0,0,1)\) . Пусть \(\vec{a}\) , \(\vec{b}\) , и \(\vec{c}\) - векторы, направленные из частицы 1 к частицами 2, 3 и 4, соответственно. Ограничим положения частиц, требованием, чтобы векторы \(\vec{a}\) , \(\vec{b}\) , и \(\vec{c}\) имели единичную длину, и угол между каждой из трех пар векторов был равен \(90^\circ\) (соответствующие скалярные произведения должны быть равны нулю). Заметим, что это снова, как и в случае с тетраэдром, даст 4 частицы и 6 связей.

Сочлененные тела

Теперь мы можем соединять несколько твердых тел при помощи шарниров (цилиндрических, сферических и т. п.). Предположив, что два тела имеют одну общую частицу, мы получим сферический шарнир (pin joint), а если общими являются две частицы, то получим цилиндрический шарнир (hinge) (рис.7). Таким же образом можно связать два тела при помощью стержня или любого другого вида связи - надо только не забыть добавить код для обработки нового вида связи в цикл релаксации.

Такой подход позволяет построить полную модель сочлененного человеческого тела. Реалистичность увеличится, если дополнительно реализовать ограничения на угловые перемещения в шарнирах. Существует несколько способов реализации таких ограничений. Простейший способ предполагает использование ограничения типа стержня, которые срабатывает только тогда, когда расстояние между двумя частицами станет ниже некоторого порогового значения (в данном случае мы имеем дело с односторонней связь вида \(|\vec{x}_2 - \vec{x}_1| > 100\) ). Как следствие этого, обе частицы никогда не смогут слишком приблизиться друг к другу (рис.8).

Другой метод создания ограничений на угловые перемещения требует соблюдения следующего условия для скалярного произведения

$$ (\vec{x}_2 - \vec{x}_0)\cdot (\vec{x}_1 - \vec{x}_0) < \alpha . $$

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

Поделитесь с друзьями или сохраните для себя:

Загрузка...