类内调用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
相关产品推荐
相关产品推荐

