|
3 | 3 | * Author(s): Aly Ashour |
4 | 4 | */ |
5 | 5 |
|
6 | | -#include <format> |
7 | | -#include <iostream> |
| 6 | +#include <cmath> |
| 7 | +#include <stdexcept> |
8 | 8 | #include <string> |
9 | 9 |
|
10 | 10 | #include "rclcpp/rclcpp.hpp" |
|
21 | 21 | using namespace ap1_msgs::msg; |
22 | 22 | using namespace ap1::control; |
23 | 23 |
|
24 | | -void ControlNode::on_speed_profile(const SpeedProfileStamped speed_profile) |
| 24 | +void ControlNode::on_speed_profile(const SpeedProfileStamped::SharedPtr speed_profile) |
25 | 25 | { |
26 | 26 | speed_profile_ = speed_profile; |
27 | 27 | } |
28 | 28 |
|
29 | | -void ControlNode::on_path(const TargetPathStamped target_path) |
| 29 | +void ControlNode::on_path(const TargetPathStamped::SharedPtr target_path) |
30 | 30 | { |
31 | 31 | target_path_ = target_path; |
32 | 32 | } |
33 | 33 |
|
34 | | -void ControlNode::on_speed(const FloatStamped speed) |
| 34 | +void ControlNode::on_speed(const FloatStamped::SharedPtr speed) |
35 | 35 | { |
| 36 | + RCLCPP_INFO_THROTTLE(this->get_logger(), *this->get_clock(), 1000, "Received speed from actuation: %.2f", speed->value); |
36 | 37 | vehicle_speed_ = speed; |
37 | 38 | } |
38 | 39 |
|
39 | | -void ControlNode::on_turn_angle(const FloatStamped turn_angle) |
| 40 | +void ControlNode::on_turn_angle(const FloatStamped::SharedPtr turn_angle) |
40 | 41 | { |
41 | 42 | vehicle_turn_angle = turn_angle; |
42 | 43 | } |
43 | 44 |
|
| 45 | +// TODO: refactor. This is just a mess of spaghetti code vro. |
44 | 46 | void ControlNode::control_loop_callback() |
45 | 47 | { |
| 48 | + // check that we have the car's velocity yet |
| 49 | + if (!this->vehicle_speed_) { // TODO: really we should safety stop all of ap1 on a NAN |
| 50 | + RCLCPP_WARN_THROTTLE(this->get_logger(), *this->get_clock(), 2000, "Velocity is null or nan fam. Skipping update."); |
| 51 | + return; |
| 52 | + } |
| 53 | + |
| 54 | + // TEMP: DEBUG |
| 55 | + if (std::isnan(this->vehicle_speed_->value)) { |
| 56 | + throw std::runtime_error("Vehicle speed is nan. Crashing"); |
| 57 | + } |
| 58 | + |
46 | 59 | // the car's current velocity. we only support moving forward atp |
47 | | - const vec3f velocity(this->vehicle_speed_.value, 0, 0); // +x is always forward on the car |
| 60 | + const vec3f velocity(this->vehicle_speed_->value, 0, 0); // +x is always forward on the car |
48 | 61 |
|
49 | 62 | const bool PATH_IS_STALE = false, SPEED_PROFILE_IS_STALE = false; // TEMP |
50 | 63 |
|
51 | 64 | // if path has no waypoints OR path is too old |
52 | | - if (target_path_.path.size() < 1 || PATH_IS_STALE) |
53 | | - return; // don't update |
54 | | - // todo: ideally this should actually still |
55 | | - // send through the speed control |
56 | | - // but we'll implement that later |
| 65 | + if (!target_path_ || target_path_->path.size() < 1 || PATH_IS_STALE) { |
| 66 | + RCLCPP_WARN(this->get_logger(), "Target path is cooked fam. Null, not enough waypoints, or old, skipping."); // TODO: should be throttled |
| 67 | + return; |
| 68 | + } |
57 | 69 |
|
58 | 70 | // if speed profile has no waypoints or speed profile is too old |
59 | | - if (speed_profile_.speeds.size() < 1 || SPEED_PROFILE_IS_STALE) |
| 71 | + if (!speed_profile_ || speed_profile_->speeds.size() < 1 || SPEED_PROFILE_IS_STALE) { |
| 72 | + RCLCPP_WARN(this->get_logger(), "Speed profile is cooked fam. Null, not enough waypoints, or old, skipping."); |
60 | 73 | return; |
| 74 | + } |
61 | 75 |
|
62 | 76 | // ask the controller to calculate the acceleration needed |
63 | | - // for now we'll only consider the very next waypoint & speed value |
64 | | - auto next_waypoint = target_path_.path.at(0); |
65 | | - const vec3f acc = controller_->compute_acceleration( |
66 | | - velocity, vec2f(next_waypoint.x, next_waypoint.y), speed_profile_.speeds.at(0)); |
| 77 | + const vec3f acc = controller_->compute_acceleration(velocity, target_path_, speed_profile_->speeds.at(0)); |
67 | 78 |
|
68 | | - // log |
69 | | - // RCLCPP_INFO(this->get_logger(), "ACC: %.2f, %.2f, %.2f", acc.x, acc.y, acc.z); |
| 79 | + // ALY'S FAVOURITE DEBUG CMD 1 |
| 80 | + RCLCPP_INFO_THROTTLE(this->get_logger(), *this->get_clock(), 700, "ACC: %.2f, %.2f, %.2f", acc.x, acc.y, acc.z); |
70 | 81 |
|
71 | 82 | // compute acc and throttle using ackermann controller |
72 | 83 | AckermannController::Command cmd = ackermann_controller_.compute_command(acc, velocity); |
73 | 84 |
|
74 | | - // DEBUG |
75 | | - // RCLCPP_INFO(this->get_logger(), "CMD: {throttle: %.2f, steering: %.2f}", cmd.throttle, cmd.steering); |
| 85 | + // ALY'S FAVOURITE DEBUG CMD 2 |
| 86 | + RCLCPP_INFO_THROTTLE(this->get_logger(), *this->get_clock(), 700, "CMD: {throttle: %.2f, steering: %.2f}", cmd.throttle, cmd.steering); |
76 | 87 |
|
77 | 88 | // pack the turn angle into a message |
78 | 89 | FloatStamped turn_msg; |
79 | 90 | turn_msg.header.stamp = this->now(); |
80 | | - turn_msg.header.frame_id = "base_link"; |
81 | 91 | turn_msg.value = cmd.steering; // rads |
82 | 92 |
|
83 | 93 | // pack the power into a message |
84 | 94 | FloatStamped pwr_msg; |
85 | 95 | pwr_msg.header.stamp = this->now(); |
86 | | - pwr_msg.header.frame_id = "base_link"; |
87 | 96 | pwr_msg.value = cmd.throttle; // [-1, 1] |
88 | 97 |
|
89 | 98 | // send both messages out |
|
0 commit comments