Программирование игр, создание игрового движка, OpenGL, DirectX, физика, форум
GameDev.ru / Программирование / Статьи / Пишем симулятор гонок

Пишем симулятор гонок

Автор:

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

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

Car sim | Пишем симулятор гонок

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

Основные части, которые необходимо рассмотреть при создании мат. модели автомобиля:

Часть 1: Крутящий момент
  1.1 Двигатель автомобиля
  1.2 КПП
  1.3 Дифференциал
Часть 2: Шасси
  2.1 Амортизаторы
  2.2 Распределение массы
  2.3 Кинематика подвески
Часть 3: Сцепление шин с дорогой
  3.1 Вращательное и поступательное движения колёс
  3.2 Тормозные механизмы
  3.3 Трение шин
  3.4 Сход/развал
  3.5 Давление в шинах, уводы и подламывания

Часть 1: Крутящий момент

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

1.1 Двигатель автомобиля

Engine | Пишем симулятор гонок

Как уже было сказано — двигатель это источник крутящего момента. Для моделирования работы двигателя достаточно задать следующие характеристики:
1) зависимость крутящего момента от текущей скорости вращения коленвала;
2) инертность вращающихся элементов (совокупность маховика, коленвала и проч.)
3) тип расположения (продольно/поперечно);
при рассматривании двигателя внутри авто нам понадобится ещё одна характеристика:
4) масса двигателя.

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

EngineGraph1 | Пишем симулятор гонок

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

    Power[RPM] = Torque[RPM] * RPM / 7000;

где RPM — текущие «обороты двигателя». Как видно, при 7000 об/мин мощность равна крутящему моменту, в этой точке графики всегда пересекаются.

Крутящий момент, развиваемый двигателем, равен:

    float torq = Torque[RPM] * Throttle;
где Throttle — значение от 0 до 1 — дроссель. Чем сильнее жмём на педаль, тем больший процент максимального крутящего момента развивается двигателем.

Куда направлен этот крутящий момент? Это зависит от сцепления, которое мы рассмотрим позже. А сейчас этот момент просто раскручивает наш мотор:

    RPM += torq / Inertia;
где Inertia — инертность вращающихся элементов.

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

    RPM += torq / Inertia - pow(1.0f - Throttle, 2) * BackTorque;
где pow() — функция возведения в степень, backTorq — константа, определяющая величину обратного момента.

Теперь ещё раз дополним этот участок — здесь заранее необходимо учесть фактор сцепления.

    float additionRPM = torq / Inertia - pow(1.0f - Throttle, 2) * BackTorque;
    RPM += additionRPM * (1.0f - Clutch);
где Clutch — значение от 0 до 1 — педаль сцепления. Часть, равная (1.0f – Clutch) уйдёт на раскрутку мотора, а часть, равная Clutch уйдёт в коробку передач, которую мы рассмотрим позже.

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

Приблизительная структура нашего мотора на языке C++ будет выглядеть так:

struct Engine
{
    // базовые величины
    float* Torque;
    float* Power;
    float Inertia, Mass, BackTorque;
    char Direction;

    float IdleRPM; // обороты холостого хода

    // динамические величины
    float RPM;

    // функция обновления
    void Progress(float Throttle, float Clutch)
    {
        if (RPM < IdleRPM && Throttle < 0.3f)
            Throttle += 0.1f;

        float torq = Torque[ (int)RPM ] * Throttle;

        float additionRPM = torq / Inertia - pow(1.0f - Throttle, 2) * BackTorque;
        RPM += additionRPM * (1.0f - Clutch);
    }
};

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

1.2 КПП

GearBox parts | Пишем симулятор гонок

В коробке переключения передач происходит две вещи — преобразование и передача крутящего момента. Для моделирования работы КПП достаточно задать следующие характеристики:
1) передаточные отношения всех передач;
2) передаточное отношение "главной пары";
3) КПД коробки передач.

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

Если вы взглянете с умным видом на график мощности, то поймёте, что он достигает маскимальных значений только в некотором диапазоне (особенно у гоночных машин он становится совсем узким). Для этого и нужны все передачи в КПП — чтобы держать мотор в диапазоне максимальной мощности.

Посмотрим, что же происходит с крутящим моментом, переданным в коробку передач:

    float toWheelTorq = torq * Efficiency / (TopGear * Gear[CurrentGear]);
где Efficiency — это КПД нашей коробки передач (в среднем равно 0.9, у заднеприводных меньше, у полноприводных ещё меньше, у «УАЗика» может вообще где-то 0.6), TopGear — коэффициент редукции главной парой, Gear[] — массив коэффициентов редукции передачами, CurrentGear — номер включенной передачи. Таким образом мы подсчитали крутящий момент, который передаётся колёсам.

Далее для примера привожу коэффициенты в КПП для «двенашки»:

    TopGear = 3.9f;

    Gear[0] = -4.0f; // задняя
    Gear[1] = 0.0f; // нейтраль
    Gear[2] = 3.64f; // первая
    Gear[3] = 1.95f; // вторая
    Gear[4] = 1.36f; // третья
    Gear[5] = 0.94f; // четвёртая
    Gear[6] = 0.78f; // пятая

КПП также действует и в обратном направлении — колёса раскручивают мотор. Это проще всего описать несколькими уравнений:

     // вращение колёс "в моторном расчёте"
     float wheelRPM = FastestWheelRotation * TopGear * Gear[CurrentGear];

     float baseTorque = (wheelRPM - RPM) * Clutch / (WheelInertia + EngineInertia);

     float toEngine = WheelInertia * baseTorque;
     float toWheels = EngineInertia * baseTorque;

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

1.3 Дифференциал

Diff | Пишем симулятор гонок

Это устройство позволяет вращаться колёсам с разными скоростями и при этом передавать на эти колёса крутящий момент.

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

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

Простым способом смоделировать блокирующийся дифференциал явлется выравниваение скоростей вращения колёс, пример для двух колёс:

    float wheelDiff = Wh[0].Rotation - Wh[1].Rotation;

    Wh[0].Rotation -= wheelDiff * 0.5f * DiffForce * Throttle * Clutch;
    Wh[1].Rotation += wheelDiff * 0.5f * DiffForce * Throttle * Clutch;

где Wh[].Rotation — скорость вращения определённого колеса, DiffForce — значение от 0 до 1 — сила блокировки дифференциала. В этой формуле также присутсвует множитель Throttle * Clutch, благодаря чему эффект блокировки возникает только при наличии крутящего момента. Если этот множитель убрать, то блокировка на заданную величину будет происходить постоянно.

Часть 2: Шасси

car box | Пишем симулятор гонок

Теперь рассмотрим сам автомобиль. Несущий каркас, на котором держится мотор и всё остальное, взаимодействует с землёй посредством шасси.

Здесь стоит сказать о модели авто, которую мы составляем в стороннем физическом движке, моделирующем поведения твёрдых тел. На рисунке выше представлен пример — колёса это цилиндры, кузов это бокс, соединены они посредством соединения типа слайдер.

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

2.1 Амортизаторы

shock | Пишем симулятор гонок

Амортизаторы состоят из двух частей — демпфирующей и пружинящей — стойка и пружина. Стойка гасит колебания, а пружина плавно передаёт нагрузку.

Как работает пружина, думаю, никому объяснять не надо:

    float force = (CurrentLength - RestLength) * SpringForce;
где CurrentLength — текущая длина пружины, RestLength — базовая длина пружины, SpringForce — сила упругости пружины.

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

Теперь демпфер:

    float dampForce = ShiftSpeed * Damping;
где ShiftSpeed — скорость сближения/отдаления колеса от кузова, величину эту получаем из физического движка (из соединения слайдер), Damping — коэффициент демпфирования. По сути это добавка к результирующей силе, которую мы считали чуть выше.

2.2 Распределение массы

car_sim2 | Пишем симулятор гонок

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

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

Учтите также, что из-за расположения мотора не по середине мы имеем не равномерное распределение массы в состоянии покоя (на скриншоте выше машина затормаживает, не беспокойтесь). Если мотор спереди (чаще всего, но не всегда), то нагрузка на переднюю ось будет больше. У некоторых машин распределено 65% на переднюю ось и 35% на заднюю. У хороших машин, даже если мотор спереди, нагрузка может быть 50/50, но в большинстве случаев где-то 60/40.

2.3 Кинематика подвески

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

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

kinematic | Пишем симулятор гонок

Это даёт ощутимый эффект в управляемости.

susp kinematic | Пишем симулятор гонок

Часть 3: Сцепление шин с дорогой

3.1 Вращательное и поступательное движения колёс

wheel | Пишем симулятор гонок

Отчего вращаются колёса? Ну для начала от нашего мотора. Мы посчитали крутящий момент, который на них передаётся, осталось только его приложить:

    Rotation += Torque / Inerita;
где Torque — приложенный крутящий момент, Inertia — инерция колеса.

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

3.2 Тормозные механизмы

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

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

    Rotation -= BrakesForce * BrakesFrontPart * BrakesState / Inertia;
где BrakesForce — сила тормозов, BrakesFrontPart — процент усилия для передней оси (для задней оси будет 1.0f – BrakesFrontPart, если кто не понял), BrakesState — процент нажатия тормоза, Inertia — инерция колеса.

Ручной тормоз устроен аналогично, только действует он исключительно на задние колёса:

    Rotation -= HandBrakeForce * HandBrakeState / Inertia;
где HandBrakeForce — сила ручного тормоза, HandBrakeState — процент нажатия тормоза, Inertia — инерция колеса.

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

Для общего развития — ещё есть понятие «снос» — это когда передняя ось скользит, а задняя нет, то есть обратная ситуация заносу.

3.3 Трение шин

Самая важная часть. Я предпочитаю рассматривать продольное и поперечное трение в отдельности, хотя можно работать и с векторами. Просто плоские графики лучше воспринимаются.

Итак, в зависимости от скорости скольжения двух поверхностей относительно друг друга, сила трения между ними изменяется. Для колёс этот график может выглядеть так:

tire fric | Пишем симулятор гонок

Как видим, чем сильнее скольжение, тем меньше сила. Это так для асфальта, но например не так для гравия — этот график может быть сильно изменён, всё зависит от покрытия и типа шин. С этим приходится экспериментировать.

Рассмотрим сначала поперечную силу — с ней всё просто. У нас есть скорость поперечного движения колеса (из физеского движка) — это и есть скорость скольжения. При помощи графика мы получаем поперечную силу, действующую на колесо:

    float lateralForce = TireFriction(LateralSpeed) * ShiftForce * Friction;
где TireFriction() — наш график трения, ShiftForce — вертикальная нагрузка на колесе, Friction — коэффициент трения.
Полученную величину передаём физическому движку, пусть приложит её к колесу в поперечном направлении.

Теперь рассмотрим продольную силу. Тут всё немного сложнее, так как необходимо учесть вращение колеса.
У нас есть продольная и вращательная скорость, найдём скольжение:

    float longSlip = LongSpeed - Rotation * 2.0f * Pi * Radius;
где LongSpeed — продольная скорость колеса, Rotation — вращение колеса, Radius — радиус колеса.

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

    float longForce = TireFriction(longSlip) * ShiftForce * Friction;

Две полученые величины — продольная и поперечная сила не могут быть максимальными одновременно, тут необходимо действует правило «окружность трения», известное среди профессиональных гонщиков:

firction circle | Пишем симулятор гонок

В некоторых случаях это может быть эллипс.

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

3.4 Сход/развал

wheel angles | Пишем симулятор гонок

Со сходом всё просто — задаём углы при расположении тел в физическом движке. Эффект проявится сам. Если Вы знакомы с такими понятиями и в жизни их ощущали, то сразу заметите, в противном случае можете не моделировать сход.

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

wa2 | Пишем симулятор гонок

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

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

3.5 Давление в шинах, уводы и подламывания

car_sim1 | Пишем симулятор гонок

В жизни шины мягкие. В гонках это редко, но тоже встречается.

На самом деле смоделировать это очень просто — представим шину в виде пружины, чем больше она растянута, тем больше силы она передаёт. Чем выше давление, тем жестче пружина. Таким образом достигается эффект подламывания шины, благодаря которому создаётся невероятная реалистичность — каждый гонщик хорошо знает, что от давления в шинах, от жёсткости их боковины и их профиля сильно зависит поведение машины на дороге.

Soft tyres | Пишем симулятор гонок

Сила трения передаётся мнимому (дополнительному телу), возникает разница в поперечном положении двух тел.

Далее всё просто: находим силу, действующую на основное тело, используя либо линейное уравнение F = kx , либо опять же строим нужный график для пущей реалистичности. Требования к зависимости следующие: сила стремится к нулю, если x стремится к нулю; сила стремится к бесконечности при x большем, чем ширина шины. Конечно на практике бесконечность не применима, поэтому результирующая сила ограничивается сверху силой трения.

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

car sim | Пишем симулятор гонок

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

Дополнительно выкладываю видео, качество ужасное, но смотреть можно. Если постараться, то можно углядеть мягкие шины :)

17 июля 2010

#физика, #racing, #автомобиль, #симулятор


Обновление: 26 мая 2013

Цена на металлопрокат в москве. , Играйте онлайн в гоночки на сайте http://gonki-games.ru про машинки для мальчиков
2001—2017 © GameDev.ru — Разработка игр