最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

python - Fixing fluctuations, precision errors and more in velocity control algorithm. Is my approach correct? - Stack Overflow

programmeradmin0浏览0评论

Problem:

I want my "Follow Coordinates System (FCS)" to reach the position of a "Set Coordinates System (SCS)" while maintaining a trapezoidal velocity profile using given parameters like limited velocity and acceleration. However, I am encountering issues such as fluctuations in the velocity and missing the target position, possibly due to precision errors. Despite testing various solutions, I have not been able to achieve consistently positive results.

System Behavior:

  • The starting positions for FCS and SCS are random. Once FCS reaches the target position of SCS (linear_distance < 1e-3), the SCS is moved randomly to a new position... For now, but in the future, I want SCS to move randomly and unpredictably at any moment, without waiting for the FCS to reach it.
  • Each step begins by calculating the linear velocity of the FCS, and then the velocity is proportionally divided among the X, Y, and Z axes based on the normalized direction vector from FCS to SCS.
  • Acceleration is calculated from the velocity, and the position is updated based on velocity too. Starting my calculations from acceleration and going from acceleration to velocity and then from velocity to position became too complex and difficult to debug, but I'm willing to give it another chance.

My failing algorithm (Python):

Part 1. Linear velocity calculations:

for step in range(cycles):

    axis_distance = np.array(current_scs[:3]) - np.array(current_fcs[:3])
    linear_distance = np.linalg.norm(axis_distance)

    breaking_distance = (linear_velocity[-1]**2) / (2 * max_deceleration)
    
    # Acceleration or constant velocity phase
    if linear_distance > breaking_distance:
        if np.abs(max_velocity - linear_velocity[-1]) > max_acceleration * cycle_time: # Preventing overshooting max_velocity
            linear_velocity.append(linear_velocity[-1] + max_acceleration * cycle_time)
        else:
            linear_velocity.append(max_velocity)  
    # Deceleration phase
    else:
        if linear_velocity[-1] > max_deceleration * cycle_time: # Preventing overshooting 0
            linear_velocity.append(linear_velocity[-1] - max_deceleration * cycle_time)
        else:
            linear_velocity.append(0)

    linear_acceleration.append((linear_velocity[-1] - linear_velocity[-2]) / cycle_time)

Part 2. Dividing linear velocity among the XYZ:

    for i in range(3):

        factor = axis_distance[i] / linear_distance if linear_distance != 0 else 0

        new_axis_velocity = linear_velocity[-1] * factor
        
        if velocity[i][-1] < new_axis_velocity:
            velocity[i].append(velocity[i][-1] + np.min([max_acceleration * cycle_time, new_axis_velocity - velocity[i][-1]]))
            #print(f"{step} accelerating at axis {i}")
        elif velocity[i][-1] > new_axis_velocity:
            velocity[i].append(velocity[i][-1] - np.min([max_deceleration * cycle_time, velocity[i][-1] - new_axis_velocity]))
            #print(f"{step} decelerating at axis {i}")
        else:
            velocity[i].append(velocity[i][-1])
            #print(f"{step} target velocity for axis {i} reached")
        
                               
        acceleration[i].append((velocity[i][-1] - velocity[i][-2]) / cycle_time)
        
        current_fcs[i] += velocity[i][-1] * cycle_time

Output:

To track progress, I log the data and display it on graphs. That's why e.g. velocity is array of arrays now. It won't be when I finish. Here's one set of graphs: As you can see FCS trajectory missed SCS at first, but then it hit and hit again it's next positions with slowing down correctly.

SCS reached at 5574 : linear_distance = 0.0008199809854013105, linear_velocity = 2.7999999999649416
SCS reached at 9163 : linear_distance = 0.0008934633980521272, linear_velocity = 0.7999999999478358

Wrong legend: orange here is linear acceleration! And here is linear velocity after dividing to XYZ

Concerns:

I could keep trying to fix it, but I’m not sure if this is the right approach in the first place. I lack a background in control theory and motion planning.

I’m looking for feedback and any advice on addressing the issues I'm facing!

Problem:

I want my "Follow Coordinates System (FCS)" to reach the position of a "Set Coordinates System (SCS)" while maintaining a trapezoidal velocity profile using given parameters like limited velocity and acceleration. However, I am encountering issues such as fluctuations in the velocity and missing the target position, possibly due to precision errors. Despite testing various solutions, I have not been able to achieve consistently positive results.

System Behavior:

  • The starting positions for FCS and SCS are random. Once FCS reaches the target position of SCS (linear_distance < 1e-3), the SCS is moved randomly to a new position... For now, but in the future, I want SCS to move randomly and unpredictably at any moment, without waiting for the FCS to reach it.
  • Each step begins by calculating the linear velocity of the FCS, and then the velocity is proportionally divided among the X, Y, and Z axes based on the normalized direction vector from FCS to SCS.
  • Acceleration is calculated from the velocity, and the position is updated based on velocity too. Starting my calculations from acceleration and going from acceleration to velocity and then from velocity to position became too complex and difficult to debug, but I'm willing to give it another chance.

My failing algorithm (Python):

Part 1. Linear velocity calculations:

for step in range(cycles):

    axis_distance = np.array(current_scs[:3]) - np.array(current_fcs[:3])
    linear_distance = np.linalg.norm(axis_distance)

    breaking_distance = (linear_velocity[-1]**2) / (2 * max_deceleration)
    
    # Acceleration or constant velocity phase
    if linear_distance > breaking_distance:
        if np.abs(max_velocity - linear_velocity[-1]) > max_acceleration * cycle_time: # Preventing overshooting max_velocity
            linear_velocity.append(linear_velocity[-1] + max_acceleration * cycle_time)
        else:
            linear_velocity.append(max_velocity)  
    # Deceleration phase
    else:
        if linear_velocity[-1] > max_deceleration * cycle_time: # Preventing overshooting 0
            linear_velocity.append(linear_velocity[-1] - max_deceleration * cycle_time)
        else:
            linear_velocity.append(0)

    linear_acceleration.append((linear_velocity[-1] - linear_velocity[-2]) / cycle_time)

Part 2. Dividing linear velocity among the XYZ:

    for i in range(3):

        factor = axis_distance[i] / linear_distance if linear_distance != 0 else 0

        new_axis_velocity = linear_velocity[-1] * factor
        
        if velocity[i][-1] < new_axis_velocity:
            velocity[i].append(velocity[i][-1] + np.min([max_acceleration * cycle_time, new_axis_velocity - velocity[i][-1]]))
            #print(f"{step} accelerating at axis {i}")
        elif velocity[i][-1] > new_axis_velocity:
            velocity[i].append(velocity[i][-1] - np.min([max_deceleration * cycle_time, velocity[i][-1] - new_axis_velocity]))
            #print(f"{step} decelerating at axis {i}")
        else:
            velocity[i].append(velocity[i][-1])
            #print(f"{step} target velocity for axis {i} reached")
        
                               
        acceleration[i].append((velocity[i][-1] - velocity[i][-2]) / cycle_time)
        
        current_fcs[i] += velocity[i][-1] * cycle_time

Output:

To track progress, I log the data and display it on graphs. That's why e.g. velocity is array of arrays now. It won't be when I finish. Here's one set of graphs: As you can see FCS trajectory missed SCS at first, but then it hit and hit again it's next positions with slowing down correctly.

SCS reached at 5574 : linear_distance = 0.0008199809854013105, linear_velocity = 2.7999999999649416
SCS reached at 9163 : linear_distance = 0.0008934633980521272, linear_velocity = 0.7999999999478358

Wrong legend: orange here is linear acceleration! And here is linear velocity after dividing to XYZ

Concerns:

I could keep trying to fix it, but I’m not sure if this is the right approach in the first place. I lack a background in control theory and motion planning.

I’m looking for feedback and any advice on addressing the issues I'm facing!

Share Improve this question asked Feb 6 at 14:21 ImmImm 318 bronze badges
Add a comment  | 

1 Answer 1

Reset to default 0

If you want to do this in fixed time steps you need to take the following into account:

  • the velocity can be trapezoidal or, if the maximum speed is not reached given the acceleration a and distance d, triangular with v below v_max. A triangular velocity exactly peaking at v_max is an edge case.
  • v_max will only be exactly reached from a linear slope if that takes an integer number of time steps.
  • by letting the velocity deviate slightly from v_max a fully symmetrical profile can always be calculated ahead of time.
  • it matters whether an odd or an even number of time steps are needed for the velocity profile, at least in the static case where v_0 = v_final = 0.
  • Using the method above, you are guaranteed to exactly hit the target (ignoring numerical accuracy limitations).
  • in discrete space the situation is complicated by the need for a Bresenham type algorithm and the requirement to vary the time steps.

For a moving target some kind of control law is needed. The optimal solution depends on various details of the problem you're trying to solve.

与本文相关的文章

发布评论

评论列表(0)

  1. 暂无评论