Skip to content

Commit a2a4170

Browse files
committed
feat: add Steering4
1 parent 45332fb commit a2a4170

File tree

7 files changed

+514
-0
lines changed

7 files changed

+514
-0
lines changed

CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,5 @@ set(CMAKE_CXX_STANDARD_REQUIRED ON)
66

77
add_subdirectory(Core)
88
add_subdirectory(Mecanum4)
9+
add_subdirectory(Steering4)
910
add_subdirectory(Controller)

Steering4/CMakeLists.txt

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
add_library(ChassisSteering4 STATIC
2+
"./SteeringWheel.cpp"
3+
"./Steering4.cpp"
4+
)
5+
6+
target_include_directories(ChassisSteering4
7+
PUBLIC
8+
${CMAKE_CURRENT_SOURCE_DIR}
9+
)
10+
11+
# link dependencies if any
12+
target_link_libraries(ChassisSteering4 PUBLIC Chassis::Core)
13+
target_link_libraries(ChassisSteering4 PUBLIC FreeRTOS)
14+
target_link_libraries(ChassisSteering4 PUBLIC bsp::GPIO_Driver)
15+
16+
# alias for external use
17+
add_library(Chassis::Steering4 ALIAS ChassisSteering4)

Steering4/Steering4.cpp

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
/**
2+
* @file Steering4.cpp
3+
* @author syhanjin
4+
* @date 2026-02-28
5+
* @brief Brief description of the file
6+
*
7+
* Detailed description (optional).
8+
*
9+
*/
10+
#include "Steering4.hpp"
11+
12+
#include <cmath>
13+
14+
#define RAD2DEG(__RAD__) ((__RAD__) / 3.14159265358979323846f * 180)
15+
16+
namespace chassis
17+
{
18+
Steering4::Steering4(Config cfg, const IChassis::Config& base_cfg) :
19+
IChassis(base_cfg), enable_calib_(cfg.enable_calibration),
20+
wheel_radius_(1e-3f * cfg.radius), // mm to m
21+
half_distance_x(0.5f * cfg.distance_x), half_distance_y(0.5f * cfg.distance_y),
22+
inv_l2_(4.0f / (cfg.distance_x * cfg.distance_x + cfg.distance_y * cfg.distance_y)),
23+
spd2rpm_(1.0f / (wheel_radius_ * 3.14159265358979323846f * 2) * 60.0f), wheel_{
24+
steering::SteeringWheel(cfg.wheel_front_right.cfg,
25+
cfg.enable_calibration,
26+
cfg.wheel_front_right.calib_cfg),
27+
steering::SteeringWheel(cfg.wheel_front_left.cfg,
28+
cfg.enable_calibration,
29+
cfg.wheel_front_left.calib_cfg),
30+
steering::SteeringWheel(cfg.wheel_rear_left.cfg,
31+
cfg.enable_calibration,
32+
cfg.wheel_rear_left.calib_cfg),
33+
steering::SteeringWheel(cfg.wheel_rear_right.cfg,
34+
cfg.enable_calibration,
35+
cfg.wheel_rear_right.calib_cfg),
36+
}
37+
{
38+
}
39+
40+
void Steering4::applyVelocity(const Velocity& velocity)
41+
{
42+
if (enable_calib_ && !calibrated_)
43+
// 需要校准但未校准,无法设置速度
44+
return;
45+
for (size_t i = 0; i < static_cast<size_t>(WheelType::Max); ++i)
46+
{
47+
const auto [xi, yi] = getWheelPosition(static_cast<WheelType>(i));
48+
const float vxi = velocity.vx - velocity.wz * yi;
49+
const float vyi = velocity.vy + velocity.wz * xi;
50+
const float speed_rpm = spd2rpm_ * std::hypot(vxi, vyi);
51+
if (fabsf(speed_rpm) < 1e-6f)
52+
{
53+
// 速度为零,无须转向
54+
wheel_[i].setTargetVelocity({
55+
.angle = wheel_[i].getSteerAngle(),
56+
.speed = 0,
57+
});
58+
}
59+
else
60+
{
61+
const float angle = RAD2DEG(atan2f(vyi, vxi));
62+
wheel_[i].setTargetVelocity({ angle, speed_rpm });
63+
}
64+
}
65+
}
66+
void Steering4::velocityControllerUpdate()
67+
{
68+
if (enable_calib_ && !calibrated_)
69+
{
70+
// check calibration state
71+
bool calibrated = true;
72+
for (auto& w : wheel_)
73+
calibrated &= w.isCalibrated();
74+
calibrated_ = calibrated;
75+
}
76+
else
77+
{
78+
// 更新反馈速度
79+
float vx = 0, vy = 0, wz = 0;
80+
for (size_t i = 0; i < static_cast<size_t>(WheelType::Max); ++i)
81+
{
82+
const auto [xi, yi] = getWheelPosition(static_cast<WheelType>(i));
83+
const float steer_angle = wheel_[i].getSteerAngle();
84+
const float driver_speed = wheel_[i].getDriveSpeed() / spd2rpm_;
85+
const float steer_angle_rad = DEG2RAD(steer_angle);
86+
const float sin_theta = sinf(steer_angle_rad);
87+
const float cos_theta = cosf(steer_angle_rad);
88+
vx += driver_speed * cos_theta;
89+
vy += driver_speed * sin_theta;
90+
wz += -yi * cos_theta + xi * sin_theta;
91+
}
92+
velocity_.vx = 0.25f * vx;
93+
velocity_.vy = 0.25f * vy;
94+
velocity_.wz = inv_l2_ * wz;
95+
}
96+
97+
for (auto& w : wheel_)
98+
wheel_->update();
99+
}
100+
101+
Steering4::WheelPosition Steering4::getWheelPosition(WheelType wheel) const
102+
{
103+
constexpr WheelPosition WHEEL_POS[static_cast<size_t>(WheelType::Max)] = {
104+
{ 1, -1 }, { 1, 1 }, { -1, 1 }, { -1, -1 }
105+
};
106+
const auto [kx, ky] = WHEEL_POS[static_cast<size_t>(wheel)];
107+
return {
108+
kx * half_distance_x,
109+
ky * half_distance_y,
110+
};
111+
}
112+
} // namespace chassis

Steering4/Steering4.hpp

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
/**
2+
* @file Steering4.hpp
3+
* @author syhanjin
4+
* @date 2026-02-28
5+
* @brief Brief description of the file
6+
*
7+
* Detailed description (optional).
8+
*
9+
*/
10+
#pragma once
11+
#include "IChassis.hpp"
12+
#include "SteeringWheel.hpp"
13+
14+
namespace chassis
15+
{
16+
17+
class Steering4 : public IChassis
18+
{
19+
public:
20+
enum class WheelType : size_t
21+
{
22+
FrontRight = 0U, ///< 右前轮
23+
FrontLeft = 1U, ///< 左前轮
24+
RearLeft = 2U, ///< 左后轮
25+
RearRight = 3U, ///< 右后轮
26+
Max
27+
};
28+
struct Config
29+
{
30+
bool enable_calibration = false; // 是否启用校准功能
31+
32+
float radius; // 驱动轮半径 (unit: mm)
33+
float distance_x; // 前后轮距 (unit: mm)
34+
float distance_y; // 左右轮距 (unit: mm)
35+
36+
struct Wheel
37+
{
38+
steering::SteeringWheel::Config cfg;
39+
steering::SteeringWheel::CalibrationConfig calib_cfg;
40+
};
41+
Wheel wheel_front_right; ///< 右前方
42+
Wheel wheel_front_left; ///< 左前方
43+
Wheel wheel_rear_left; ///< 左后方
44+
Wheel wheel_rear_right; ///< 右后方
45+
};
46+
47+
Steering4(Config cfg, const IChassis::Config& base_cfg);
48+
[[nodiscard]] bool enable() override
49+
{
50+
if (enabled_)
51+
return true;
52+
bool enabled = true;
53+
for (auto& w : wheel_)
54+
enabled &= w.enable();
55+
if (!enabled)
56+
{
57+
disable();
58+
return false;
59+
}
60+
enabled_ = true;
61+
return true;
62+
}
63+
64+
void disable() override
65+
{
66+
for (auto& w : wheel_)
67+
w.disable();
68+
enabled_ = false;
69+
}
70+
71+
void startCalibration()
72+
{
73+
for (auto& w : wheel_)
74+
wheel_->startCalibration();
75+
}
76+
77+
protected:
78+
void applyVelocity(const Velocity& velocity) override;
79+
void velocityControllerUpdate() override;
80+
81+
float forwardGetVx() override
82+
{
83+
return velocity_.vx;
84+
}
85+
float forwardGetVy() override
86+
{
87+
return velocity_.vy;
88+
}
89+
float forwardGetWz() override
90+
{
91+
return velocity_.wz;
92+
}
93+
94+
[[nodiscard]] WheeledKinematicsType kinematicsType() const override
95+
{
96+
return WheeledKinematicsType::VelocityIntegrated;
97+
}
98+
float forwardGetX() override = 0;
99+
float forwardGetY() override = 0;
100+
float forwardGetYaw() override = 0;
101+
102+
private:
103+
bool enabled_{ false };
104+
bool enable_calib_;
105+
bool calibrated_{ false };
106+
107+
float wheel_radius_;
108+
float half_distance_x;
109+
float half_distance_y;
110+
float inv_l2_;
111+
float spd2rpm_;
112+
113+
struct
114+
{
115+
float vx, vy, wz;
116+
} velocity_{}; // 反馈速度
117+
118+
steering::SteeringWheel wheel_[];
119+
120+
struct WheelPosition
121+
{
122+
float x, y;
123+
};
124+
125+
WheelPosition getWheelPosition(WheelType wheel) const;
126+
};
127+
128+
} // namespace chassis

0 commit comments

Comments
 (0)