python的机器人基础原理工业场景模拟第四十篇:产线调试,增加关节最大加速度限制,调整轨迹时间,防止机械臂过载冲击。
《Python机器人基础原理》第四十篇:产线调试——增加关节最大加速度限制,调整轨迹时间,防止机械臂过载冲击
1. 实际工业应用场景
周二下午,某汽车零部件焊接产线周检修后的首次热机调试。一台3-DOF平面SCARA机器人(大臂长400 mm、质量2.1 kg、质心距基座210 mm、绕质心转动惯量0.18 kg·m²;小臂长300 mm、质量1.4 kg、质心距肘关节150 mm、绕质心转动惯量0.06 kg·m²;基座旋转关节额定扭矩8.0 N·m、最大角速度2.8 rad/s、最大角加速度8.0 rad/s²;末端额定负载0.8 kg;节拍要求3.5 s/次,重复定位精度±0.08 mm)正在执行金属垫片搬运任务。
这是第39篇工位仿真之后的跟进调试。上篇的时间缩放把速度压到了约束线以下(k=1.22),但没管加速度。小赵把优化后的轨迹文件导入调试终端,按下启动。机器人动了0.3秒,在第二段加速段急停,驱动器面板跳出"Overload Protection — Joint 1 Torque Limit"报警。
"又超了。"老刘放下咖啡杯,走到示教器前调出加速度曲线,"你看,取料位到抬升段那0.3秒的加速窗口里,关节1的角加速度峰值14.2 rad/s²,超了额定8.0的两倍还不止。扭矩跟加速度成正比——基座等效惯量大约0.72 kg·m²,14.2乘以0.72,峰值扭矩10.2 N·m,超了8.0的额定值。上篇k=1.22只能把加速度压到9.54,还是超。Z轴也一样——z从0.05升到0.18 m只给了0.3秒,线加速度2.89 m/s²,超了0.8的约束三倍多。"
小赵翻出上篇的报告。"那时间缩放继续拉?"
"对,但这次约束条件变了。加速度按1/k²缩小,不是1/k。k=1.22只够管速度,加速度需要k=√(14.2/8.0)×1.05≈1.40。取速度和加速度约束的较大值——k_final=1.40。缩放后节拍3.2×1.40=4.48秒,超了3.5秒的产线要求。"
"超了近一秒。"
"所以得改路径。把加速段的时间窗口拉长——要么把抬升段从0.3秒扩到0.5秒,要么把取料到抬升的z向距离缩短。缩放是兜底,改路径才是根本。"
本篇解决的问题:在已有速度约束时间缩放的基础上,增加关节最大角加速度约束校验。对越限段进行二次时间缩放(全局拉伸),量化加速度越限的严重程度和节拍代价。用简化动力学模型估算扭矩,验证加速度约束与过载报警的因果关系。
⚠️ 声明:本篇全部代码为课程离线仿真,运行在普通PC上,用于产线调试阶段加速度约束校核算法验证。不可直接用于真实机器人控制器或产线设备。真实工业现场需结合驱动器扭矩前馈、在线加速度规划、伺服增益整定。代码作者不对直接使用本代码于真实设备造成的任何后果负责。
2. 痛点分析
课程模块 本篇对应的工程痛点
第6章 轨迹规划与控制 → 6.4 轨迹约束与优化 时间缩放仅约束速度,未约束加速度,导致驱动器扭矩超限触发过载保护
第5章 机器人关节驱动与控制 → 5.3 扭矩-加速度关系 电机扭矩与关节加速度成正比(τ = J·α),加速度越限直接导致扭矩越限
第4章 机器人动力学建模 → 4.2 牛顿-欧拉递推 加速度约束需要动力学模型支撑,本篇用简化惯量模型估算扭矩,验证约束有效性
本篇代码解决 L2 离线产线调试仿真校核层。输入:工位轨迹点位序列 + 时间戳 + 关节最大角速度/角加速度约束 + 简化动力学参数。处理:IK映射→速度计算→加速度计算→双约束检测→时间缩放(取速度/加速度约束的较大k)→扭矩估算→节拍量化→验证。输出:4张对比图表 + 缩放报告。
不覆盖:完整牛顿-欧拉动力学递推、摩擦力模型、柔性关节振动、在线自适应加速度限制。
3. 核心逻辑讲解
物理直觉
你开一辆载重卡车走山路。上坡时你不能一脚油门踩到底——发动机扭矩有限,加速度太大就会熄火。机械臂同理:每个关节电机有最大输出扭矩,扭矩等于等效转动惯量乘以角加速度加上摩擦。角加速度越大,需要的扭矩越大。如果轨迹在拐点处要求瞬间从静止加速到高速,加速度极大,电机根本跟不上,驱动器只能报过载。
加速度约束的本质:限制速度变化的快慢。速度约束管"最高能跑多快",加速度约束管"从静止到最高速至少要用多长时间"。两者共同决定轨迹时间下界。
业务逻辑 → 代码映射
输入:工位轨迹 P[N][3] + 时间戳 t[N] + ω_max + α_max + 等效惯量 J
↓
【步骤1:逆运动学映射】
q[i] = IK(P[i]) → [θ₁, θ₂, θ₃, d₄]
↓
【步骤2:前向差分算速度】
ω[i] = (q[i+1] - q[i]) / (t[i+1] - t[i])
↓
【步骤3:差分之差分算加速度】
α[i] = (ω[i+1] - ω[i]) / (t[i+1] - t[i])
(假设等间隔采样,dt恒定)
↓
【步骤4:双约束计算缩放因子】
k_vel = max(|ω|) / ω_max × safety_margin
k_acc = sqrt(max(|α|) / α_max) × safety_margin
(加速度按1/k²缩小,所以k ∝ sqrt(α_actual/α_max))
k_final = max(k_vel, k_acc)
↓
【步骤5:时间缩放】
t_scaled = t × k_final,位置序列不变
↓
【步骤6:扭矩估算】
τ_est[i] = J × α_scaled[i]
↓
【步骤7:验证 + 节拍量化】
重算缩放后速度和加速度,确认满足约束
若 scaled_duration > 节拍要求 → 给出路径优化建议
↓
输出:对比图表 + 缩放报告
关键公式文字翻译
加速度缩放关系:位置P(t),速度v = dP/dt,加速度a = d²P/dt²。时间缩放 t' = k·t,则 v' = (1/k)·v,a' = (1/k²)·a。加速度按1/k²缩小——k需要比速度约束要求的更大。例如实际加速度14.2 rad/s²,约束8.0,比值1.775,开方得1.332,安全系数1.05 → k_acc = 1.40。
扭矩估算:τ ≈ J·α(忽略摩擦和重力项)。基座等效惯量约0.72 kg·m²,加速度14.2 rad/s²时估算扭矩10.2 N·m,超额定8.0 N·m。缩放后加速度7.24 rad/s²,扭矩5.2 N·m,满足约束。
为什么缩放不会引入额外放大:时间缩放只改变时间参数化,路径不变。IK映射的非线性已经包含在原始加速度 α_raw 中,缩放后精确按 α_scaled(t) = α_raw(t/k) / k² 缩小。不存在"缩放后额外冲高"的效应。
4. OOP代码实现
技术栈
严格限定:numpy, scipy, matplotlib。不引入pybullet、roboticstoolbox等任何第三方机器人库。
项目结构树
debug_sim/
├── run_debug_sim.py
├── requirements.txt
├── robot/
│ ├── __init__.py
│ ├── models.py
│ ├── inverse_kinematics.py
│ ├── trajectory_generator.py
│ ├── time_scaler.py
│ ├── constraint_checker.py
│ ├── dynamics_model.py
│ └── visualize_debug.py
├── tests/
│ ├── __init__.py
│ └── test_debug_sim.py
└── results/
核心源码
"robot/models.py" — 数据模型
"""
数据模型:DH参数、连杆动力学参数、轨迹点位、调试配置
全部参数内置,自包含可复现
"""
from dataclasses import dataclass, field
from typing import List
import numpy as np
@dataclass
class DHLink:
"""单个连杆的D-H参数(标准D-H约定)"""
a: float # 连杆长度 (m)
alpha: float # 连杆扭转角 (rad)
d: float # 连杆偏移 (m)
theta_offset: float = 0.0 # 关节角偏置 (rad)
@dataclass
class LinkDynamics:
"""连杆动力学参数"""
mass: float # 质量 (kg)
com_x: float # 质心x坐标 (m,沿连杆方向)
com_y: float # 质心y坐标 (m)
com_z: float # 质心z坐标 (m)
inertia_zz: float # 绕Z轴(旋转轴)转动惯量 (kg·m²)
@dataclass
class RobotConfig:
"""
机器人配置:3-DOF平面SCARA + Z轴移动
dyn[0]=基座, dyn[1]=大臂, dyn[2]=小臂, dyn[3]=末端负载
"""
links: List[DHLink]
dynamics: List[LinkDynamics]
joint_limits: List[tuple] = None
max_joint_velocities: List[float] = None
max_joint_accelerations: List[float] = None
rated_torques: List[float] = None
def __post_init__(self):
if self.joint_limits is None:
self.joint_limits = [
(-170 * np.pi / 180, 170 * np.pi / 180),
(-150 * np.pi / 180, 150 * np.pi / 180),
(-150 * np.pi / 180, 150 * np.pi / 180),
(-0.12, 0.12),
]
if self.max_joint_velocities is None:
self.max_joint_velocities = [2.8, 2.8, 3.2, 0.12]
if self.max_joint_accelerations is None:
self.max_joint_accelerations = [8.0, 8.0, 10.0, 0.8]
if self.rated_torques is None:
self.rated_torques = [8.0, 5.0, 3.0, 0.0]
# DH参数(与第39篇同一工位)
CALIBRATED_LINKS = [
DHLink(a=0.400, alpha=0.0, d=0.150, theta_offset=0.0),
DHLink(a=0.300, alpha=0.0, d=0.0, theta_offset=0.0),
DHLink(a=0.0, alpha=0.0, d=0.0, theta_offset=0.0),
DHLink(a=0.0, alpha=0.0, d=-0.10, theta_offset=0.0),
]
# 动力学参数:与场景描述对齐
# dyn[0]=基座, dyn[1]=大臂(inertia_zz=0.18), dyn[2]=小臂(inertia_zz=0.06), dyn[3]=末端负载
CALIBRATED_DYNAMICS = [
LinkDynamics(mass=1.5, com_x=0.0, com_y=0.0, com_z=0.05, inertia_zz=0.05),
LinkDynamics(mass=2.1, com_x=0.21, com_y=0.0, com_z=0.0, inertia_zz=0.18),
LinkDynamics(mass=1.4, com_x=0.15, com_y=0.0, com_z=0.0, inertia_zz=0.06),
LinkDynamics(mass=0.8, com_x=0.0, com_y=0.0, com_z=0.0, inertia_zz=0.01),
]
@dataclass
class TrajectoryPoint:
"""轨迹点位"""
time: float
position: np.ndarray
@dataclass
class TimeScalingConfig:
"""时间缩放配置"""
safety_margin: float = 1.05
max_scale_factor: float = 5.0
cycle_time_requirement: float = 3.5
@dataclass
class ScalingReport:
"""缩放报告"""
original_duration: float
scaled_duration: float
scale_factor: float
max_vel_raw: float
max_vel_scaled: float
max_accel_raw: float
max_accel_scaled: float
violating_joint_vel: int
violating_joint_accel: int
constraint_satisfied: bool
cycle_time_violated: bool
cycle_time_excess: float
k_from_velocity: float
k_from_acceleration: float
"robot/inverse_kinematics.py" — 逆运动学
"""
逆运动学模块
3-DOF平面SCARA + Z轴移动,解析解
不可达时raise ValueError
Z轴d4 = z - d_base,纳入限位检查
"""
import numpy as np
from robot.models import RobotConfig
class InverseKinematics:
"""SCARA逆运动学解析求解器"""
def __init__(self, config: RobotConfig, elbow_mode: str = "up"):
self.config = config
self.a1 = config.links[0].a
self.a2 = config.links[1].a
self.d_base = config.links[0].d
self.elbow_mode = elbow_mode
def solve(self, position: np.ndarray) -> np.ndarray:
x, y, z = position[0], position[1], position[2]
r = np.sqrt(x**2 + y**2)
r_min = abs(self.a1 - self.a2)
r_max = self.a1 + self.a2
if r < r_min - 1e-6 or r > r_max + 1e-6:
raise ValueError(
f"点位 ({x:.3f}, {y:.3f}, {z:.3f}) 不可达:"
f"r={r:.4f} m 超出 [{r_min:.4f}, {r_max:.4f}] m"
)
cos_theta2 = (r**2 - self.a1**2 - self.a2**2) / (2 * self.a1 * self.a2)
if abs(cos_theta2) > 1.0:
raise ValueError(f"arccos参数越界: {cos_theta2:.6f}")
theta2 = np.arccos(cos_theta2)
phi = np.arctan2(y, x)
cos_alpha = (r**2 + self.a1**2 - self.a2**2) / (2 * self.a1 * r)
if abs(cos_alpha) > 1.0:
raise ValueError(f"α的arccos参数越界: {cos_alpha:.6f}")
alpha = np.arccos(cos_alpha)
if self.elbow_mode == "up":
theta1 = phi - alpha
else:
theta1 = phi + alpha
theta3 = -theta2
d4 = z - self.d_base
# 限位检查(4关节全部校验)
limits = self.config.joint_limits
joint_vals = [theta1, theta2, theta3, d4]
joint_names = ["基座", "大臂", "小臂", "Z轴"]
for j in range(4):
if not (limits[j][0] <= joint_vals[j] <= limits[j][1]):
if j < 3:
raise ValueError(
f"{joint_names[j]}关节角 {joint_vals[j]*180/np.pi:.1f}° "
f"超出限位 [{limits[j][0]*180/np.pi:.1f}°, "
f"{limits[j][1]*180/np.pi:.1f}°]"
)
else:
raise ValueError(
f"{joint_names[j]}位移 {joint_vals[j]*1000:.1f} mm "
f"超出限位 [{limits[j][0]*1000:.1f}, "
f"{limits[j][1]*1000:.1f}] mm"
)
return np.array([theta1, theta2, theta3, d4], dtype=np.float64)
"robot/trajectory_generator.py" — 轨迹生成
"""
轨迹生成模块
四段式路径:取料→抬升→平移→下降放料
原始节拍3.2 s,加速窗口0.3 s,故意制造加速度越限
与第39篇为同一工位的不同阶段
"""
import numpy as np
from robot.models import TrajectoryPoint
class TrajectoryGenerator:
"""产线调试轨迹生成器"""
def __init__(self, total_time: float = 3.2, n_points: int = 140):
self.total_time = total_time
self.n_points = n_points
def generate_debug_trajectory(self) -> list:
"""
四段式路径,模拟焊接产线搬运
0: 取料 (0.25, -0.10, 0.05)
1: 抬升 (0.25, -0.10, 0.18)
2: 平移 (0.45, 0.10, 0.18)
3: 放料 (0.45, 0.10, 0.05)
时间分配:0→0.3→0.8→3.2
第一段加速窗口仅0.3 s,制造加速度越限
Z轴0.3 s内从0.05升到0.18 m,线加速度约2.89 m/s²
"""
dt = self.total_time / (self.n_points - 1)
trajectory = []
waypoints = np.array([
[0.25, -0.10, 0.05],
[0.25, -0.10, 0.18],
[0.45, 0.10, 0.18],
[0.45, 0.10, 0.05],
])
t_waypoints = np.array([0.0, 0.3, 0.8, 3.2])
for i in range(self.n_points):
t = i * dt
seg = 0
for j in range(len(t_waypoints) - 1):
if t_waypoints[j] <= t <= t_waypoints[j + 1]:
seg = j
break
if t >= t_waypoints[-1]:
seg = len(t_waypoints) - 2
t0 = t_waypoints[seg]
t1 = t_waypoints[seg + 1]
p0 = waypoints[seg]
p1 = waypoints[seg + 1]
if t1 - t0 > 1e-6:
s = (t - t0) / (t1 - t0)
else:
s = 1.0
pos = p0 + s * (p1 - p0)
trajectory.append(TrajectoryPoint(time=t, position=pos))
return trajectory
"robot/time_scaler.py" — 时间缩放
"""
时间缩放模块
支持速度和加速度双约束,取较大的k
加速度按1/k²缩放,k_acc = sqrt(α_ratio) × margin
"""
from typing import List
import numpy as np
from robot.models import TimeScalingConfig, ScalingReport
class TimeScaler:
"""轨迹时间缩放器"""
def __init__(self, config: TimeScalingConfig):
self.config = config
def compute_velocities(self, times: np.ndarray,
joint_vars: np.ndarray) -> np.ndarray:
"""
前向差分计算关节速度
假设等间隔采样(dt恒定),边界处dt取相邻值
"""
n = len(times)
n_joints = joint_vars.shape[1]
velocities = np.zeros((n - 1, n_joints))
for i in range(n - 1):
dt = times[i + 1] - times[i]
if dt > 1e-10:
velocities[i] = (joint_vars[i + 1] - joint_vars[i]) / dt
return velocities
def compute_accelerations(self, times: np.ndarray,
joint_vars: np.ndarray) -> np.ndarray:
"""
前向差分的差分计算关节加速度
假设等间隔采样:统一使用 times[1]-times[0] 作为dt
边界两行加速度恒为0(无足够邻点)
加速度按1/k²缩放
"""
velocities = self.compute_velocities(times, joint_vars)
n = len(velocities)
n_joints = velocities.shape[1]
accelerations = np.zeros((n - 1, n_joints))
# 等间隔假设下,统一dt
dt = times[1] - times[0] if len(times) > 1 else 1.0
for i in range(n - 1):
if dt > 1e-10:
accelerations[i] = (velocities[i + 1] - velocities[i]) / dt
return accelerations
def compute_scale_factors(self, joint_vars: np.ndarray,
times: np.ndarray,
max_velocities: List[float],
max_accelerations: List[float]) -> tuple:
"""
分别计算速度约束和加速度约束要求的缩放因子
返回 (k_vel, k_acc)
"""
velocities = self.compute_velocities(times, joint_vars)
accelerations = self.compute_accelerations(times, joint_vars)
n_joints = velocities.shape[1]
# 速度约束
max_vel_ratio = 0.0
for j in range(n_joints):
if max_velocities[j] > 0:
ratio = np.max(np.abs(velocities[:, j])) / max_velocities[j]
max_vel_ratio = max(max_vel_ratio, ratio)
k_vel = max_vel_ratio * self.config.safety_margin
k_vel = max(1.0, min(k_vel, self.config.max_scale_factor))
# 加速度约束:k ∝ sqrt(α_actual / α_max)
max_accel_ratio = 0.0
for j in range(n_joints):
if max_accelerations[j] > 0:
ratio = np.max(np.abs(accelerations[:, j])) / max_accelerations[j]
max_accel_ratio = max(max_accel_ratio, ratio)
k_acc = np.sqrt(max_accel_ratio) * self.config.safety_margin
k_acc = max(1.0, min(k_acc, self.config.max_scale_factor))
return k_vel, k_acc
def scale_timestamps(self, times: np.ndarray,
scale_factor: float) -> np.ndarray:
"""仅拉伸时间戳,位置序列不变——不做反向插值"""
return times * scale_factor
def generate_report(self, original_duration: float,
scaled_duration: float,
scale_factor: float,
max_vel_raw: float, max_vel_scaled: float,
max_accel_raw: float, max_accel_scaled: float,
violating_joint_vel: int,
violating_joint_accel: int,
constraint_satisfied: bool,
cycle_time_requirement: float,
k_vel: float, k_acc: float) -> ScalingReport:
cycle_time_violated = scaled_duration > cycle_time_requirement
cycle_time_excess = max(0.0, scaled_duration - cycle_time_requirement)
return ScalingReport(
original_duration=original_duration,
scaled_duration=scaled_duration,
scale_factor=scale_factor,
max_vel_raw=max_vel_raw,
max_vel_scaled=max_vel_scaled,
max_accel_raw=max_accel_raw,
max_accel_scaled=max_accel_scaled,
violating_joint_vel=violating_joint_vel,
violating_joint_accel=violating_joint_accel,
constraint_satisfied=constraint_satisfied,
cycle_time_violated=cycle_time_violated,
cycle_time_excess=cycle_time_excess,
k_from_velocity=k_vel,
k_from_acceleration=k_acc
)
"robot/constraint_checker.py" — 约束校验
"""
约束校验模块
同时校验速度和加速度约束
复用TimeScaler的差分方法
"""
from typing import List
import numpy as np
from robot.models import RobotConfig
class ConstraintChecker:
"""双约束校验器"""
def __init__(self, robot_config: RobotConfig, time_scaler):
self.robot_config = robot_config
self.max_velocities = robot_config.max_joint_velocities
self.max_accelerations = robot_config.max_joint_accelerations
self.time_scaler = time_scaler
def check_all_constraints(self, times: np.ndarray,
joint_vars: np.ndarray) -> dict:
"""同时校验速度和加速度约束"""
velocities = self.time_scaler.compute_velocities(times, joint_vars)
accelerations = self.time_scaler.compute_accelerations(times, joint_vars)
n_joints = velocities.shape[1]
# 速度校验
vel_violations = np.zeros(n_joints, dtype=bool)
max_vel_per_joint = np.zeros(n_joints)
for j in range(n_joints):
max_vel_per_joint[j] = np.max(np.abs(velocities[:, j]))
if max_vel_per_joint[j] > self.max_velocities[j]:
vel_violations[j] = True
# 加速度校验
accel_violations = np.zeros(n_joints, dtype=bool)
max_accel_per_joint = np.zeros(n_joints)
for j in range(n_joints):
max_accel_per_joint[j] = np.max(np.abs(accelerations[:, j]))
if max_accel_per_joint[j] > self.max_accelerations[j]:
accel_violations[j] = True
all_satisfied = (not np.any(vel_violations) and
not np.any(accel_violations))
return {
'all_satisfied': all_satisfied,
'velocity': {
'satisfied': not np.any(vel_violations),
'max_per_joint': max_vel_per_joint,
'violations': vel_violations,
},
'acceleration': {
'satisfied': not np.any(accel_violations),
'max_per_joint': max_accel_per_joint,
'violations': accel_violations,
}
}
"robot/dynamics_model.py" — 简化动力学
"""
简化动力学模型
正确计算等效转动惯量(含平行轴定理)
用 τ ≈ J·α 估算关节扭矩,验证加速度约束与过载报警的因果关系
"""
import numpy as np
from robot.models import RobotConfig
class SimplifiedDynamics:
"""
简化动力学模型
dyn[0]=基座, dyn[1]=大臂(inertia_zz=0.18), dyn[2]=小臂(0.06), dyn[3]=末端负载
"""
def __init__(self, config: RobotConfig):
self.config = config
self.J_equivalent = self._compute_equivalent_inertia()
def _compute_equivalent_inertia(self) -> list:
"""
计算每个关节的等效转动惯量(含平行轴项)
基座关节(关节0):
J = 基座自身 + 大臂(m·r² + I_zz) + 小臂(m·r² + I_zz) + 末端(m·r²)
大臂关节(关节1):
J = 大臂自身I_zz + 小臂(m·r² + I_zz) + 末端(m·r²)
小臂关节(关节2):
J = 小臂自身I_zz + 末端(m·r²)
Z轴(关节3):
J = 等效质量
"""
dyn = self.config.dynamics
links = self.config.links
J = [0.0, 0.0, 0.0, 0.0]
# 小臂关节(关节2)
J[2] = dyn[2].inertia_zz + dyn[3].mass * links[1].a**2
# 大臂关节(关节1)
r_small = links[0].a + links[1].com_x
J[1] = dyn[1].inertia_zz + dyn[2].mass * r_small**2 + dyn[2].inertia_zz
J[1] += dyn[3].mass * links[0].a**2
# 基座关节(关节0)
r_big = links[0].com_x
J[0] = dyn[0].inertia_zz + dyn[1].mass * r_big**2 + dyn[1].inertia_zz
r_small_total = links[0].a + links[1].a
J[0] += dyn[2].mass * r_small_total**2 + dyn[2].inertia_zz
J[0] += dyn[3].mass * r_small_total**2
# Z轴:等效质量
J[3] = dyn[2].mass + dyn[3].mass
return J
def estimate_torques(self, accelerations: np.ndarray) -> np.ndarray:
"""
估算各关节扭矩:τ_j ≈ J_j · α_j
前3轴角加速度×惯量,第4轴线加速度×质量
"""
n = accelerations.shape[0]
n_joints = accelerations.shape[1]
torques = np.zeros((n, n_joints))
for i in range(n):
for j in range(n_joints):
torques[i, j] = self.J_equivalent[j] * acceler
利用AI解决实际问题,如果你觉得这个工具好用,欢迎关注长安牧笛!
DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。
更多推荐

所有评论(0)