Вычисление скорости движущегося объекта на основе его расстояния до цели

Я пишу симуляцию, в которой объект движется в 2D-мире к целевой позиции, сохраненной как вектор target(x,y). Положение объекта также сохраняется как вектор положения pos(x,y). Объект содержит еще два вектора, желаемую скорость движения dv(x,y), а также текущую скорость движения cv(x,y). В начале симуляции оба этих вектора скорости являются начальными, т.е. установлены на (0,0).

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

dv.set(target).sub(pos).normalize()
dv.scale(speed)

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

Затем в каждом кадре (этап обновления) текущая скорость cv устанавливается на основе желаемой скорости dv и значения ускорения acc. Это делается путем простого вычисления разницы между cv и dv и фиксации этой разницы до acc. Таким образом, объект начинает двигаться медленно и постепенно ускоряется, чтобы в конечном итоге достичь полной скорости.

Пока это работает нормально. Теперь я хочу использовать acc и для замедления. Когда расстояние между pos и target достигает определенного значения, желаемая скорость dv должна быть установлена ​​на (0,0), чтобы объект постепенно замедлялся до полной остановки в заданном положении.

Мой вопрос: как я могу рассчитать, на каком расстоянии мне нужно установить dv на (0,0) (т.е. сказать системе остановить движение), чтобы объект правильно замедлился, чтобы остановиться точно в целевом положении?


person Matthias    schedule 06.01.2015    source источник


Ответы (2)


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

vf2 = vi2 + 2 * a * d

  • vf — ваша конечная скорость или 0 (скорость, с которой вы хотите двигаться)

  • vi — заданная начальная скорость (скорость, с которой движется ваш объект в данный момент).

  • а ускорение

  • д - расстояние.

Решите для д:

  • 2*a*d = vf2 - vi2

  • 2*a*d = 0 - vi2

предположим, что ускорение отрицательно, поэтому умножьте обе части на -1

  • 2*|a|*d = vi2

|а| это абсолютное значение вашего ускорения (замедление в вашем случае)

  • d = vi2 / (2*|a|)
person AndyG    schedule 06.01.2015
comment
Это не работает для меня. Я использую vi=10 и a=0.5, т.е. движение увеличивается с шагом 0,5, пока не будет достигнута полная скорость. С этими значениями ваша последняя строка дает мне расстояние d=100.0, тогда как из проб и ошибок я знаю, что оно должно быть немного меньше 1,0. - person Matthias; 06.01.2015
comment
Я добавляю a к вектору скорости на каждом временном шаге. Итак, я предполагаю, что ваше уравнение основано на a, растянутом на целую секунду? Думаю, имеет смысл. Есть ли простое преобразование вашего решения в мою ситуацию? - person Matthias; 06.01.2015
comment
@ Маттиас, если ваше ускорение составляет 0,5 м / с ^ 2, а ваш временной шаг равен 0,5, вы будете применять только около 0,25 от этого на каждом временном шаге. Просто разделите свое ускорение на величину вашего временного шага. На самом деле ваша скорость должна быть масштабирована аналогичным образом, чтобы оставаться независимой от временного шага (например, если вы по какой-то причине хотите изменить свой временной шаг на 10, вы не хотите волшебным образом увидеть 10-кратное увеличение скорости). - person AndyG; 06.01.2015
comment
Это имеет смысл, спасибо. Итак, я уже масштабировал скорость по временному шагу (что составляет долю секунды, то есть delta с последнего временного шага). Теперь я также масштабирую ускорение на delta. Применяя ваше уравнение, замедление теперь работает намного лучше. Однако объект останавливается слишком рано, он никогда полностью не достигает цели. Я предполагаю, что ваше уравнение верно, и мне нужно искать проблему где-то еще... - person Matthias; 06.01.2015
comment
Большое спасибо, теперь все работает хорошо. Ответ принят :-) - person Matthias; 06.01.2015

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

  • ускорение 5
  • максимальная скорость 13
  • объект начинает замедляться, как только достигает максимальной скорости

Вот как будет развиваться симуляция дискретного времени

first tick
  old speed = 0
  new speed = 5
  distance  = 5

second tick
  old speed = 5
  new speed = 10
  distance  = 15

third tick
  old speed = 10
  new speed = 13
  distance  = 28  <-- total distance while accelerating

fourth tick
  old speed = 13
  distance  = 41
  new speed = 10  <-- not 8!!!

fifth tick
  old speed = 10
  distance  = 51
  new speed =  5

sixth tick
  old speed =  5
  distance  = 56  <-- Yay, twice the distance, we have symmetry
  new speed =  0

Здесь есть два ключевых момента

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

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

if ( old_speed % acceleration != 0 )                   // if speed is not a multiple of acceleration
   new_speed = old_speed - old_speed % acceleration;   //   reduce speed to a multiple of acceleration
else                                                   // otherwise
   new_speed = old_speed - acceleration;               //   reduce speed by acceleration

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

distance = acceleration * (1+2+3+ ... +N) + fudge_factor

где

  • N top_speed / acceleration усекается до целого числа, например. 13/5 ==> 2
  • fudge_factor равно 0, если максимальная скорость кратна ускорению, или top_speed в противном случае.

Расчет можно упростить, заметив, что

1+2+3+ ... +N = N * (N+1) / 2

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

int top_speed = 13;
int acceleration = 5;

int N = top_speed / acceleration;     // Note: in C, integer division truncates

int fudge = 0;
if ( top_speed % acceleration != 0 )
    fudge = top_speed;

int distance = acceleration * (N * (N+1)) / 2 + fudge;
person user3386109    schedule 06.01.2015
comment
Кажется, это не работает для меня. Я использую top_speed=10.0 и acceleration=0.5, и с этими значениями ваша последняя строка acceleration * (N * (N+1)) / 2 + fudge дает мне distance=105.0, тогда как из проб и ошибок я знаю, что это должно быть немного меньше 1,0 - person Matthias; 06.01.2015