generated from wessel/boilerplate
Merge pull request '[PR] Add nodes grade_calculator and final_grade_determinator' (#2) from 1-grade-generator/cijfer-determinator-calculator into 1-grade-generator/master
Reviewed-on: http://git.wessel.gg/inholland/ros2-assignments/pulls/2 Reviewed-by: Wessel T <contact@wessel.gg>
This commit was merged in pull request #2.
This commit is contained in:
@@ -36,11 +36,21 @@ target_link_libraries(exam_result_generator pqxx pq tomlplusplus::tomlplusplus)
|
||||
|
||||
add_executable(final_grade_determinator
|
||||
src/final_grade_determinator/main.cpp
|
||||
src/database/DatabaseManager.cpp
|
||||
src/config/ConfigManager.cpp
|
||||
src/final_grade_determinator/nodes/FinalGradeDeterminator.cpp
|
||||
)
|
||||
target_include_directories(final_grade_determinator PRIVATE
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/final_grade_determinator
|
||||
)
|
||||
ament_target_dependencies(final_grade_determinator rclcpp g2_2025_interfaces)
|
||||
target_link_libraries(final_grade_determinator pqxx pq tomlplusplus::tomlplusplus)
|
||||
|
||||
|
||||
add_executable(grade_calculator
|
||||
src/grade_calculator/main.cpp
|
||||
src/grade_calculator/nodes/GradeCalculator.cpp
|
||||
)
|
||||
ament_target_dependencies(grade_calculator rclcpp g2_2025_interfaces)
|
||||
|
||||
|
||||
@@ -18,6 +18,14 @@ struct StudentCourse {
|
||||
bool operator==(const StudentCourse& other) const {
|
||||
return student_name == other.student_name && course_name == other.course_name;
|
||||
}
|
||||
|
||||
bool operator<(const StudentCourse& other) const {
|
||||
return student_name < other.student_name
|
||||
|| (student_name == other.student_name
|
||||
&& course_name < other.course_name);
|
||||
}
|
||||
};
|
||||
|
||||
typedef std::map<StudentCourse, std::vector<int>> StudentCourseResultMap;
|
||||
|
||||
} // namespace assignments::one
|
||||
|
||||
@@ -65,6 +65,7 @@ void ExamResultGenerator::generate_random_result() {
|
||||
|
||||
// Publish exam result
|
||||
auto exam_msg = g2_2025_interfaces::msg::Exam();
|
||||
exam_msg.student_name = selected.student_name;
|
||||
exam_msg.course_name = selected.course_name;
|
||||
exam_msg.result = grade;
|
||||
|
||||
|
||||
@@ -2,36 +2,19 @@
|
||||
* Action server node template for ROS2
|
||||
*
|
||||
* Node description:
|
||||
* Template action server that demonstrates action server implementation
|
||||
* with goal handling, feedback publishing, and cancellation support
|
||||
*
|
||||
* Reviewed by: <x>
|
||||
* Changelog:
|
||||
* [04-09-2025] Wessel T: Implement template
|
||||
*/
|
||||
|
||||
#include <cstdlib>
|
||||
|
||||
#include "rclcpp/rclcpp.hpp"
|
||||
|
||||
namespace lessons::zero::tmp {
|
||||
|
||||
class NodeTemplate : public rclcpp::Node {
|
||||
public:
|
||||
NodeTemplate()
|
||||
: Node("node_template")
|
||||
{
|
||||
}
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
} // namespace lessons::zero::template
|
||||
#include "nodes/FinalGradeDeterminator.hpp"
|
||||
|
||||
int main(int argc,char *argv[]) {
|
||||
rclcpp::init(argc,argv);
|
||||
|
||||
auto node = std::make_shared<lessons::zero::tmp::NodeTemplate>();
|
||||
auto node = std::make_shared<assignments::one::final_grade_determinator::FinalGradeDeterminator>();
|
||||
|
||||
rclcpp::spin(node);
|
||||
rclcpp::shutdown();
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
#include "FinalGradeDeterminator.hpp"
|
||||
|
||||
namespace assignments::one::final_grade_determinator {
|
||||
|
||||
FinalGradeDeterminator::FinalGradeDeterminator() : Node("final_grade_determinator") {
|
||||
this->declare_parameter("grade_collection_amount", 5);
|
||||
grade_collection_amount_ = this->get_parameter("grade_collection_amount").as_int();
|
||||
|
||||
db_manager_ = std::make_unique<DatabaseManager>(this->get_logger());
|
||||
|
||||
// Create publisher for exam results
|
||||
student_publisher_ = this->create_publisher<g2_2025_interfaces::msg::Student>(
|
||||
"student_course_management", 10
|
||||
);
|
||||
|
||||
// Create subscriber for adding/removing student/course combinations
|
||||
exam_subscriber_ = this->create_subscription<g2_2025_interfaces::msg::Exam>(
|
||||
"exam_results", 10,
|
||||
std::bind(
|
||||
&FinalGradeDeterminator::exam_results_callback,
|
||||
this,
|
||||
std::placeholders::_1
|
||||
)
|
||||
);
|
||||
|
||||
exam_service_client_= this->create_client<g2_2025_interfaces::srv::Exams>("grade_calculator_service");
|
||||
}
|
||||
|
||||
void FinalGradeDeterminator::exam_results_callback(
|
||||
const g2_2025_interfaces::msg::Exam::SharedPtr msg
|
||||
) {
|
||||
student_course_combo_.student_name = msg->student_name;
|
||||
student_course_combo_.course_name = msg->course_name;
|
||||
|
||||
data_map_[student_course_combo_].push_back(msg->result);
|
||||
|
||||
auto grade_collection_as_ulong = static_cast<unsigned long>(grade_collection_amount_);
|
||||
if (data_map_[student_course_combo_].size() == grade_collection_as_ulong) {
|
||||
RCLCPP_INFO(this->get_logger(),
|
||||
"%s // %s: results sent to calculator",
|
||||
msg->student_name.c_str(), msg->course_name.c_str()
|
||||
);
|
||||
grade_calculator_request(student_course_combo_);
|
||||
}
|
||||
}
|
||||
|
||||
void FinalGradeDeterminator::grade_calculator_request(StudentCourse combo) {
|
||||
if (!exam_service_client_->wait_for_service(std::chrono::seconds(1))) {
|
||||
RCLCPP_WARN(this->get_logger(), "Service not available");
|
||||
return;
|
||||
}
|
||||
|
||||
auto request = std::make_shared<g2_2025_interfaces::srv::Exams::Request>();
|
||||
request->course_name = combo.course_name;
|
||||
request->student_name = combo.student_name;
|
||||
request->exam_grades = data_map_[combo];
|
||||
|
||||
// Callback is used due to ros2 not liking passing multiple arguments in async calls
|
||||
auto callback = [this, combo](rclcpp::Client<g2_2025_interfaces::srv::Exams>::SharedFuture future)
|
||||
{
|
||||
this->grade_calculator_response(future, combo);
|
||||
};
|
||||
exam_service_client_->async_send_request(request, callback);
|
||||
}
|
||||
|
||||
void FinalGradeDeterminator::grade_calculator_response(
|
||||
rclcpp::Client<g2_2025_interfaces::srv::Exams>::SharedFuture future,
|
||||
StudentCourse studentCourseCombo
|
||||
) {
|
||||
if (!db_manager_ || !db_manager_->is_connected()) {
|
||||
RCLCPP_WARN(this->get_logger(), "no database connection");
|
||||
return;
|
||||
}
|
||||
|
||||
auto response = future.get();
|
||||
|
||||
auto student_message = g2_2025_interfaces::msg::Student();
|
||||
student_message.student_name = studentCourseCombo.student_name;
|
||||
student_message.course_name = studentCourseCombo.course_name;
|
||||
student_message.timestamp = this->now();
|
||||
student_publisher_->publish(student_message);
|
||||
|
||||
RCLCPP_INFO(this->get_logger(),
|
||||
"%s // %s is %d",
|
||||
studentCourseCombo.student_name.c_str(), studentCourseCombo.course_name.c_str(), response->result
|
||||
);
|
||||
|
||||
db_manager_->store_final_course_result(
|
||||
studentCourseCombo,
|
||||
grade_collection_amount_,
|
||||
response->result
|
||||
);
|
||||
}
|
||||
|
||||
} // namespace assignments::one::final_grade_determinator
|
||||
@@ -0,0 +1,44 @@
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <random>
|
||||
#include <vector>
|
||||
#include <chrono>
|
||||
|
||||
#include "rclcpp/rclcpp.hpp"
|
||||
#include "g2_2025_interfaces/msg/exam.hpp"
|
||||
#include "g2_2025_interfaces/msg/student.hpp"
|
||||
#include "g2_2025_interfaces/srv/exams.hpp"
|
||||
|
||||
#include "database/DatabaseManager.hpp"
|
||||
#include "database/StudentCourse.hpp"
|
||||
|
||||
namespace assignments::one::final_grade_determinator {
|
||||
|
||||
class FinalGradeDeterminator : public rclcpp::Node {
|
||||
public:
|
||||
FinalGradeDeterminator();
|
||||
private:
|
||||
rclcpp::Subscription<g2_2025_interfaces::msg::Exam>::SharedPtr exam_subscriber_;
|
||||
rclcpp::Publisher<g2_2025_interfaces::msg::Student>::SharedPtr student_publisher_;
|
||||
|
||||
rclcpp::Client<g2_2025_interfaces::srv::Exams>::SharedPtr exam_service_client_;
|
||||
|
||||
std::unique_ptr<DatabaseManager> db_manager_;
|
||||
|
||||
StudentCourse student_course_combo_;
|
||||
StudentCourseResultMap data_map_;
|
||||
|
||||
// Params
|
||||
int grade_collection_amount_;
|
||||
|
||||
void grade_calculator_request(StudentCourse combo);
|
||||
void exam_results_callback(const g2_2025_interfaces::msg::Exam::SharedPtr msg);
|
||||
void grade_calculator_response(
|
||||
rclcpp::Client<g2_2025_interfaces::srv::Exams>::SharedFuture future,
|
||||
StudentCourse studentCourseCombo
|
||||
);
|
||||
};
|
||||
|
||||
} // namespace assignments::one::final_grade_determinator
|
||||
@@ -10,28 +10,13 @@
|
||||
* [04-09-2025] Wessel T: Implement template
|
||||
*/
|
||||
|
||||
#include <cstdlib>
|
||||
|
||||
#include "rclcpp/rclcpp.hpp"
|
||||
|
||||
namespace lessons::zero::tmp {
|
||||
|
||||
class NodeTemplate : public rclcpp::Node {
|
||||
public:
|
||||
NodeTemplate()
|
||||
: Node("node_template")
|
||||
{
|
||||
}
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
} // namespace lessons::zero::template
|
||||
#include "nodes/GradeCalculator.hpp"
|
||||
|
||||
int main(int argc,char *argv[]) {
|
||||
rclcpp::init(argc,argv);
|
||||
|
||||
auto node = std::make_shared<lessons::zero::tmp::NodeTemplate>();
|
||||
auto node = std::make_shared<assignments::one::grade_calculator::GradeCalculator>();
|
||||
|
||||
rclcpp::spin(node);
|
||||
rclcpp::shutdown();
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
#include "GradeCalculator.hpp"
|
||||
|
||||
namespace assignments::one::grade_calculator {
|
||||
|
||||
GradeCalculator::GradeCalculator() : Node("grade_calculator") {
|
||||
grade_calculator_service_server_ = this->create_service<g2_2025_interfaces::srv::Exams>(
|
||||
"grade_calculator_service",
|
||||
std::bind(
|
||||
&GradeCalculator::grade_calculator_callback,
|
||||
this,
|
||||
std::placeholders::_1,
|
||||
std::placeholders::_2
|
||||
)
|
||||
);
|
||||
|
||||
RCLCPP_INFO(this->get_logger(), "Grade calculator service server started");
|
||||
}
|
||||
|
||||
void GradeCalculator::grade_calculator_callback(
|
||||
const g2_2025_interfaces::srv::Exams::Request::SharedPtr request,
|
||||
const g2_2025_interfaces::srv::Exams::Response::SharedPtr response
|
||||
) {
|
||||
if (request->exam_grades.size() != 0){
|
||||
grades_total_ = std::accumulate(request->exam_grades.begin(), request->exam_grades.end(), 0);
|
||||
|
||||
auto lowercase = request->student_name;
|
||||
|
||||
std::transform(lowercase.begin(), lowercase.end(), lowercase.begin(), ::tolower);
|
||||
|
||||
grade_result_ = (grades_total_) / request->exam_grades.size();
|
||||
|
||||
if (lowercase.compare("wessel") == 0){
|
||||
grade_result_ += 10;
|
||||
}
|
||||
|
||||
if (grade_result_ > 100) {
|
||||
grade_result_ = 100;
|
||||
} else if (grade_result_ < 10){
|
||||
grade_result_ = 10;
|
||||
}
|
||||
}
|
||||
|
||||
response->result = grade_result_;
|
||||
}
|
||||
|
||||
} // namespace assignments::one::grade_calculator
|
||||
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <random>
|
||||
#include <vector>
|
||||
|
||||
#include "rclcpp/rclcpp.hpp"
|
||||
#include "g2_2025_interfaces/msg/exam.hpp"
|
||||
#include "g2_2025_interfaces/msg/student.hpp"
|
||||
#include "g2_2025_interfaces/srv/exams.hpp"
|
||||
|
||||
|
||||
namespace assignments::one::grade_calculator {
|
||||
|
||||
class GradeCalculator : public rclcpp::Node {
|
||||
public:
|
||||
GradeCalculator();
|
||||
private:
|
||||
rclcpp::Service<g2_2025_interfaces::srv::Exams>::SharedPtr grade_calculator_service_server_;
|
||||
|
||||
int grades_total_;
|
||||
int grade_result_ = 0;
|
||||
|
||||
void grade_calculator_callback(
|
||||
const g2_2025_interfaces::srv::Exams::Request::SharedPtr request,
|
||||
const g2_2025_interfaces::srv::Exams::Response::SharedPtr response
|
||||
);
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
string student_name
|
||||
string course_name
|
||||
int32 result
|
||||
builtin_interfaces/Time timestamp
|
||||
|
||||
Reference in New Issue
Block a user