新闻详情

新闻详情

首页 / 资讯中心 / 详情

基于Unity ML-Agents的自行车机器人强化学习训练与多智能体避障仿真

发布时间:2026/10/2 17:47:36来源:尧图网络
基于Unity ML-Agents的自行车机器人强化学习训练与多智能体避障仿真
简介这是一套基于 Unity ML-Agents release 15 开发的智能自行车机器人仿真系统面向智能交通、强化学习与自动驾驶领域的研究者、开发者及高校学生用于解决自行车智能体在复杂城市交通环境中的自主导航、避障与群体协同行为建模问题。资源共 566 个文件压缩包约 34.12MB包含 30 个 onnx 和 26 个 pt 格式的训练模型、23 个 Unity 场景 asset、21 个 C# 脚本、14 个 prefab 预制体、15 个 mat 材质以及 TensorBoard 训练日志和说明文档等meta、unity 等工程文件构成完整项目可直接打开运行或继续训练。目前已有 71 人在 CSDN 学习并下载。整套资源提供了可复现的强化学习训练环境与环岛、十字路口等多种交通场景地形还附带了训练好的模型与配套说明便于研究者快速复现实验、观察智能体决策过程也可作为毕业设计或智能体仿真课程的项目基础。资源内目录结构清晰便于按需检索和二次开发。1. 在Unity里训一辆自行车之前为什么这个仿真系统值得做如果用一句话说清楚这个项目它是在 Unity 引擎里搭出一套带真实交通要素的骑行环境用 ML-Agents 的强化学习算法去训练一个能让自行车机器人自主导航和避障的决策模型同时让多辆自行车组成群体在模拟车流里跑出类似真实交通的行为。它解决的核心问题是把传统写在代码里的 if-else 避障逻辑变成数据驱动的策略换一个路口布局、换一种车流密度规则脚本要逐条改而强化学习模型只需要重新训练或微调。适合正在做机器人导航前期验证、自动驾驶决策预研、游戏 AI 行为设计以及交通流仿真的人。我见过很多人对这套方案的第一反应是“Unity 做仿真是不是太重了”但真正动手以后会发现ML-Agents 已经帮你把采样、replay buffer、PPO 更新全部封装好你要做的是把自行车的感知和运动学模型写对剩下的事情交给训练器。2. 搭建自行车智能体环境Agent接口、感知输入与奖励函数2.1 让自行车机器人进入ML-Agents决策循环新建Agent脚本并挂载行为参数ML-Agents 的训练闭环是这样转起来的场景里每个挂了 Behavior Parameters 的对象就是一个 Agent训练器按设定频率给它发决策请求Agent 先收集观测把观测向量传给神经网络网络输出连续或离散动作动作作用到自行车刚体上环境返回奖励。对自行车机器人来说最关键的既不是画一个好看的车模而是把“控制量”和“运动学模型”设计得足够简单。我一般会先用运动学自行车模型起步控制量只有两维一个是驱动速度一个是前轮转角。暂不做侧倾平衡把自行车当成一个非完整约束运动体。原因是强化学习刚上手时最怕状态空间太大如果你把倾角、角速度、扭矩、路面坡度全部塞进观测里训练难度会指数级上升。等路径规划和避障跑通了再去叠加平衡控制层。using UnityEngine; using Unity.MLAgents; using Unity.MLAgents.Sensors; using Unity.MLAgents.Actuators; public class BikeAgent : Agent { [Header(运动学参数)] public float maxDriveSpeed 12f; // 最大前进速度约等于城市骑行速度 public float maxSteerAngle 30f; // 前轮最大摆角超过会显得动作假 public float wheelBase 1.8f; // 轴距决定转弯半径 public Transform target; public Transform spawnPoint; private Rigidbody bikeRb; private float currentSpeed; private float currentSteer; public override void Initialize() { bikeRb GetComponentRigidbody(); } public override void OnEpisodeBegin() { transform.SetPositionAndRotation(spawnPoint.position, spawnPoint.rotation); bikeRb.linearVelocity Vector3.zero; bikeRb.angularVelocity Vector3.zero; target.position RandomPathPoint(); // 在可行区域里取一个合法目标点 } public override void CollectObservations(VectorSensor sensor) { // 自车速度转换到车身坐标系再做归一化 Vector3 localVel transform.InverseTransformDirection(bikeRb.linearVelocity); sensor.AddObservation(localVel.x / maxDriveSpeed); sensor.AddObservation(localVel.z / maxDriveSpeed); sensor.AddObservation(currentSteer / maxSteerAngle); // 目标点相对位置按场景尺度归一化到 -1 ~ 1 Vector3 offset target.position - transform.position; sensor.AddObservation(offset.x / 50f); sensor.AddObservation(offset.z / 50f); } public override void OnActionReceived(ActionBuffers actions) { float drive Mathf.Clamp(actions.ContinuousActions[0], -1f, 1f); float steer Mathf.Clamp(actions.ContinuousActions[1], -1f, 1f); currentSpeed drive * maxDriveSpeed; currentSteer steer * maxSteerAngle; // 自行车模型先按前轮转角算航向角速度再更新刚体速度 float yawRate currentSpeed * Mathf.Tan(currentSteer * Mathf.Deg2Rad) / wheelBase; transform.Rotate(Vector3.up, yawRate * Time.fixedDeltaTime, Space.Self); bikeRb.linearVelocity transform.forward * currentSpeed; // 稠密奖励向目标前进并给到达终点一个较大的正向奖励 float forwardSpeed Vector3.Dot(bikeRb.linearVelocity, transform.forward); AddReward(forwardSpeed / maxDriveSpeed * 0.05f); AddReward(Vector3.Distance(transform.position, target.position) 1f ? 1f : 0f); } public override void Heuristic(in ActionBuffers actionsOut) { // 人工验证环境时使用键盘控制不需要训练器介入 actionsOut.ContinuousActions[0] Input.GetAxis(Vertical); actionsOut.ContinuousActions[1] Input.GetAxis(Horizontal); } }代码里我刻意没有用 3D 射线传感器而是把它放到 Unity 编辑器里配置这样调射线根数、探测距离、layer mask 不用动代码。需要注意的是Behavior Parameters上的观测维度会被传感器组件自动累加你在CollectObservations里压入的是向量观测运行时顺序是“传感器先、向量后”这个顺序一旦定了就别再改否则旧模型全部失效。刚体要关闭角扰动锁定 z 轴旋转质量设 80kg 左右这些细节直接影响训练时能不能稳定起步。2.2 状态不一定靠射线传感器配置和空间归一化ML-Agents 里常见有 RayPerceptionSensorComponent3D、CameraSensorComponent 和向量传感器。自行车在交通场景里我用的最多的是 RayPerception 加向量观测。相机传感器维度太大训练时动不动就是几万维输入而且画面里的阴影、光照变化很容易让模型过拟合射线传感器只取固定角度和距离更贴近激光雷达的感知逻辑。配置项建议值原因Ray Count79 根能覆盖正前方和左右 45 度Ray Angle起始 -45 度结束 45 度转弯时能看到侧向障碍Ray Distance1520 米更远的信息对训练不是线性增益Layer Mask静态障碍、车辆、行人别选地面和路牙否则全是噪声Decision Period5物理步长 0.02s 时相当于每 0.1s 决策一次这里列的是一个起点值不是最优值。射线太多会让观测维度从 35 涨到 60反而拉慢训练射线太少又会在路口看不到侧面来车。我习惯先上 7 根等训练稳定后再加。还有归一的习惯所有速度除以最大速度所有距离除以场景尺度保证输入到神经网络的量级在 -1 到 1 附近。ML-Agents 的normalize配置虽然也能自动处理但它对自定义的距离输入并不友好。2.3 奖励函数怎么设先分清“要学的事情”和“不要学的事情”奖励设计是强化学习里最容易变成玄学的部分因为模型真的会钻空子。我给自己定了一个原则第一优先写硬约束第二写导航引导最后才写风格惩罚。硬约束包括碰撞即给负奖励并结束回合超出区域同样结束导航引导用“前进速度投影”这种稠密量风格惩罚是用来防止模型只想着拿前进奖励在原地画龙。奖励项数值说明朝目标方向前进0.05 × 归一化速度稠密引导让模型学会向前骑到达目标点1回合终止信号只给一次碰撞障碍物-0.8立即结束回合离目标超过 50 米-0.5相当于走出地图的兜底惩罚转向角长期超过 25 度-0.02抑制画龙和原地打转这里最容易踩的坑是奖励量纲打架。比如碰撞是 -0.8而前进奖励每帧只有 0.05一个回合如果跑 200 帧累计起来前进奖励约 10碰撞惩罚根本压不住它。解决方法是做减法而不是加法把朝目标前进的奖励改小同时在没前进的时候给一个微弱的负奖励。模型天生的惰性会帮你去掉无效行为。3. 用mlagents-learn启动训练PPO配置、训练命令与盯盘方法3.1 先给trainer写一份能落地的YAML配置在 release 15 对应的 2.x 分支里训练参数完全由 YAML 控制trainer 默认用 PPO。很多人在这个文件里照抄默认值结果训练出来的自行车动作一顿一顿。它不是写错代码而是batch_size、buffer_size、time_horizon之间比例不对。behaviors: BikeAgent: trainer_type: ppo hyperparameters: batch_size: 256 buffer_size: 4096 learning_rate: 3.0e-4 beta: 0.01 epsilon: 0.2 lambd: 0.95 num_epoch: 4 learning_rate_schedule: linear network_settings: normalize: true hidden_units: 256 num_layers: 2 vis_encode_type: simple reward_signals: extrinsic: strength: 1.0 gamma: 0.99 max_steps: 2000000 time_horizon: 128 summary_freq: 10000buffer_size是经验池容量batch_size是每次更新抽样的样本量建议前者是后者的八到十六倍。beta是熵权重控制探索程度。如果你是第一次跑先别去调epsilon和lambd这两个在 PPO 里默认值已经够稳。max_steps指的是总训练步数单个自行车场景 200 万步能看到明显结果如果场景里放了十几辆车把 200 万改成 500 万别妄想用 30 万步训出群体行为。3.2 从命令行启动训练编辑器还是训练打包出来的可执行文件先要装好 Python 侧的工具我用pip install mlagents安装版本要和 Unity 里的com.unity.ml-agents对齐不然连接时会报版本不匹配。对齐以后有两种跑法第一次建议用编辑器直接跑因为可以随时暂停改 prefab。# 方式一在 Unity Editor 里直接训练 mlagents-learn config/bike_ppo.yaml --run-idbike_nav_v1 --train # 启动命令后切回 Unity 编辑器点 Play控制台会显示连接建立 # 方式二打包成可执行文件后再训练适合批量做参数实验 mlagents-learn config/bike_ppo.yaml --run-idbike_nav_v2 --train --envbuild/BikeSim.x86_64编辑器训练开着很多调试 UI性能会慢不少。一批实验跑通后我习惯打包发布版去训练--env后面跟上可执行文件路径。--run-id相当于实验名所有日志都写到results/bike_nav_v1下。上次训练中断了加--resume继续想从一个成熟模型继续微调用--initialize-from旧run_id。注意同一 run_id 不能重复起否则终端会报错这时候改成bike_nav_v3或先清空目录。3.3 训练时看什么TensorBoard里几根曲线说明什么问题训练跑起来以后另一个终端执行tensorboard --logdir results/bike_nav_v1 --port 6006。我每次训练最先看的是四个指标Cumulative Reward、Entropy、Policy Loss、Value Loss。指标健康表现异常情况Cumulative Reward先波动后逐步上升长时间贴着 0 不动先怀疑奖励太稀疏Entropy初始 1 附近缓慢下降掉到 0.1 以下策略过于死板调大 betaPolicy Loss围绕 0.01~0.1 波动剧烈震荡且 reward 不涨学习率调低Value Loss逐步收敛忽高忽低检查观测里是不是混入了 NaN新手最容易把熵当坏人看到它下降就紧张。其实熵下降说明策略在学习真正要担心的是下降太快、最后变成一个重复动作。我处理这类问题时先加beta到 0.02再观察如果 reward 也跟着掉再把beta降回 0.01。训练是黑匣子一次只动一个变量否则你根本不知道是哪个参数救了模型。4. 让自行车群体在复杂环境中学会避让多智能体强化学习的训练配置4.1 多个自行车共享一套策略还是各训各的交通场景里基本不可能只放一辆自行车标题里说的“自行车群体”才是难点。多智能体强化学习在这套系统里的实现方式比想象中简单只要所有自行车挂同一个 Behavior NameML-Agents 就会把它们当作同策略的智能体共享同一个网络参数。换句话说你训练出来的是一个通用的“骑行决策脑”然后复制到每一辆车上让它们各自跑。如果给不同车辆设不同 Behavior Name比如外卖骑手和通勤骑手它们的经验池就分开了各训各的模型。这在语义上更合理但训练成本翻倍。我在第一版项目里一般让所有自行车同构共享一个 Behavior。等模型稳定了再在观测里加入“骑手类型”这个量让一辆车学到不同风格而不是从零再训一遍。用同一个 Behavior 还有一个隐藏优势智能体之间天然共享经验群体避让的学习速度会比互不干扰的独立环境快一些。4.2 群体场景里的奖励设计把“车的空间”写进状态群体避让和静态避障本质区别是别的自行车不是固定的障碍物它们也会对你的动作做出反应。只靠障碍物射线不够你必须在观测里加入周围邻居的信息。我一般取最近的 6 辆车把它们在自车坐标系下的相对位置和相对速度压进向量观测不足 6 个时补零。public int maxNeighborsToObserve 6; public override void CollectObservations(VectorSensor sensor) { var allBikes FindObjectsByTypeBikeAgent(FindObjectsSortMode.None); List(float dist, BikeAgent bike) neighbors new(); foreach (var other in allBikes) { if (other this) continue; neighbors.Add((Vector3.Distance(other.transform.position, transform.position), other)); } neighbors.Sort((a, b) a.dist.CompareTo(b.dist)); for (int i 0; i maxNeighborsToObserve; i) { if (i neighbors.Count) { // 转成本车坐标系便于网络理解“他在我左边还是右边” Vector3 localPos transform.InverseTransformPoint(neighbors[i].bike.transform.position); sensor.AddObservation(localPos / 10f); float relSpeed neighbors[i].bike.currentSpeed - currentSpeed; sensor.AddObservation(relSpeed / maxDriveSpeed); } else { sensor.AddObservation(Vector3.zero); sensor.AddObservation(0f); } } }奖励侧我额外给两个信号一个是“侵入他人空间”的惩罚当邻居距离小于 2 米时每帧扣分另一个是“顶头对峙”的惩罚当对方在自己前方且接近速度大于 0而自车横向偏移不变时每帧扣分。后一项非常关键它专治两辆车面对面堵死谁也不让的僵局。没有这个信号群体训练后期就会变成互相赌气整体奖励曲线卡在一个平台上不去。4.3 把训练难度从“路人甲”调到“早晚高峰”课程式场景参数复杂环境不是一上来就把车流密度拉满。ML-Agents 的 2.x 版本把一部分课程学习功能移到了 Python 侧我的做法是写一个简单的 Python 包装器按阶段调整场景参数。经典方案是每训完一个阶段让车流密度提高一点红绿灯周期缩短一点。import subprocess, json, time for stage in range(1, 6): density 0.1 * stage with open(scenario_params.json, w) as f: json.dump({density: density, traffic_light_cycle: 15 - stage}, f) subprocess.run([ mlagents-learn, config/bike_ppo.yaml, --run-id, fbike_nav_v{stage}, --resume, --env, build/BikeSim.x86_64, ]) time.sleep(10)场景里的车辆数和红绿灯周期在 Unity 侧读取scenario_params.json来生成。这里要注意--resume的意义每个阶段都是在上一个模型基础上继续训练不是从零开始。课程式训练比直接上高峰车流效果好得多因为模型在低密度时先把“怎么骑行”学会后面才把注意力放到“怎么避让”。我自己见过太多一上来就放几十辆车的实验跑了三百万步奖励都是负的不是算法不行是难度没有循序渐进。5. 自行车机器人训练避坑清单五个最容易翻车的地方5.1 学了十万步还在原地转圈奖励给了个寂寞现象训练曲线一直贴着零偶尔有一两个回合出现正奖励但整体就是涨不上去。原因目标点奖励设得太大而中间缺少稠密引导。自行车随机晃到终点附近时拿到一次 1大部分徘徊行为是随机的网络根本不知道哪些动作组合导致了好结果。解决把单次 1 拆成多个小奖励每靠近目标一定距离就给一次“接近增量”同时把无效徘徊设置成微小负奖励。模型会更早意识到“往前走”这个动作的因果联系训练曲线起来的就会早得多。5.2 路口明明有车射线就是检测不到现象训练时自行车直线撞向障碍物仿佛完全看不见但手动控制模式下能轻松避开。原因RayPerceptionSensor 的 Layer Mask 没选对或者射线从刚体中心射出但刚体中心被车身模型挡住了。还有可能是射线探测距离太短到 5 米内才感知紧急刹车来不及。解决先在场景里打开射线可视化调试逐帧确认射线真的命中目标。Layer Mask 只勾选障碍物、车辆、行人。射线组件的起点放在底盘中心不要放在车座或车把位置。我习惯给路面单独设一层并把该层从 ray mask 排除否则地面会在很近距离内产生无效命中。5.3 训练速度慢到怀疑人生观测维度和batch互相顶着现象GPU 占用不高但每小时只能推进几万步训练曲线迟迟不出来。原因观测维度被堆得太高射线也上了几十根。更常见的是batch_size和buffer_size设得不匹配比如 buffer_size 设 100 万而 batch_size 只有 128每轮更新都要从巨大的 buffer 里采样数据搬运花费的时间远超计算时间。解决先把观测砍到必要的量射线 7 根最多 9 根。batch_size调成 buffer 的十六分之一左右buffer_size控制在 4096 到 8192。再检查是不是开了过多的 Unity 调试 UI训练时把 Game 视图的解析度调低或者直接用打包出来的 exe 训练。5.4 群体里两辆自行车互相顶住谁也不让现象训练后期两辆车面对面停住用鼠标看它俩就是不转弯。奖励曲线停在一个低水平不涨。原因碰撞惩罚只在碰撞发生时生效但两辆车保持安全距离对峙时谁动谁吃亏两者的惩罚梯度相同模型学到的策略就是“不动”。解决给“相对前进步”加惩罚具体可以在奖励里判断若最近邻居距离变近且自车横向速度接近零就扣分。更有效的是把碰撞判定改成双方各扣分扣得重一些并且追加“超过多少步还没越过中点”的回合级惩罚。这样模型会发现“一直堵着”比“绕一步走”更亏就会开始寻找绕行路径。5.5 编辑器里跑得好好的导出模型后一运行就发疯现象训练模式下一切都好把.onnx模型放进 Behavior Parameters 的 Model 字段后自行车开始画龙或直冲障碍。原因推理时观测输入和训练时不一致。比如训练时传感器顺序是“射线 向量”导出后你把行为参数里的传感器顺序改了或者向量观测里混进了 Debug 用的数据又或者normalize:true在训练侧做了归一化但推理时模型没有拿到对应参数。解决保持行为参数的观测配置完全一致改观测前先看代码里 AddObservation 的顺序。训练完成后把.onnx放入 Unity然后用和训练完全相同的场景设置跑一遍。如果编辑器内正常只有打包后异常检查是不是通过可执行文件启动时把--num-envs设成了多个导致时间步不同步。我会在项目里养一个习惯每次改动观测就改 Behavior Name比如从BikeAgent改成BikeAgent_v2从根上杜绝旧模型被误用。6. 验证一个“会自主导航”的自行车模型评估场景与落地扩展6.1 用固定种子跑一轮场景矩阵而不是肉眼盯着看训练完成后别急着说“模型会自主导航”。我一般固定随机种子准备四类评估场景空旷直行、城市路口、密集车流、雾天低能见度。每种场景下跑 20 个回合统计三个指标任务完成率、平均碰撞次数、平均骑行时间。这个场景矩阵要和训练场景稍微有差别否则你只是在验证模型背题而不是验证泛化。# 评估模式不更新策略只记录 rollout 的分值 mlagents-learn config/bike_ppo.yaml \ --run-idbike_nav_eval \ --resume \ --envbuild/BikeSim_Eval.x86_64 \ --num-envs4--resume用来加载已经训好的模型去掉--train后训练器只采样不更新策略。如果曲线和训练时差不多说明模型泛化还可以。我更推荐把统计逻辑直接写进 Unity 侧的自定义脚本在每个回合结束时分门别类地写 CSV。这样评估不依赖训练器的日志将来接实体车也可以直接用同一套脚本评估。6.2 从仿真系统走到机器人本体的三个扩展方向仿真系统做出来不是只为了看一眼动画。第一个扩展是把训练好的策略导出成.onnx接到 ROS 小车或自行车机器人实体上做 sim-to-real。常见做法是在训练阶段加入 domain randomization把车身质量、路面摩擦、传感器噪声全部随机化让模型对真实世界的差异不再敏感。第二个扩展是把多智能体强化学习的结论用到交通流控制上比如统计不同车流密度下群体的平均拥堵时长反推红绿灯配时方案这个方向比单车避障更有研究价值。第三个扩展是把它做成一个可复用的仿真测试平台用来验证其他控制算法比如 MPC 或传统路径规划在同样复杂交通环境里的表现让强化学习模型当对照组。我自己做这类项目时养成的习惯是每改一次观测或奖励就截图留下一版 TensorBoard 曲线。两个月后想反悔全靠run_id和这些截图找回现场。奖励结构不能三天两头乱改一次只改一个变量改完奖励就用同一组随机种子重新评估如果完成率变差说明这次改动引入的复杂度比收益大果断撤销。训练是黑匣子但你的实验记录可以让它不再装神弄鬼。希望帮到你。本文还有配套的精品资源点击获取
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

HowToCook 干锅花菜实战指南:湘味家常菜的标准化做法与火候原理 2026/10/2 21:02:12

HowToCook 干锅花菜实战指南:湘味家常菜的标准化做法与火候原理

文档教程 【免费下载链接】HowToCook Programmers guide about how to cook at home. 项目地址: https://gitcode.com/GitHub_Trending/ho/HowToCook 点击查看 免费下载 干锅花菜是一道湘味家常菜,以脆嫩干香的花菜搭配焦香四溢的五花肉为核心&#xff…

阅读更多 →
SnapOtter权限管理:RBAC角色、17种细粒度权限与API密钥范围完全指南 2026/10/2 21:01:59

SnapOtter权限管理:RBAC角色、17种细粒度权限与API密钥范围完全指南

SnapOtter权限管理:RBAC角色、17种细粒度权限与API密钥范围完全指南 【免费下载链接】SnapOtter Open-source, self-hosted file-processing tool. Convert, compress, OCR, transcribe & run local AI across image, video, audio, PDF & documents, via UI, REST API…

阅读更多 →
FreeRTOS 实战教程-第一章 2026/10/2 21:01:59

FreeRTOS 实战教程-第一章

第一章 FreeRTOS 基础与 CubeIDE 配置 1.1 从裸机到多任务:为什么要用 RTOS 先回顾一下我们写过的 9 个裸机工程,它们几乎都是同一种结构 —— 超级循环(Super Loop): int main(void) {HAL_Init(); /* 各种初始化 */SystemClock_Config();MX_GPIO_Init()…

阅读更多 →
单视频三维重构与无人机蜂群协同侦察阵地态势融合技术白皮书 2026/10/2 21:01:59

单视频三维重构与无人机蜂群协同侦察阵地态势融合技术白皮书

1. 摘要现代化阵地攻防作战呈现立体化、全域化、快节奏、高对抗发展趋势,传统二维视频监控、单机侦察、空地独立感知的态势体系已无法满足全天候、无盲区、连续化的战备感知需求。地面固定视频监控存在维度单一、纵深不足、遮挡盲区泛滥、立体态势缺失等短板&#x…

阅读更多 →
《动手学深度学习》Adadelta 优化算法全解:无需学习率的自适应梯度方法(d2l-zh) 2026/10/2 21:01:59

《动手学深度学习》Adadelta 优化算法全解:无需学习率的自适应梯度方法(d2l-zh)

人工智能深度学习机器学习教程 【免费下载链接】d2l-zh 《动手学深度学习》:面向中文读者、能运行、可讨论。中英文版被70多个国家的500多所大学用于教学。 项目地址: https://gitcode.com/GitHub_Trending/d2/d2l-zh 点击查看 免费下载 Adadelta 是 Ad…

阅读更多 →
南昌市热门的老板桌源头工厂排名及服务好的定制厂家推荐汇总 鑫恒家具 2026/10/2 21:01:59

南昌市热门的老板桌源头工厂排名及服务好的定制厂家推荐汇总 鑫恒家具

南昌选老板桌不想踩坑?这篇源头工厂挑选干货值得看完开篇导语: 老板桌(班台)是办公室里最能体现企业形象的一件家具,但市面上产品鱼龙混杂:板材异味重、封边开裂、大桌进不了电梯、售后没人管……在南昌,江西省鑫恒家具有限公司(…

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞 ✉