Soccer Server 足球服务器(中):模型
Action Models 行为模型
Catch Model 扑球模型
守门员是唯一有能力接球的球员。如果球在可接球区内并且守门员在罚球区内,则守门员可以在 play_on 模式下在任何方向接球。如果守门员在 $\varphi$ 方向接球,则可接球区域是一个在 $\varphi$ 方向上长度为 server::catchable_area_l
和宽度为 server::catchable_area_w
的矩形区域。如果球在该区域内,将有概率 server::catch_probability
接住球(如果在该区域外则不会被接住)。
Catch Model Parameters
Parameter in server.conf and player.conf |
Value |
---|---|
server::catchable_area_l | 2.0 |
server::catchable_area_w | 1.0 |
server::catch_probability | 1.0 |
server::catch_ban_cycle | 5 |
server::goalie_max_moves | 2 |
player::catchable_area_l_stretch_max | 1.3 |
player::catchable_area_l_stretch_min | 1 |
守门员可以使用(catch DIR)
命令来捕捉球。
在服务器版本 14.0.0 中引入了异类守门员。从这个版本开始,在线教练可以更改守门员的球员类型。“catchable_area_l_stretch”变量通过两个新参数添加到每个异构播放器类型:player::catchable_area_l_stretch_min
和 player::catchable_area_l_stretch_max
以下伪代码显示了 catch 模型的权衡规则:
// catchable_area_l_stretch is the heterogeneous parameter, currenlty within [1.0,1.3]
double this_catchable_are_delta = server::catchable_area_l * (catchable_area_l_stretch - 1.0)
double this_catchable_area_l_max = server::catchable_area_l + this_catchable_are_delta
double this_catchable_area_l_min = server::catchable_area_l - this_catchable_are_delta
if (ball_pos is inside the MINIMAL catch area)
{
// the MINIMAL catch area has a length of this_catchable_area_l_min and width server::catchable_area_w goalie
// catches the ball with probability server::catch_probability (which is 1.0 by default)
}
else if (ball_pos is beyond the MAXIMAL (stretched) area)
{
// the MAXIMAL catch area has a length of this_catchable_area_l_max and width server::catchable_area_w goalie
// definitely misses the ball
}
else
{
double ball_relative_x = (ball_pos - goalie_pos).rotate(-(goalie_body + catch_dir)).x
double catch_prob = server::catch_probability
- server::catch_probability
* (ball_relative_x - this_catchable_area_l_min)
/ (this_catchable_area_l_max - this_catchable_area_l_min)
// goalie catches the ball with probability catch_prob it holds: catch_prob is in [0.0,1.0]
}
如果一个 catch 命令不成功,它需要 server::catch_ban_cycle
个模拟周期去冷却。
如果守门员成功接球,比赛模式将在同一周期中首先更改为goaliecatch_ball\[l|r] 和freekick[l|r]。一旦守门员接住球,就可以使用移动命令在禁区内随球移动。守门员在踢球前可以使用移动命令 server::goalie_max_moves
次。其他移动命令没有任何效果,服务器将响应 (error too_many_moves)。请注意,接球、移动、将球踢短距离并立即再次接球移动超过 server::goalie_max_moves 次被视为不绅士的比赛。
Dash Model 冲刺模型
注:从本章开始,power本词由于翻译原因,有可能翻译成“功率”“力量”等多种说法,代指为同一种变量。
dash 命令用于向玩家的身体方向加速。 dash 将加速power作为参数。加速功率的有效范围可以在 server.conf 中配置,各自的参数是 server::min_dash_power
和 server::max_dash_power
。
Dash Model Parameters
Default Parametersserver.conf |
Default Value (Range) | Heterogeneous Player Parametersplayer.conf |
Value |
---|---|---|---|
server::min_dash_power | -100.0 | ||
server::max_dash_power | 100.0 | ||
server::player_decay server::inertia_moment | 0.4 ([0.3, 0.5]) 5.0 ([2.5, 7.5]) |
player::player_decay_delta_min player::player_decay_delta_max player::inertia_moment_delta_factor |
-0.1 0.1 25.0 |
server::player_accel_max | 1.0 | ||
server::player_rand | 0.1 | ||
server::player_speed_max | 1.05 | ||
server:: player_speed_max_min |
0.75 | ||
server::stamina_max | 8000.0 | ||
server::stamina_capacity | 130600.0 | ||
server::stamina_inc_max server::dash_power_rate |
45.0 ([40.2, 52.2]) 0.006 ([0.0048, 0.0068]) |
player::new_dash_power_rate_delta_min player::new_dash_power_rate_delta_max player::new_stamina_inc_max_delta_factor |
-0.0012 0.0008 -6000 |
server::extra_stamina server::effort_init server::effort_min |
50.0 ([50.0, 100.0]) 1.0 ([0.8, 1.0]) 0.6 ([0.4, 0.6]) |
player::extra_stamina_delta_min player::extra_stamina_delta_max player::effort_max_delta_factor player::effort_min_delta_factor |
0.0 50.0 -0.004 -0.004 |
server::effort_dec | 0.3 | ||
server::effort_dec_thr | 0.005 | ||
server::effort_inc | 0.01 | ||
server::effort_inc_thr | 0.6 | ||
server::recover_dec_thr | 0.3 | ||
server::recover_dec | 0.002 | ||
server::recover_init | 1.0 | ||
server::recover_min | 0.5 | ||
server::wind_ang | 0.0 | ||
server::wind_dir | 0.0 | ||
server::wind_force | 0.0 | ||
server::wind_rand | 0.0 |
每个玩家都有一定数量的耐力(stamina),这些耐力将被冲刺命令消耗。在每半场开始时,球员的体力设置为 server::stamina_max
。如果玩家向前加速($power>0$),耐力会因力量而减少。向后加速($power<0$)对玩家来说更昂贵:耐力减少$-2\times power$。如果玩家的耐力低于冲刺所需的power,则power会降低,因此冲刺命令不需要比可用更多的耐力。每次可用功率低于所需power时,都可以使用一些额外的耐力。额外耐力的数量取决于玩家类型和参数 player::extra_stamina_delta_min
和 player::extra_stamina_delta_max
。
注:上一段感觉有点迷,有谁看懂了能在群里解释一下?
降低体力后,服务器会计算冲刺命令的有效冲刺功率(effective dash power)。有效的 dash power edp 取决于 dash_power_rate
和玩家当前的努力。玩家的努力是一个介于 effort_min
和 effort_max
之间的值;它取决于玩家的耐力管理(见下):
$$ edp=effort\cdot dash_power_rate\cdot power
$$ edp 和玩家当前的身体方向被转换为向量并添加到玩家当前的加速度向量 $\vec{a_n}$中(通常之前应该为 0,因为玩家在一个周期中不能多次冲刺,并且玩家不会通过冲刺以外的其他方式加速)。
在从仿真步骤 $n$ 到仿真步骤 $n+1$ 的过渡时,加速度$\vec{a_n}$生效:
- $\vec{a_n}$被归一化为
server::player_accel_max
的最大长度。 - $\vec{a_n}$被添加到当前玩家速度 $\vec{v_n}$。 $\vec{v_n}$将被归一化为
player_speed_max
的最大长度。球员的最大速度是 player.conf 中server::player_speed_max
+player::player_speed_max_delta_min
和server::player_speed_max
+player::player_speed_max_delta_max
之间的值。 - 噪声 $\vec{n}$ 和风 $\vec{w}$ 将被添加到$\vec{v_n}$。噪音和风都可以在 server.conf 中配置。负责风的参数是
server::wind_force
、server::wind_dir
和server::wind_rand
。在当前设置下,模拟足球场上没有风。噪声的负责参数是server::player_rand
。噪声向量的方向和长度都在区间$[-|\vec{v_n}|\cdot player_rand,|\vec{v_n}|\cdot player_rand]$内。 - 球员的新位置 $\vec{p}{n+1}$ 是旧位置 $\vec{p}{n}$ 加上速度矢量 $\vec{v_n}$(即玩家在两个模拟步骤之间的最大距离差是
player_speed_max
)。 player_decay
应用于玩家的速度:$\vec{v}{n+1}=\vec{v}{n}\cdot player_decay$ 。加速 $\vec{a}_{n+1}$ 设置为零。
归一化(normalize):在这里应该是单位化的方法。
Sideward and Omni-Directional Dashes 侧向和全向冲刺
除了 dash(x) 命令的已知参数,其中 $x∈[−100,100]$ 决定冲刺的相对强度(负号表示向后),全向 dash 模型使用 dash 命令的两个参数:dash(power,dir)
其中power决定了冲刺的相对强度,dir代表冲刺加速度相对于玩家身体角度的方向。命令需要发送到 Soccer 服务器的格式是 (dash <power> <dir>)
。如果power是负值,则将使用 dir 的反向角度。实际上,dash的方向由相应的足球服务器参数限制为$dir \in [$server::min_dash_angle
,server::max_dash_angle
$]$
dash 命令的有效功率由 dash 方向的绝对值决定。玩家将始终以全部有效力量 (100%) 与他们当前的身体方向冲刺,另外两个 Soccer Server 参数 server::side_dash_rate
和 server::back_dash_rate
确定执行非直线冲刺时应用的有效功率。
因此,(根据当前 Soccer Server 参数默认值)扫射运动(球员向左/向右 90 度)将以 40% 的有效功率执行,而向后冲刺将以 60% 的功率执行(。对于这四个主要方向之间的值,将应用有效功率的线性插值。以下公式解释了侧向dsah模型背后的数学原理:
$$ dir_rate = \begin{cases} back_dash_rate - ( back_dash_rate - side_dash_rate ) ( 1.0 - ( fabs( dir ) - 90.0 ) / 90.0 ) & \text{if } fabs( dir ) > 90.0 \ side_dash_rate + ( 1.0 - side_dash_rate ) ( 1.0 - fabs( dir ) / 90.0 ) ) & \text{else} \end{cases}
$$
存在服务器参数 server::min_dash_power
,它确定可用于 dash 命令的第一个参数 $power$ 的最高最小值。预计此参数将在未来版本的 Soccer Server 中设置为零,而出于与旧团队二进制文件兼容的原因,目前鼓励将其默认值设置为 -100。
参数 server::dash_angle_step
允许玩家的冲刺方向更加离散。如果此值设置为 90.0 度,则允许玩家冲向四个主要方向,对于 45.0 的设置,我们会到达八个不同的方向。将此参数设置为 1.0,Soccer Server 能够模拟全向运动模型,例如在中型联赛中很常见。
Dash Model Parameters Part II
Default Parametersserver.conf |
Default Value (Range) |
---|---|
server::server::max_dash_angle | 180.0 |
server::server::min_dash_angle | -180.0 |
server::side_dash_rate | 0.4 |
server::back_dash_rate | 0.6 |
server::dash_angle_step | 1 |
Stamina Model 体力/耐力模型
对于一个球员的体力,有三个重要的变量:体力值(the stamina value)、恢复(recovery)和努力(effort)。冲刺时耐力会降低,并且每个周期都会略微补充;恢复负责每个周期恢复多少耐力;努力说明冲刺的效果如何(见上文)。基本上,以下代码块中显示的算法表明,耐力低于某个阈值的每个模拟step,努力或恢复都会减少,直到达到最小值。每走一步,玩家的耐力都会超过某个阈值,努力就会增加到最大值。恢复值仅每半场重置为 1.0,但不会在比赛中增加。
# if stamina is below recovery decrement threshold, recovery is reduced
if stamina <= recover_dec_thr * stamina_max
if recovery > recover_min
recovery = recovery - recover_dec
# if stamina is below effort decrement threshold, effort is reduced
if stamina <= effort_dec_thr * stamina_max
if effort > effort_min
effort = effort - effort_dec
effort = max(effort, effort_min)
# if stamina is above effort increment threshold, effort is increased
if stamina >= effort_inc_thr * stamina_max
if effort < effort_max
effort = effort + effort_inc
effort = min(effort, effort_max)
# recover the stamina a bit
stamina_inc = recovery * stamina_inc_max
stamina = min(stamina + stamina_inc, stamina_max)
在 rcssserver 版本 13 或更高版本中,stamina_capacity 变量已被采用为除了上述三个体力变量之外的玩家体力模型之一。stamina_capacity 定义为每个玩家体力的最大恢复能力。当玩家在游戏中恢复体力时,也会从一个人的 stamina_capacity 中消耗相同数量的体力。stamina_capacity 定义为每个玩家体力的最大恢复能力。当玩家在游戏中恢复体力时,也会从一个人的 stamina_capacity 中消耗相同数量的体力。更新的算法显示在以下代码块中。 stamina_inc 可以从前面的代码块中获得。
# stamina_inc is restricted by the residual capacity
if stamina_capacity >= 0.0
if stamina_inc > stamina_capacity
stamina_inc = stamina_capacity
stamina = min(stamina + stamina_inc, stamina_max)
# stamina capacity is reduced as the same amount as stamina_inc
if stamina_capacity >= 0.0
stamina_capacity = max(0.0, stamina_capacity - stamina_inc)
stamina_capacity 在正常半场以及其他与耐力相关的变量开始后重置为初始值。然而,stamina_capacity 在加时赛的半场和点球大战之前永远不会恢复。stamina_capacity 在参数上被定义为server::stamina_capacity
(自 rcsserver 版本 16.0.0 起,stamina_capacity 的默认值为 130600)。如果 server::stamina_capacity 设置为负值,则每个玩家都有无限的耐力容量。此设置使包含 stamina_capacity 的 stamina-model 与 rcssserver 版本 13 之前的 stamina 模型完全相同。stamina_capacity 信息作为以下 sense_body 消息接收:
(stamina <STAMINA> <EFFORT> <CAPACITY>)
Kick Model 踢球模型
kick 命令有两个参数,玩家客户端想要使用的踢力(在 server::minpower
和 server::maxpower
之间)和玩家踢球的角度。角度以度为单位,并且必须介于 server::minmoment
和 server::maxmoment
之间(有关当前参数值,请参见表)。
一旦踢球命令到达服务器,如果球对球员来说是可以踢的并且球员没有被标记为越位,则踢球将被执行。如果球员和球之间的距离在 0 和 kickable_margin
之间,那么球对球员来说是可踢的。异类(Heterogeneous)玩家可以有不同的可踢边际。对于本节中距离的计算,重要的是要知道,如果我们谈论球员和球之间的距离,我们谈论的是球员和球的外形之间的最小距离。所以这部分的距离是两个物体中心之间的距离减去球的半径再减去球员的半径。
首先要计算踢腿的有效踢腿功率 ep:
$$ {\mathrm ep} = {\mathrm kick power} \cdot {\mathrm kick_power_rate}
$$
如果球不在球员的正前方,有效的踢球力量将根据球相对于球员的位置而减少一定的量。角度和距离都很重要。
如果球的相对角度为$0^\circ$。球员客户端的身体方向 - 即球在球员面前 - 有效力量将保持不变。角度越大,有效功率降低的越多。最坏的情况是如果球在球员身后(角度 $180^\circ$):有效功率降低25%。
有效踢球力量的第二个重要变量是球到球员的距离:很明显 - 如果踢球 - 球和球员之间的距离在 0 和球员的可踢边距之间。如果距离为0,则有效踢力不会再次降低。球离球员客户端越远,有效踢球力量就会降低得越多。如果球距离是球员的可踢边距,则有效踢球力量将减少原来踢球力量的25%。踢球的最坏情况是,如果一名球员在自己身后踢了一个远处的球:将使用 50% 的踢球力量。对于有效踢力,我们得到以下公式(dir diff表示球与球员身体方向的绝对方向差,dist diff表示球与球员的绝对距离。):
$$ 0\le\mathrm{dir_diff}\le180^\circ\land0\le\mathrm{dist_diff}\le\mathrm{kickable_margin} \ {\mathrm ep} = \mathrm{ep} \cdot (1 - 0.25 \cdot \frac{\mathrm{dir_diff}}{180^\circ} - 0.25 \cdot \frac{\mathrm{dist_ball}}{\mathrm{kickable_margin}})
$$
有效踢功率用于计算 $\vec{a}_{n_i}$,将添加到全局球加速度的加速度矢量 $\vec{a_n}$ 在周期 n 期间(请记住,我们有一个多代理系统,每个靠近球的球员都可以在同一个循环中踢球)。
有一个服务器参数 server::kick_rand
可用于对球的加速度产生一些噪音。对于默认玩家,kick_rand
为 0.1。对于异类玩家,kick_rand
取决于 player.conf 中的 player::kick_rand_delta_factor
和实际可踢边际。从RoboCup 2000开始,kick_rand 用于在普通玩家的评估轮中产生一些噪音。
TODO kick noise model after rcssserver-12.
在从仿真步骤 $n$ 到仿真步骤 $n+1$ 的过渡时,加速度$\vec{a_n}$生效:
- $\vec{a}_{n}$ 被归一化为
server::ball_accel_max
的最大长度。 - $\vec{a}{n}$ 与当前球速相加 $\vec{a}{n}$ 。 $\vec{v}_{n}$ 将被归一化为
server::ball_speed_max
的最大长度。 - 噪声 $\vec{n}$ 和风 $\vec{w}$ 将被添加到$\vec{v_n}$。噪音和风都可以在 server.conf 中配置。噪声的负责参数是
server::ball_rand
。噪声向量的方向和长度都在区间$[-|\vec{v_n}|\cdot ball_rand,|\vec{v_n}|\cdot ball_rand]$内。负责风的参数是server::wind_force
、server::wind_dir
和server::wind_rand
。 - 球员的新位置 $\vec{p}{n+1}$ 是旧位置 $\vec{p}{n}$ 加上速度矢量 $\vec{v_n}$(即玩家在两个模拟步骤之间的最大距离差是
ball_speed_max
)。 ball_decay
应用于玩家的速度:$\vec{v}{n+1}=\vec{v}{n}\cdot ball_decay$ 。加速 $\vec{a}_{n+1}$ 设置为零。
在当前设置下,假设最佳踢球,球的距离可达 50。最佳踢球后55个循环,从开球位置到球的距离约为48,剩余速度小于0.1。最佳踢球后18个循环,球的距离为34-34,剩余速度略小于1。
踢球模型和当前参数设置的含义是,使用几个小踢球进行复合踢球仍然可能会有所帮助——例如停止球,将其踢到可踢区域内更有利的位置,然后将其踢到所需的方向。例如停止球,将其踢到可踢区域内更有利的位置,然后将其踢到所需的方向。使用复合踢将球加速到最大速度而不将其置于相对位置 (0,0{textdegree}) 将是另一种可能性。
Ball and Kick Model Parameters
Default Parametersserver.conf |
Default Value (Range) | Heterogeneous Player Parametersplayer.conf |
Value |
---|---|---|---|
server::minpower | -100 | ||
server::maxpower | 100 | ||
server::minmoment | -180 | ||
server::maxmoment | 180 | ||
server::kickable_margin | 0.7 ([0.6, 0.8]) | player::kickable_margin_delta_min player::kickable_margin_delta_max |
-0.1 0.1 |
server::kick_power_rate | 0.027 | ||
server::kick_rand | 0.1 ([0.0, 0.2]) | player::kick_rand_delta_factor player::kickable_margin_delta_min player::kickable_margin_delta_max |
1 -0.1 0.1 |
server::ball_size | 0.085 | ||
server::ball_decay | 0.94 | ||
server::ball_rand | 0.05 | ||
server::ball_speed_max | 3.0 | ||
server::ball_accel_max | 2.7 | ||
server::wind_force | 0.0 | ||
server::wind_dir | 0.0 | ||
server::wind_rand | 0.0 |
Move Model 移动模型
移动命令可用于将球员直接放在场上所需的位置。 move 是为了安排球队而存在的,在正常比赛期间不起作用。它在每半场开始时可用(比赛模式 before_kick_off
)和进球后(比赛模式 goal_l_?
或 goal_r_?
)。在这些情况下,只要比赛模式不改变,球员可以被放置在本方半场的任何位置(即 X < 0)并且可以移动任意次数。移动到对方半场位置的球员将被服务器设置到自己一侧的随机位置。移动命令的第二个目的是在守门员接球后在禁区内移动守门员。如果守门员接住球,它可以在禁区内与球一起移动。守门员在踢球前可以移动 goalie_max_moves
次。其他移动命令没有任何效果,服务器将响应 (error too_many_moves)。
Parameter in server.conf |
Value |
---|---|
goalie_max_moves | 2 |
Say Model 说模型
使用 say 命令,玩家可以向其他玩家广播消息。消息可以是 say_msg_size
个字符长,其中 say 消息的有效字符来自集合 sth(不带方括号)。双方队员都可以在 audio_cut_dist
的距离内听到玩家所说的消息。假设发送到服务器的消息将立即发送回该距离内的玩家。说命令的使用仅受到收听消息的玩家的有限能力的限制。
Parameter in server.conf |
Value |
---|---|
say_msg_size | 10 |
audio_cut_dist | 50 |
Tackle Model 铲球模型
铲球命令是将球加速向球员的身体。球员可以通过执行铲球命令来踢出踢命令无法踢出的球。铲球的成功取决于与球位置相关的随机概率,可以通过以下公式获得。
当球在球员面前时,铲球失败的概率为:
$$ {\mathrm fail_prob = (\frac{player_to_ball.x}{tackle_dist})^{tackle_exponent} + (\frac{player_to_ball.y}{tackle_width})^{tackle_exponent}}
$$
当球在球员身后时铲球失败的概率为:
$$ {\mathrm fail_prob = (\frac{player_to_ball.x}{tackle_back_dist})^{tackle_exponent} + (\frac{player_to_ball.y}{tackle_back_width})^{tackle_exponent}}
$$ 铲球成功的概率为:
$$ {\mathrm tackle_prob = 1.0 – fail_prob}
$$
在这种情况下,当球在球员面前时,使用tackle_dist
(默认为2.0),否则使用tackle_back_dist
(默认为0.5);player_to_ball
是从球员到球的向量,相对于球员的身体方向。当铲球命令成功时,它会在自己的身体方向上给球一个加速度。
铲球的执行效果与踢的类似,是通过tackle_power_rate
(默认为0.027)乘以幂得到的。可以用以下公式表示:
$$ {\mathrm effective_power} = {\mathrm power} \times {\mathrm tackle_power_rate}
$$ 一旦球员执行了铲球命令,无论成功与否,球员在 10 个循环内都无法再移动。
Parameters for the tackle command
Parameter in server.conf |
Value |
---|---|
tackle_dist | 2 |
tackle_back_dist | 0 |
tackle_width | 1.25 |
tackle_cycles | 10 |
tackle_exponent | 6 |
tackle_power_rate | 0.027 |
max_tackle_power | 100 |
max_back_tackle_power | 0 |
tackle_rand_factor | 2 |
Turn Model 转向模型
turn 命令用于改变玩家的身体方向。turn 命令的参数是时刻;目前的有效值介于 server::minmoment
和 server::maxmoment
之间。如果玩家不动,则力矩等于玩家转身的角度。但是,有一个惯性概念,使您在移动时更难以转动。具体来说,玩家转身的实际角度如下:
$$ actual_angle=\frac{moment}{1+inertia_moment\times player_speed}
$$
server::inertia_moment
是一个 server.conf 参数,默认值为 5.0。因此(使用默认值),当玩家速度为 1.0 时,他可以做的最大有效转弯是 ±30。但是,请注意,因为您不能在同一个循环中进行冲刺和转弯,玩家在执行回合时可以走的最快速度是 $player_speed_max\times player_decay$,这意味着默认玩家(使用默认值)的有效回合为 ±60。
对于异类玩家,惯性矩是默认惯性值加上一个介于$player_decay_delta_min\times inertia_moment_delta_factor$和$player_decay_delta_max\times inertia_moment_delta_factor$之间的值
Default Parametersserver.conf |
Default Value (Range) | Heterogeneous Player Parametersplayer.conf |
Value |
---|---|---|---|
server::minmoment | -180 | ||
server::maxmoment | 180 | ||
server::inertia_moment | 5.0 ([2.5, 7.5]) |
player::player_decay_delta_min player::player_decay_delta_max player::inertia_moment_delta_factor |
-0.1 0.1 25 |
TurnNeck Model
使用 turn_neck,玩家可以在某种程度上独立于身体转动脖子。玩家头部的角度就是玩家的视角。turn 命令改变玩家身体的角度,而 turn_neck 改变玩家相对于身体的颈部角度。玩家颈部的最小和最大相对角度由 server.conf 中的 server::minneckang
和 server::maxneckang
给出。请记住,颈部角度是相对于玩家身体的,因此如果客户端发出转弯命令,即使没有发出 turn_neck 命令,视角也会发生变化。此外,turn_neck 命令可以在与 turn、dash 和 kick 命令相同的周期内执行。 turn_neck 不会像 turn 那样受动量影响。turn_neck 命令的参数必须在 server::minneckmoment
和 server::maxneckmoment
之间的范围内。
Parameter in server.conf |
Value |
---|---|
minneckang | -90 |
maxneckang | 90 |
minneckmoment | -180 |
maxneckmoment | 180 |