You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

类内调用Simulator::AdvanceTo触发Meshcat WebSocket线程失败求助

问题:Drake模拟器在回调函数中调用AdvanceTo触发WebSocket线程错误

代码背景

头文件变量声明

drake::systems::DiagramBuilder<double> builder_;
std::unique_ptr< MultibodyPlant< double > plant_;
drake::multibody::MultibodyPlant<double>* plant_{};
drake::geometry::SceneGraph<double>* scene_graph_{};

std::unique_ptr<drake::systems::Diagram<double>> diagram_;
std::unique_ptr<drake::systems::Context<double>> diagram_context_;
drake::systems::Context<double> *plant_context_;
std::unique_ptr<drake::systems::Simulator<double>> simulator_;

double timestep_;
double time_;

源文件初始化代码

drake::multibody::MultibodyPlantConfig plant_config;
plant_config.time_step = 1e-3;

std::tie(plant_, scene_graph_) = AddMultibodyPlant(plant_config,&builder_);

const std::string urdf = drake::FindResourceOrThrow("drake/urdf/iiwa_description/urdf/iiwa14_no_collision.urdf");
    
drake::multibody::Parser(plant_).AddModelFromFile(urdf);

const double static_friction = 0.5;
const Eigen::Matrix<double, 4, 1> green(0.5, 1.0, 0.5, 1.0);
plant_->RegisterVisualGeometry(plant_->world_body(), drake::math::RigidTransformd(),
                                drake::geometry::HalfSpace(), "GroundVisualGeometry", green);
    
// For a time-stepping model only static friction is used.
const drake::multibody::CoulombFriction<double> ground_friction(static_friction,
                                                                    static_friction);

plant_->RegisterCollisionGeometry(plant_->world_body(), RigidTransformd(),
                                    drake::geometry::HalfSpace(),
                                    "GroundCollisionGeometry", ground_friction);

Vector3d gravity;
gravity << 0.0, 0.0, -9.81;
plant_->mutable_gravity_field().set_gravity_vector(gravity);

plant_->WeldFrames(plant_->world_frame(), plant_->GetFrameByName("base"));
plant_->Finalize();
plant_->set_penetration_allowance(1e-3);
plant_->set_stiction_tolerance(1e-3);

// Publish contact results for visualization.
drake::visualization::AddDefaultVisualization(&builder_);

  
diagram_ = builder_.Build();

// Create a context for this system:
diagram_context_ = diagram_->CreateDefaultContext();
drake::systems::Context<double>& plant_context = diagram_->GetMutableSubsystemContext(*plant_, diagram_context_.get());

plant_context_ = &(diagram_->GetMutableSubsystemContext(*plant_, diagram_context_.get()));
    
Eigen::VectorXd tau = Eigen::VectorXd::Zero(plant_->num_actuated_dofs());
plant_->get_actuation_input_port().FixValue(plant_context_, tau);
    
simulator_ = std::make_unique<drake::systems::Simulator<double>>(*diagram_, std::move(diagram_context_));
simulator_->set_publish_every_time_step(true);
simulator_->set_target_realtime_rate(1.0);
simulator_->Initialize();

timestep_ = 1e-3;
time_ = timestep_;

simulator_->AdvanceTo(time_);

问题现象

初始化函数中调用simulator_->AdvanceTo(time_)可正常运行,但在回调函数中调用该方法时触发错误:

abort: Failure at geometry/meshcat.cc:606 in ThrowIfWebsocketThreadExited(): condition 'IsThread(main_thread_id_)' failed.

解决建议

  • 核心原因:线程亲和性约束:Drake的Meshcat可视化模块要求WebSocket相关操作必须在创建它的主线程执行,回调函数通常运行在非主线程,违反此约束导致报错。
  • 方案1:将回调操作转移到主线程:通过消息队列、信号槽或线程调度机制,把simulator_->AdvanceTo()的调用转移到主线程执行,确保所有涉及模拟器推进、可视化的操作都在主线程完成。
  • 方案2:临时禁用Meshcat可视化:如果仅需调试核心逻辑,可修改可视化添加代码禁用Meshcat,绕过WebSocket线程限制:
    drake::visualization::AddDefaultVisualization(&builder_, {.enable_meshcat = false});
    
  • 方案3:检查主线程生命周期:确保主线程在回调执行期间未提前退出,WebSocket线程依赖主线程存活,主线程退出会导致其异常终止。
  • 方案4:保证对象线程安全:Drake的Simulator、Context等对象并非线程安全,禁止在多个线程同时操作,所有修改或推进操作必须在同一线程(主线程)执行。

内容的提问来源于stack exchange,提问作者Murt

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.01 20:20:55