Skip to content
This repository was archived by the owner on Dec 3, 2025. It is now read-only.

add fire_controller#12

Merged
AlrayQiu merged 60 commits intomainfrom
tongji-dev
Oct 13, 2025
Merged

add fire_controller#12
AlrayQiu merged 60 commits intomainfrom
tongji-dev

Conversation

@heyeuu
Copy link
Copy Markdown
Member

@heyeuu heyeuu commented Oct 9, 2025

完成了火控的主要逻辑,其余再瞅瞅
需要注意的:

  1. 一些变量需要在每帧及时更新,但不方便直接传入,我将其作为类的成员函数,提供了Set函数,需要及时更新,such as:
FireController fire_controller{
private:
    gimbal_pos_
}
Decider{
private:
    std::unordered_set<ArmorId> invincible_armor_;//刚复活处于无敌状态的装甲板
}

2.不清楚是否足够解耦?模块提供了类似于Update的函数。一些其他的逻辑,稍后会重理一理,毕竟至少现在比之前更理解一些。先看看,怼个进度
3.有问题直接和我说哈(≧ω≦)

heyeuu and others added 30 commits September 1, 2025 14:37
- Return armor_id from input armor_pattern
…nterface implements to be read-only and immutable.
Note: The implement of ITargetPredictor interface is not fully implemented yet.
heyeuu added 16 commits October 3, 2025 04:34
- fire_judge → fire_decision
- gimble_angle_solver → aim_solver
- Improve fire validation and decision process
- State Machine: add convergence detection logic
- LiveTargetManager: implement add/remove operations for LiveTarget
- IdentifiedArmor: add GetDetectedIDs() method for ID retrieval
- Tracker: complete state update logic implementation
- FireControl: add reset function for SnapshotManager
Replace runtime type checks with templates for better performance.
@heyeuu heyeuu requested a review from AlrayQiu October 10, 2025 01:54
@AlrayQiu
Copy link
Copy Markdown
Contributor

  1. 由于实现类之间耦合了
    IMG_20251010_145039
    所以FireControl实际上是一个包含了 ICarState,IFireControl,ITargetPredictor的超级大类

但是你写的时候按照左边图中来组织,导致更新的函数是FireController类特有的,因此外部对于你的类需要特化实现
在fire_controller中 有这两个点

    void UpdateIdentifiedArmors(std::shared_ptr<interfaces::IArmorInImage> armors);
    void UpdateGimbalPosition(const Eigen::Vector3d& gimbal_pos);

可以直接在FireControl继承这三个接口来解决问题

LiveTarget 和 CarState之间也有类似的问题,可以举一反三一下

  1. UpdateGimbalPosition(const Eigen::Vector3d& gimbal_pos);在IUpdatePackage中可以获取,而且这个参数只用了第一个分量,有点理解不能,可以补下注释

3.Time Stamped 不应该通过设置的,而是直接从IUpdatePackage中拿到,之前的版本如果写了个Set的话那就大概是神志不清胡言乱语了


低三点一定要改,第一第二不想改也行,我后面Merge的时候顺手加上那三个接口也不会很其他部分以及测试

void UpdateIdentifiedArmors(std::shared_ptr<interfaces::IArmorInImage> armors);
void UpdateGimbalPosition(const Eigen::Vector3d& gimbal_pos);

void SetTimeStamp(const std::time_t& time_stamp);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TimeStamp 从IUpdatePackge直接获取,要与传感器同时

@heyeuu
Copy link
Copy Markdown
Member Author

heyeuu commented Oct 11, 2025

关于FireController耦合:
目前,在FireController中:

class FireController::Impl {
public:
    Impl(std::shared_ptr<StateMachine> state_machine, bool auto_fire,
        const double& control_delay_in_second, const double& bullet_speed, double yaw_offset,
        double pitch_offset)
        : control_delay_(control_delay_in_second)
        , bullet_speed_(bullet_speed)
        , tracker_(std::make_unique<Tracker>())
        , aim_solver_(std::make_unique<AimingSolver>(bullet_speed, yaw_offset, pitch_offset))
        , fire_decision_(std::make_unique<FireDecision>(auto_fire))
        , live_target_manager_(std::make_shared<LiveTargetManager>(state_machine)) { }
}

FireController中依赖了ITargetPredictor的具体实现类LiveTargetManager,而LiveTargetManager又依赖了ICarState的具体实现,这才造成了耦合。然后在实现中,本希望模仿观察者模式,及时地通知ICarState的具体实现类,但好像成了东施效颦邯郸学步了。

对此,我目前的想法是:
ITargetPredictor应该作为ICarState的依赖,就像这样:

class StateMachine : public world_exe::interfaces::ICarState{
public:
    // 依赖注入:通过构造函数接收 ITargetPredictor 接口
    TargetManager(std::shared_ptr<world_exe::interfaces::ITargetPredictor> predictor)
        : predictor_(std::move(predictor)) {
      ...
    }

  // 实现 ICarState 接口的核心方法
    const enumeration::CarIDFlag& GetAllowdToFires() const override{
//在这里调用ITargetPredictor的方法isConverged()来
     if (predictor_->isConverged(id)) {
         ...
         return   id;   
      }
}
private:
 std::shared_ptr<world_exe::interfaces::ITargetPredictor> predictor_;
}

而FireController呢,依赖ICarState,就像这样:

class FireControl::public interfaces::IFireControl{
public:
      const data::FireControl CalculateTarget(const TimePoint& current_timestamp) override{
      //通过ICarState的方法可以获得来获得预测器预测收敛的id
      auto converged_cars=car_state_manager_->GetAllowdToFires();
      //接下来需要进行飞行时间的迭代预测,需要IPredictor
     //TODO:** 如何获得 IPredictor? **
}
private:
      std::shared_ptr<world_exe::interfaces::ICarState> car_state_manager_;
}

现在需要解决的问题是获得IPredictor来迭代飞行时间,解决了这个问题就能得到最终火控的指令了
在现有接口的基础上,ITargetPredictor 可以通过这个函数

     * @brief 按照传入的id生成IPredictor
     *
     * @param id
     * @return const IPredictor&
     */
    virtual std::shared_ptr<IPredictor> GetPredictor(const enumeration::ArmorIdFlag& id) const = 0;

来获得IPredictor
即在FireControl中调用GetPredictor(),但这仍需要依赖ITargetPredictor
那先假设需要在FireControl中依赖ITargetPredictor
那就可以这样写

class FireControl::public interfaces::IFireControl{
public:
      const data::FireControl CalculateTarget(const TimePoint& current_timestamp) override{
      //通过ICarState的方法可以获得来获得预测器预测收敛的id
      auto converged_cars=car_state_manager_->GetAllowdToFires();
      auto snapshot=  predictor_-> GetPredictor(converged_cars);
     //之后将snapshot扔进其他类,如AimingSolver进行飞行时间的迭代等,拿去给生产控制指令的类使用,这些属于具体的算法实现了,先省略,更细节得写写
}
private:
      std::shared_ptr<world_exe::interfaces::ICarState> car_state_manager_;
      std::shared_ptr<world_exe::interfaces::ITargetPredictor> predictor_;
}

这样姿,感觉就更解耦一些吧(吗?),缺点是,好像IFireControl依赖了ITargetPredictor和ICarState,但是ICarState也依赖了ITargetPredictor,有点重复的感觉,有点怪就是了

目前我是这个想法

@AlrayQiu
Copy link
Copy Markdown
Contributor

关于FireController耦合: 目前,在FireController中:

class FireController::Impl {
public:
    Impl(std::shared_ptr<StateMachine> state_machine, bool auto_fire,
        const double& control_delay_in_second, const double& bullet_speed, double yaw_offset,
        double pitch_offset)
        : control_delay_(control_delay_in_second)
        , bullet_speed_(bullet_speed)
        , tracker_(std::make_unique<Tracker>())
        , aim_solver_(std::make_unique<AimingSolver>(bullet_speed, yaw_offset, pitch_offset))
        , fire_decision_(std::make_unique<FireDecision>(auto_fire))
        , live_target_manager_(std::make_shared<LiveTargetManager>(state_machine)) { }
}

FireController中依赖了ITargetPredictor的具体实现类LiveTargetManager,而LiveTargetManager又依赖了ICarState的具体实现,这才造成了耦合。然后在实现中,本希望模仿观察者模式,及时地通知ICarState的具体实现类,但好像成了东施效颦邯郸学步了。

对此,我目前的想法是: ITargetPredictor应该作为ICarState的依赖,就像这样:

class StateMachine : public world_exe::interfaces::ICarState{
public:
    // 依赖注入:通过构造函数接收 ITargetPredictor 接口
    TargetManager(std::shared_ptr<world_exe::interfaces::ITargetPredictor> predictor)
        : predictor_(std::move(predictor)) {
      ...
    }

  // 实现 ICarState 接口的核心方法
    const enumeration::CarIDFlag& GetAllowdToFires() const override{
//在这里调用ITargetPredictor的方法isConverged()来
     if (predictor_->isConverged(id)) {
         ...
         return   id;   
      }
}
private:
 std::shared_ptr<world_exe::interfaces::ITargetPredictor> predictor_;
}

而FireController呢,依赖ICarState,就像这样:

class FireControl::public interfaces::IFireControl{
public:
      const data::FireControl CalculateTarget(const TimePoint& current_timestamp) override{
      //通过ICarState的方法可以获得来获得预测器预测收敛的id
      auto converged_cars=car_state_manager_->GetAllowdToFires();
      //接下来需要进行飞行时间的迭代预测,需要IPredictor
     //TODO:** 如何获得 IPredictor? **
}
private:
      std::shared_ptr<world_exe::interfaces::ICarState> car_state_manager_;
}

现在需要解决的问题是获得IPredictor来迭代飞行时间,解决了这个问题就能得到最终火控的指令了 在现有接口的基础上,ITargetPredictor 可以通过这个函数

     * @brief 按照传入的id生成IPredictor
     *
     * @param id
     * @return const IPredictor&
     */
    virtual std::shared_ptr<IPredictor> GetPredictor(const enumeration::ArmorIdFlag& id) const = 0;

来获得IPredictor, 即在FireControl中调用GetPredictor(),但这仍需要依赖ITargetPredictor 那先假设需要在FireControl中依赖ITargetPredictor 那就可以这样写

class FireControl::public interfaces::IFireControl{
public:
      const data::FireControl CalculateTarget(const TimePoint& current_timestamp) override{
      //通过ICarState的方法可以获得来获得预测器预测收敛的id
      auto converged_cars=car_state_manager_->GetAllowdToFires();
      auto snapshot=  predictor_-> GetPredictor(converged_cars);
     //之后将snapshot扔进其他类,如AimingSolver进行飞行时间的迭代等,拿去给生产控制指令的类使用,这些属于具体的算法实现了,先省略,更细节得写写
}
private:
      std::shared_ptr<world_exe::interfaces::ICarState> car_state_manager_;
      std::shared_ptr<world_exe::interfaces::ITargetPredictor> predictor_;
}

这样姿,感觉就更解耦一些吧(吗?),缺点是,好像IFireControl依赖了ITargetPredictor和ICarState,但是ICarState也依赖了ITargetPredictor,有点重复的感觉,有点怪就是了

目前我是这个想法


类关系设计没有问题,但是时许上可能无法实现

类图

@heyeuu
Copy link
Copy Markdown
Member Author

heyeuu commented Oct 11, 2025

关于FireController耦合: 目前,在FireController中:

class FireController::Impl {
public:
    Impl(std::shared_ptr<StateMachine> state_machine, bool auto_fire,
        const double& control_delay_in_second, const double& bullet_speed, double yaw_offset,
        double pitch_offset)
        : control_delay_(control_delay_in_second)
        , bullet_speed_(bullet_speed)
        , tracker_(std::make_unique<Tracker>())
        , aim_solver_(std::make_unique<AimingSolver>(bullet_speed, yaw_offset, pitch_offset))
        , fire_decision_(std::make_unique<FireDecision>(auto_fire))
        , live_target_manager_(std::make_shared<LiveTargetManager>(state_machine)) { }
}

FireController中依赖了ITargetPredictor的具体实现类LiveTargetManager,而LiveTargetManager又依赖了ICarState的具体实现,这才造成了耦合。然后在实现中,本希望模仿观察者模式,及时地通知ICarState的具体实现类,但好像成了东施效颦邯郸学步了。
对此,我目前的想法是: ITargetPredictor应该作为ICarState的依赖,就像这样:

class StateMachine : public world_exe::interfaces::ICarState{
public:
    // 依赖注入:通过构造函数接收 ITargetPredictor 接口
    TargetManager(std::shared_ptr<world_exe::interfaces::ITargetPredictor> predictor)
        : predictor_(std::move(predictor)) {
      ...
    }

  // 实现 ICarState 接口的核心方法
    const enumeration::CarIDFlag& GetAllowdToFires() const override{
//在这里调用ITargetPredictor的方法isConverged()来
     if (predictor_->isConverged(id)) {
         ...
         return   id;   
      }
}
private:
 std::shared_ptr<world_exe::interfaces::ITargetPredictor> predictor_;
}

而FireController呢,依赖ICarState,就像这样:

class FireControl::public interfaces::IFireControl{
public:
      const data::FireControl CalculateTarget(const TimePoint& current_timestamp) override{
      //通过ICarState的方法可以获得来获得预测器预测收敛的id
      auto converged_cars=car_state_manager_->GetAllowdToFires();
      //接下来需要进行飞行时间的迭代预测,需要IPredictor
     //TODO:** 如何获得 IPredictor? **
}
private:
      std::shared_ptr<world_exe::interfaces::ICarState> car_state_manager_;
}

现在需要解决的问题是获得IPredictor来迭代飞行时间,解决了这个问题就能得到最终火控的指令了 在现有接口的基础上,ITargetPredictor 可以通过这个函数

     * @brief 按照传入的id生成IPredictor
     *
     * @param id
     * @return const IPredictor&
     */
    virtual std::shared_ptr<IPredictor> GetPredictor(const enumeration::ArmorIdFlag& id) const = 0;

来获得IPredictor, 即在FireControl中调用GetPredictor(),但这仍需要依赖ITargetPredictor 那先假设需要在FireControl中依赖ITargetPredictor 那就可以这样写

class FireControl::public interfaces::IFireControl{
public:
      const data::FireControl CalculateTarget(const TimePoint& current_timestamp) override{
      //通过ICarState的方法可以获得来获得预测器预测收敛的id
      auto converged_cars=car_state_manager_->GetAllowdToFires();
      auto snapshot=  predictor_-> GetPredictor(converged_cars);
     //之后将snapshot扔进其他类,如AimingSolver进行飞行时间的迭代等,拿去给生产控制指令的类使用,这些属于具体的算法实现了,先省略,更细节得写写
}
private:
      std::shared_ptr<world_exe::interfaces::ICarState> car_state_manager_;
      std::shared_ptr<world_exe::interfaces::ITargetPredictor> predictor_;
}

这样姿,感觉就更解耦一些吧(吗?),缺点是,好像IFireControl依赖了ITargetPredictor和ICarState,但是ICarState也依赖了ITargetPredictor,有点重复的感觉,有点怪就是了
目前我是这个想法

类关系设计没有问题,但是时许上可能无法实现
类图

我没表述清就是了,我说的就是这个意思

- Reimplement predictor module with clear dependency boundaries
- Rewrite fire_control module to follow proper dependency injection
@AlrayQiu AlrayQiu merged commit 9d493d4 into main Oct 13, 2025
2 checks passed
AlrayQiu added a commit that referenced this pull request Oct 13, 2025
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants