首页 > 其他分享 >OCS2_mobile_manipulator案例详解

OCS2_mobile_manipulator案例详解

时间:2024-06-21 15:43:23浏览次数:12  
标签:std reset manipulator const MPC mobile _. OCS2 mpc

1. 启动

共启动3个节点

mobile_manipulator_mpc_node //mpc问题构建,计算
mobile_manipulator_dummy_mrt_node  //仿真,承接MPC的输出,发布Observation, 对于仿真来讲,状态发布也是反馈
mobile_manipulator_target  //交互发布target

2. MobileManipulatorMpcNode.cpp

MobileManipulatorInterface interface(taskFile, libFolder, urdfFile);  //问题构建
auto rosReferenceManagerPtr = std::make_shared<ocs2::RosReferenceManager>(robotName, interface.getReferenceManagerPtr()); //目标点接收在这里
ocs2::GaussNewtonDDP_MPC mpc(interface.mpcSettings(), interface.ddpSettings(), interface.getRollout(), 
                               interface.getOptimalControlProblem(), interface.getInitializer());  //DDP
MPC_ROS_Interface mpcNode(nodeHandle,mpc, robotName);  //MPC线程

3. MobileManipulatorInterface.cpp

MobileManipulatorInterface::MobileManipulatorInterface
{
  //一些初始化
  //pinocchio接口,这里注意一下,createPinocchioInterface会把底盘的x,y,theta,这三个自由度作为一个复合joint加入到pinocchio模型中
  pinocchioInterfacePtr_.reset(new PinocchioInterface(createPinocchioInterface(urdfFile, modelType, removeJointNames)));  
  manipulatorModelInfo_ = mobile_manipulator::createManipulatorModelInfo(*pinocchioInterfacePtr_, modelType, baseFrame, eeFrame);
  ddpSettings_ = ddp::loadSettings(taskFile, "ddp");  //从文件里读取配置参数
  mpcSettings_ = mpc::loadSettings(taskFile, "mpc");
  referenceManagerPtr_.reset(new ReferenceManager);  

  //问题构建:
  //二次输入型cost
  problem_.costPtr->add("inputCost", getQuadraticInputCost(taskFile));
  //关节限位约束
  problem_.softConstraintPtr->add("jointLimits", getJointLimitSoftConstraint(*pinocchioInterfacePtr_, taskFile));
  //末端约束
  problem_.stateSoftConstraintPtr->add("endEffector", getEndEffectorConstraint(*pinocchioInterfacePtr_, taskFile, "endEffector",
                                                                               usePreComputation, libraryFolder, recompileLibraries));
  //最终末端约束
  problem_.finalSoftConstraintPtr->add("finalEndEffector", getEndEffectorConstraint(*pinocchioInterfacePtr_, taskFile, "finalEndEffector",
                                                                                    usePreComputation, libraryFolder, recompileLibraries));
  //自碰撞约束
  problem_.stateSoftConstraintPtr->add(
        "selfCollision", getSelfCollisionConstraint(*pinocchioInterfacePtr_, taskFile, urdfFile, "selfCollision", usePreComputation,
                                                    libraryFolder, recompileLibraries));.
  //运动学
  problem_.dynamicsPtr.reset(
          new WheelBasedMobileManipulatorDynamics(manipulatorModelInfo_, "dynamics", libraryFolder, recompileLibraries, true));
  
  //预计算
  problem_.preComputationPtr.reset(new MobileManipulatorPreComputation(*pinocchioInterfacePtr_, manipulatorModelInfo_));

  //rollout
  rolloutPtr_.reset(new TimeTriggeredRollout(*problem_.dynamicsPtr, rolloutSettings));

  initializerPtr_.reset(new DefaultInitializer(manipulatorModelInfo_.inputDim));
}

末端约束

std::unique_ptr<StateCost> MobileManipulatorInterface::getEndEffectorConstraint(const PinocchioInterface& pinocchioInterface,
                                                                                const std::string& taskFile, const std::string& prefix,
                                                                                bool usePreComputation, const std::string& libraryFolder,
                                                                                bool recompileLibraries)
{
  
  if (usePreComputation) 
  {
    //MobileManipulatorPinocchioMapping和MobileManipulatorPinocchioMappingCppAd都是MobileManipulatorPinocchioMappingTpl,类型不一样而已
    //MobileManipulatorPinocchioMappingTpl继承PinocchioStateInputMapping,主要功能是定制获取关节位置,速度,雅可比
    MobileManipulatorPinocchioMapping pinocchioMapping(manipulatorModelInfo_);

    //主要功能是获取末端位置,速度,角度误差等接口
    PinocchioEndEffectorKinematics eeKinematics(pinocchioInterface, pinocchioMapping, {manipulatorModelInfo_.eeFrame});
    constraint.reset(new EndEffectorConstraint(eeKinematics, *referenceManagerPtr_));
  } 
  else 
  {
    MobileManipulatorPinocchioMappingCppAd pinocchioMappingCppAd(manipulatorModelInfo_);
    PinocchioEndEffectorKinematicsCppAd eeKinematics(pinocchioInterface, pinocchioMappingCppAd, {manipulatorModelInfo_.eeFrame},
                                                     manipulatorModelInfo_.stateDim, manipulatorModelInfo_.inputDim,
                                                     "end_effector_kinematics", libraryFolder, recompileLibraries, false);
    constraint.reset(new EndEffectorConstraint(eeKinematics, *referenceManagerPtr_));
  }
  std::vector<std::unique_ptr<PenaltyBase>> penaltyArray(6);
  std::generate_n(penaltyArray.begin(), 3, [&] { return std::make_unique<QuadraticPenalty>(muPosition); });
  std::generate_n(penaltyArray.begin() + 3, 3, [&] { return std::make_unique<QuadraticPenalty>(muOrientation); });

  return std::make_unique<StateSoftConstraint>(std::move(constraint), std::move(penaltyArray));
}

4. MPC_ROS_interface.cpp

//构造函数主要创建了观测的订阅和mpc结果的发布,以及mpc的reset
MPC_ROS_Interface()
{
  // Observation subscriber
  mpcObservationSubscriber_ = nodeHandle_->create_subscription<ocs2_msgs::msg::MpcObservation>(topicPrefix_ + "_mpc_observation", 1, std::bind(&MPC_ROS_Interface::mpcObservationCallback, this, std::placeholders::_1));

  // MPC publisher
  mpcPolicyPublisher_ = nodeHandle_->create_publisher<ocs2_msgs::msg::MpcFlattenedController>(topicPrefix_ + "_mpc_policy", 1);

  // MPC reset service server
  mpcResetServiceServer_ = nodeHandle_->create_service<ocs2_msgs::srv::Reset>(topicPrefix_ + "_mpc_reset", std::bind(&MPC_ROS_Interface::resetMpcCallback, this, std::placeholders::_1,std::placeholders::_2));

  // start thread for publishing
#ifdef PUBLISH_THREAD
  publisherWorker_ = std::thread(&MPC_ROS_Interface::publisherWorker, this);
#endif
}
void MPC_ROS_Interface::mpcObservationCallback(const std::shared_ptr<ocs2_msgs::msg::MpcObservation> msg)
{
  //启动MPC
  bool controllerIsUpdated = mpc_.run(currentObservation.time, currentObservation.state);
  copyToBuffer(currentObservation);
}
ocs2_msgs::msg::MpcFlattenedController MPC_ROS_Interface::createMpcPolicyMsg(const PrimalSolution& primalSolution,
                                                                          const CommandData& commandData,
                                                                          const PerformanceIndex& performanceIndices) 
{
  ocs2_msgs::msg::MpcFlattenedController mpcPolicyMsg; //自定义topic类型,发布mpc相关计算

  uint8                   controller_type         # what type of controller is this
  MpcObservation         init_observation        # plan initial observation
  MpcTargetTrajectories plan_target_trajectories # target trajectory in cost function
  MpcState[]             state_trajectory        # optimized state trajectory from planner
  MpcInput[]             input_trajectory        # optimized input trajectory from planner
  float64[]               time_trajectory         # time trajectory for stateTrajectory and inputTrajectory
  uint16[]                post_event_indices       # array of indices indicating the index of post-event time in the trajectories
  ModeSchedule           mode_schedule           # optimal/predefined MPC mode sequence and event times
  ControllerData[]       data                   # the actual payload from flatten method: one vector of data per time step
  MpcPerformanceIndices performance_indices     # solver performance indices
  
  //填充数据
  mpcPolicyMsg.time_trajectory = primalSolution.timeTrajectory_;
  mpcPolicyMsg.post_event_indices = primalSolution.postEventIndices_;
  mpcState.value = primalSolution.stateTrajectory_;
  mpcInput.value[j] = primalSolution.inputTrajectory_
  mpcPolicyMsg.data.emplace_back(ocs2_msgs::msg::ControllerData());
  primalSolution.controllerPtr_->flatten(timeTrajectoryTruncated, policyMsgDataPointers);
}

5. GaussNewtonDDP.cpp

void GaussNewtonDDP::runImpl(scalar_t initTime, const vector_t& initState, scalar_t finalTime)
{
  // set cost desired trajectories
  for (auto& ocp : optimalControlProblemStock_) {
    ocp.targetTrajectoriesPtr = &this->getReferenceManager().getTargetTrajectories();
  }
  initializeConstraintPenalties();  // initialize penalty coefficients
  bool initialSolutionExists = initializePrimalSolution();  // true if the rollout is not purely from the Initializer
  initializeDualSolutionAndMetrics();
  // DDP main loop
  while (true) 
  {
    //constructs the LQ problem around the nominal trajectories
    approximateOptimalControlProblem();
    //solves the LQ problem
    avgTimeStepBP_ = solveSequentialRiccatiEquations(nominalPrimalData_.modelDataFinalTime.cost);
    //calculate controller and store the result in unoptimizedController_
    calculateController();
    //based on the current LQ solution updates the optimized primal and dual solutions
    //更新原始解和对偶解,运行搜索策略来找到最佳步长,搜索成功后更新对偶解
    takePrimalDualStep(lqModelExpectedCost);
    // check convergence
    std::tie(isConverged, convergenceInfo) = searchStrategyPtr_->checkConvergence(
        !initialSolutionExists, *std::prev(performanceIndexHistory_.end(), 2), performanceIndexHistory_.back());
    //条件完成
    if (isConverged || (totalNumIterations_ - initIteration) == ddpSettings_.maxNumIterations_) 
    {
      break;
    }
    else
    {
      // update the constraint penalty coefficients
      updateConstraintPenalties(performanceIndex_.equalityConstraintsSSE);
    }
  }  
}

approximateOptimalControlProblem()

void GaussNewtonDDP::approximateOptimalControlProblem()
{
  //对最优化问题进行二次近似,dynamics,cost,Equality constraints,Lagrangians
  approximateIntermediateLQ(nominalDualData_.dualSolution, nominalPrimalData_);
  //对过程cost进行二次近似
  while ((timeIndex = nextTimeIndex_++) < NE)
  {
    ocs2::approximatePreJumpLQ(optimalControlProblemStock_[taskId], time, state, multiplier, modelData);
  }
  //对终端cost进行近似
  modelData = ocs2::approximateFinalLQ(optimalControlProblemStock_[0], time, state, multiplier);
}

solveSequentialRiccatiEquations()

scalar_t SLQ::solveSequentialRiccatiEquations(const ScalarFunctionQuadraticApproximation& finalValueFunction) 
{
  const size_t N = nominalPrimalData_.primalSolution.timeTrajectory_.size();

  nominalDualData_.riccatiModificationTrajectory.resize(N);
  nominalDualData_.projectedModelDataTrajectory.resize(N);

  if (N > 0) {
    // perform the computeRiccatiModificationTerms for partition i
    nextTimeIndex_ = 0;
    nextTaskId_ = 0;
    auto task = [this, N]() {
      int timeIndex;
      const matrix_t SmDummy = matrix_t::Zero(0, 0);

      // get next time index is atomic
      while ((timeIndex = nextTimeIndex_++) < N) {
        computeProjectionAndRiccatiModification(nominalPrimalData_.modelDataTrajectory[timeIndex], SmDummy,
                                                nominalDualData_.projectedModelDataTrajectory[timeIndex],
                                                nominalDualData_.riccatiModificationTrajectory[timeIndex]);
      }
    };
    runParallel(task, settings().nThreads_);
  }

  return solveSequentialRiccatiEquationsImpl(finalValueFunction);
}

computeProjectionAndRiccatiModification()

void GaussNewtonDDP::computeProjectionAndRiccatiModification(const ModelData& modelData, const matrix_t& Sm, ModelData& projectedModelData,riccati_modification::Data& riccatiModification) const 
{
  // compute the Hamiltonian's Hessian
  riccatiModification.time_ = modelData.time;
  riccatiModification.hamiltonianHessian_ = computeHamiltonianHessian(modelData, Sm);

  //计算约束投影 
  computeProjections(riccatiModification.hamiltonianHessian_, modelData.stateInputEqConstraint.dfdu,
                     riccatiModification.constraintRangeProjector_, riccatiModification.constraintNullProjector_);

  // 通过投影来转换LQ模型数据,考虑状态输入等式约束
  projectLQ(modelData, riccatiModification.constraintRangeProjector_, riccatiModification.constraintNullProjector_,         projectedModelData);

  // compute deltaQm, deltaGv, deltaGm
  searchStrategyPtr_->computeRiccatiModification(projectedModelData, riccatiModification.deltaQm_, riccatiModification.deltaGv_,riccatiModification.deltaGm_);
}

标签:std,reset,manipulator,const,MPC,mobile,_.,OCS2,mpc
From: https://www.cnblogs.com/penuel/p/18237546

相关文章

  • 斯坦福大学Mobile ALOHA——一款革命性的家政机器人
    https://www.bilibili.com/video/BV1nT421e7Cy/?spm_id_from=333.999.0.0随着社会老龄化问题的加剧,家政机器人成为了解决日常生活辅助需求的新方向。欢迎来了解MobileAloha家政机器人的技术原理和潜力——它将把你的家务活变成轻而易举的事。推动这款机器人功能的技术特点包......
  • ChallengeMobile
    解题思路获取到输入的字符串保存到s,调用Jformat方法对s进行验证,返回true则代表输入字符串正确反之错误。Jformat方法分析:首先看到使用了LoadData加载了”ming“给了a方法,a方法的返回值赋值给了arr_b。接着判断SDK_INT是否小于29:意思就是判断Android版本是否小于10,如果不是......
  • YOLOv8 更换骨干网络之 MobileNetV3 详解
    鱼弦:公众号【红尘灯塔】,CSDN博客专家、内容合伙人、新星导师、全栈领域优质创作者、51CTO(Top红人+专家博主)、github开源爱好者(go-zero源码二次开发、游戏后端架构https://github.com/Peakchen)YOLOv8更换骨干网络之MobileNetV3详解1.MobileNetV3简介MobileNetV3......
  • 深度学习项目-MobileNetV2水果识别模型
    FruitRecognitionDeepLearning深度学习小项目,利用CNN和MobileNetV2搭建的水果识别模型。github地址fruit为本次大作业使用的数据集。geneFruit为数据增强后的数据集。FruitRecognition为本次大作业相关代码及相关曲线热力图。项目使用conda环境进行训练,相关测试版本如下:......
  • Offline web technology for Mobile devices
    一、当前问题1、弱网或断网,当用户进入电梯或无网区,长时间白屏或无法显示页面2、正常网络,从点击app到显示首页文字图片,白屏时间大约7-9秒 二、原因分析1、从技术视角,分析一下网页启动的几个关键耗时阶段 2、没有做离线化技术,而手机端用户进入弱网与无网区......
  • 基于开源IM即时通讯框架MobileIMSDK:RainbowChat v11.5版已发布
    关于MobileIMSDKMobileIMSDK是一套专门为移动端开发的开源IM即时通讯框架,超轻量级、高度提炼,一套API优雅支持UDP 、TCP 、WebSocket 三种协议,支持iOS、Android、H5、小程序、Uniapp、标准Java平台,服务端基于Netty编写。工程开源地址是:1)Gitee码云地址:https://gitee.com/ja......
  • 轻量化网络——MobileNet
    原文链接:https://zhuanlan.zhihu.com/p/402766063作为轻量化网络的经典网络,MobileNet自诞生就被广泛应用于工业界。笔者也经常在结构设计中使用MobileNet的诸多设计思想。本文参考众多大神文章,较详细介绍MobileNet系列的设计及改进思想,力求温故知新,举一反三。MobileNetV1Mobil......
  • SciTech-EE-Mobile-OTG: 切换Host与Device角色由手机USB接口取电为外部设备供电的方法
    SciTech-EE-Mobile-OTG:由手机USB接口取电为外部设备供电的方法OTG接口与转换器OTG是"OnTheGo"的英文缩写,字面上可以理解为“安上即可用”。USB传输是Host-Device的主从结构,一切USB传输都有Host发起:比如:在开发板上插入U盘,这时开发板作为USBHost;但开发板插在PC上,开发板......
  • 基于开源IM即时通讯框架MobileIMSDK:RainbowChat-iOS端v9.0版已发布
    关于MobileIMSDKMobileIMSDK是一套专门为移动端开发的开源IM即时通讯框架,超轻量级、高度提炼,一套API优雅支持 UDP 、TCP 、WebSocket 三种协议,支持 iOS、Android、H5、标准Java、小程序、Uniapp,服务端基于Netty编写。工程开源地址是:1)Gitee码云地址:https://gitee.com/ja......
  • NVIDIA人形机器人AI套件:NVIDIA Isaac Manipulator 和 NVIDIA Isaac Perceptor
    IsaacManipulator为机械臂提供了卓越的灵活性和模块化AI功能,并提供了一系列强大的基础模型和GPU加速库。它提供了高达80倍的路径规划加速,零样本感知提高了效率和吞吐量,使开发者能够实现更多新的机器人任务的自动化。早期生态系统合作伙伴包括安川电机、泰瑞达旗下子公司优傲、Pic......