我目前正在使用this之类的表演激光设备。设备接收2D点列表,然后显示该列表。内部有一个galvanometer,用于控制反射镜以投射激光点。
假设我要显示5个激光点(A,B,C,D,E)。由于激光设备不喜欢在短时间内移动很长的距离,因此必须添加中间点,称为消隐点(激光沿着这些消隐点移动时处于关闭状态)。此过程的目的是实现不对振镜施加过多压力的目的。
我目前正在使用简单的Nearest Neighbor algorithm计算5个点之间的“最短路径”,最后以直线的空白线(下图中的红色虚线)结束。
通过这种优化,我已经获得了相当不错的结果。但我想更进一步。检流计在移动时具有一定的物理动量。当急转弯时,例如从C-> D和D-> E传播,确实会给激光设备造成压力。
因此,我正在考虑通过引入弯曲的消隐线而不是直线的消隐线来吸收一些物理动量(请参见上图“解决方案?”中的最后一个图像)。
任何想法如何实现?
指向一些算法资源和/或一些伪代码或C#将很有帮助。谢谢!
答案 0 :(得分:3)
正如其他人提到的那样,您想为此使用某种三次样条插值。
一旦知道了每个关键点的访问时间和每个点的速度,就可以计算出以选定速度通过关键点的分段三次Hermite样条曲线。参见:https://en.wikipedia.org/wiki/Cubic_Hermite_spline
由于您对速度没有任何特殊要求,因此您可能希望使用经典的三次样条(是,这些东西的名称不明确):http://mathworld.wolfram.com/CubicSpline.html这种样条形式决定了要确保的速度一阶导数(速度)和二阶导数(加速度)在整个路径上都是平滑变化的。
由于您对到达每个关键点的确切时间也没有任何特殊要求,因此您可能希望设置整个路径的最大时间,然后选择关键点的时间以最大程度地减少最大加速度或类似的东西。我没有一个真正简单的方法来做到这一点。我会尝试的是:
最初,使关键点之间的时间与这些点之间的距离成比例。然后,应用几轮:
但是,如果没有这些优化回合,您可能会非常高兴-最初的猜测不会太糟糕。
答案 1 :(得分:2)
我认为您要处理的是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也可以理解它。