代码之家  ›  专栏  ›  技术社区  ›  salocinx

如何连接点和吸收动量?

  •  1
  • salocinx  · 技术社区  · 8 年前

    我目前正在使用一种显示激光设备,比如 this 是的。设备接收二维点列表,然后显示该列表。内部有一个 galvanometer 控制反射镜投射激光点的装置。

    假设我想显示5个激光点(A、B、C、D、E)。由于激光设备不喜欢在短时间间隔内长距离移动,因此必须添加中间点,称为消隐点(激光沿着这些消隐点移动时关闭)。这个程序的目的是为了不给电流计施加太大的压力。

    我正在用一个简单的 Nearest Neighbor algorithm ,以直线空白结束(下图中的红色虚线)。

    enter image description here

    我用这个优化已经取得了相当好的效果。但我想更进一步。电流计在运动时有一定的物理动量。当进行急转弯时,例如从C->D和D->E移动时,会对激光设备产生应力。

    所以我想通过引入弯曲的消隐线而不是直的消隐线来吸收一些物理动量(上图“解决方案?”)是的。

    知道怎么做到吗?

    指出一些算法资源和/或一些伪代码或c会有帮助。谢谢您!

    2 回复  |  直到 8 年前
        1
  •  3
  •   Matt Timmermans    8 年前

    正如其他人提到的,您需要使用某种三次样条插值来实现这一点。

    一旦你知道访问每个关键点的时间和每个点的速度,你就可以计算一个分段的三次hermite样条曲线,它以选定的速度通过关键点。见: https://en.wikipedia.org/wiki/Cubic_Hermite_spline

    由于对速度没有任何特殊要求,您可能希望使用经典的三次样条曲线(是的,这些东西的名称不明确): http://mathworld.wolfram.com/CubicSpline.html 这种样条曲线确定速度,以确保一阶导数(速度)和二阶导数(加速度)沿整个路径平滑变化。

    由于您还没有对每个关键点到达的确切时间有任何特殊要求,您可能需要设置整个路径的最大时间,然后选择关键点的时间,以最小化最大加速度或类似的情况。我没有一个简单的方法来做到这一点。我要尝试的是:

    首先,使关键点之间的时间与这些点之间的距离成比例。然后,应用几轮:

    1. 调整每段时间,使关键点的切向加速度为0。
    2. 重新计算样条曲线

    不过,如果没有这些优化循环,您可能会非常高兴——最初的猜测不会太糟。

        2
  •  2
  •   Tommaso Fontana    8 年前

    我认为你所面对的是 Traveling-Salesman-Problem(TSP) ( here the slide of a Phd course which talk about how to try to solve it )使激光上的应力最小化的路径是使移动激光所需的力和力的变化最小化的路径,因为这是曲率最小的路径,所以我认为最好的方法是用一个圆的弧线将3对点之间的路径圆角。

    关于如何计算通过3个点的圆的参数的例子可以找到 here

    我不精通C语言,所以我将在Python中添加一个实现,希望您也觉得它很有用。

    其思想是,对于点a,b,c的每三个点,我都会找到经过这三个点的圆的弧,这个弧就是连接b和c的路径。

    我还没来得及测试这个,所以可能有一些错误的迹象。

    # Initial points 
    points = [(1,1),(2,3),(5,3),(-4.1),(12,3)]
    #List of point in the order find by the solution of the TSP
    spl = tsp_solve(points) # generic function to solve the TSP
    
    # Append the first two point of the list so that I can iterate over the list
    # and parse every triplet of points in the same way.
    spl = spl + spl[:2]
    
    # The list where will be added every path that connect the points
    paths = []
    
    # For each tirplets of sequential points
    for A,B,C in zip(spl[:-2],spl[1:-1],spl[2:]):
        # Calculate the angular coefficent of the two line that pass on A,B and B,C
        coeff_ab = (B[1] - A[1]) / (B[0] - A[0])
        coeff_bc = (C[1] - B[1]) / (C[0] - B[0])
        # If the two line have the same coeff then all the 3 point are on the same line
        # and therfore the best path is that line.
        if(coeff_ab == coeff_bc):
            offset_y = A[1] - coeff_ab * A[0]   
            delta_x = C[0] - B[0]            
            paths.append({"type":"Line","coeff":coeff_ab,"offset_y":offset_y,"deta_x":delta_x})
            continue
        # Calculate the x of the center of the circle
        center_x  = coeff_ab *coeff_bc *(C[0]-A[0])
        center_x += coeff_ab *(B[0]+C[0]) 
        center_x -= coeff_bc *(A[0]+B[0])
        center_x /= 2*(coeff_ab - coeff_bc)
        # Calculate the y of the center of the circle
        center_y  = (A[1]+B[1)/2
        center_y -= (center_x - (A[0] + B[0])/2)
        center_y /= coeff_bc
    
        radius = sqrt(center_x**2 + center_y**2)
    
        paths.append({"type":"Circle","Radius":radius,"center_x":center_x,"center_y":center_y})
    
    # Function To Calculate the X and Y of the lines and circles.
    
    def calculate_circle_x(circle,time):
        """Function that return the x of a circle at a given time"""
        time = time + circle["time_off"]
        return circle["radius"] * cos(2*pi*time) + circle["center_x"]
    def calculate_circle_y(circle,time):
        """Function that return the y of a circle at a given time"""
        time = time + circle["time_off"]
        return circle["radius"] * sin(2*pi*time) + circle["center_y"]
    
    def calculate_line_x(line,time):
        """Function that return the x of a line at a given time"""
        time = (line['delta_x']*time) + line["time_off"]
        return time
    def calculate_line_y(line,time):
        """Function that return the y of a line at a given time"""
        time = (line['delta_x']*time) + line["time_off"]
        return time * line["coeff"] + line['offset_y']
    
    def calculate_x(obj,time):
        """Function that return the x of whatever it's passed"""
        if(obj['type'] == 'Circle'):
            return calculate_circle_x(obj,time)
        else:
            return calculate_line_x(obj,time)
    
    def calculate_y(obj,time):
        """Function that return the y of whatever it's passed"""
        if(obj['type'] == 'Circle'):
            return calculate_circle_y(obj,time)
        else:
            return calculate_line_y(obj,time)
    
    # Calculate some sample of the global path to plot it or do whatever with it.
    number_of_sample = 100000
    path_points = []
    number_of_paths = len(paths)
    
    # Calculate some time equidistant point's sample
    for i in range(number_of_sample):
        # Calculate the global time
        global_time = i*number_of_paths/number_of_sample
        # Calculate in which path the point it is
        path_number = int(global_time)
        # Calculate which time of the path it is
        local_time  = global_time - path_number
        path = paths[path_number]
        # Calculate the sampled point
        new_point = (calculate_x(path,local_time),calculate_y(path,local_time))
        # Add the sampled point to the path_points list
        path_points.append(new_point)
    
    # Print the result of the path point sampled.
    print(path_points)
    

    现在你有了点,或者至少有了一个关于如何计算点的例子,你可以把它转换成c。我试着对它做了很多评论,这样即使你不知道python,你也可以理解它。