CreOS SDK
The CreOS SDK allows you to interact with Avular robots
 
Loading...
Searching...
No Matches
System Monitor (C++)

Example for monitoring different statuses of a robot using the CreOS SDK client library.

Introduction

The System Monitor tool is a CLI tool that uses the CreOS SDK client library to monitor different statuses of an Avular robot. You can install the System Monitor by installing the creos-system-monitor package and its dependencies as follows, replacing <version> with the version number of the CreOS SDK you want to install, and <architecture> with the architecture of your system (e.g., amd64, arm64):

sudo apt install ./creos-system-monitor_<version>_<architecture>.deb ./creos-client_<version>_<architecture>.deb ./creos-utils_<version>_<architecture>.deb

Once installed, the System Monitor can be invoked using the creos-system-monitor command.

Below you can find all C++ source files for this tool. The tool is split into four different notifiers, each responsible for monitoring a different status of the robot:

Each notifier subscribes or pulls a value from one or more data sources, and prints the value to the console. They also only print values if they have changed since the last time they were printed. The main.cpp file contains the main function that creates a Client instance and initializes the notifiers using interface instances provided by this client.

Source code

main.cpp

1// Copyright (C) 2024 Avular Holding B.V. - All Rights Reserved
2// You may use this code under the terms of the Avular
3// Software End-User License Agreement.
4//
5// You should have received a copy of the Avular
6// Software End-User License Agreement license with
7// this file, or download it from: avular.com/eula
8//
9/*****************************************************************************
10 * Retrieve system information and monitor the state of the robot.
11 *
12 * The system information and battery status will be logged once. The state of
13 * the robot will be printed initially and whenever it changes.
14 ****************************************************************************/
15#include <spdlog/spdlog.h>
16#include <creos/client.hpp>
17#include <creos/messages/state.hpp>
18#include <iostream>
19#include <mutex>
20
21#include "battery_notifier.hpp"
22#include "control_source_notifier.hpp"
23#include "state_notifier.hpp"
24#include "system_info.hpp"
25
26int main(int argc, char* argv[]) {
27
28 // Connect to the robot
29 std::unique_ptr<creos::Client> client;
30 if (argc > 1) {
31 // use the first argument as the host address if it is available
32 std::string host = argv[1];
33 client = std::make_unique<creos::Client>(host);
34 } else {
35 // otherwise use the default host address
36 client = std::make_unique<creos::Client>();
37 }
38
39 get_system_info(client->system_info());
40 battery_notifier(client->system_info());
41 state_notifier(client->diagnostics());
42 control_source_notifier(client->setpoint_control());
43
44 while (true) {
45 // Sleep for 1 second
46 usleep(1000000);
47 }
48 return 0;
49}

battery_notifier.hpp

1// Copyright (C) 2024 Avular Holding B.V. - All Rights Reserved
2// You may use this code under the terms of the Avular
3// Software End-User License Agreement.
4//
5// You should have received a copy of the Avular
6// Software End-User License Agreement license with
7// this file, or download it from: avular.com/eula
8//
9#pragma once
10
11#include <math.h>
12#include <spdlog/spdlog.h>
13#include <creos/messages/battery_status.hpp>
14#include <creos/system_info_interface.hpp>
15
16void battery_notifier(creos::ISystemInfoInterface* system_info_interface) {
17 system_info_interface->subscribeToBatteryStatus(
18 [previous_battery_status = creos_messages::BatteryStatus{},
19 first_call = true](const creos_messages::BatteryStatus& battery_status) mutable {
20 bool printed_header = false;
21 auto print_header = [&printed_header]() {
22 if (!printed_header) {
23 spdlog::info("Battery status:");
24 printed_header = true;
25 }
26 };
27
28 auto fuzzy_compare = [&](float a, float b, float diff) -> bool {
29 return (std::abs(a - b) >= diff && !std::isnan(a) && !std::isnan(b)) || first_call;
30 };
31
32 if (battery_status.state != previous_battery_status.state || first_call) {
33 print_header();
34 std::string state = "";
35 switch (battery_status.state) {
37 state = "Unknown";
38 break;
40 state = "Offline";
41 break;
43 state = "Charging";
44 break;
46 state = "Discharging";
47 break;
49 state = "Balancing";
50 break;
52 state = "Error";
53 break;
54 default:
55 throw std::runtime_error("Unknown battery state");
56 }
57 spdlog::info(" - State: {}", state);
58 previous_battery_status.state = battery_status.state;
59 }
60
61 if (fuzzy_compare(battery_status.voltage, previous_battery_status.voltage, 0.3f)) {
62 print_header();
63 spdlog::info(" - Voltage: {} V", battery_status.voltage);
64 previous_battery_status.voltage = battery_status.voltage;
65 }
66
67 if (fuzzy_compare(battery_status.state_of_charge, previous_battery_status.state_of_charge, 0.01f)) {
68 print_header();
69 spdlog::info(" - State of charge: {:.2f}%", battery_status.state_of_charge * 100);
70 previous_battery_status.state_of_charge = battery_status.state_of_charge;
71 }
72
73 if (fuzzy_compare(battery_status.state_of_health, previous_battery_status.state_of_health, 0.01f)) {
74 print_header();
75 spdlog::info(" - State of health: {:.2f}%", battery_status.state_of_health * 100);
76 previous_battery_status.state_of_health = battery_status.state_of_health;
77 }
78
79 if (fuzzy_compare(battery_status.temperature, previous_battery_status.temperature, 0.5f)) {
80 print_header();
81 spdlog::info(" - Temperature: {} °C", battery_status.temperature);
82 previous_battery_status.temperature = battery_status.temperature;
83 }
84
85 if (battery_status.alerts != previous_battery_status.alerts || first_call) {
86 print_header();
87 spdlog::info(" - Alerts:");
88 previous_battery_status.alerts = battery_status.alerts;
89
90 bool has_alerts = false;
91 if (battery_status.alerts.cell_under_voltage) {
92 spdlog::info(" - Cell under voltage");
93 has_alerts = true;
94 }
95 if (battery_status.alerts.cell_over_voltage) {
96 spdlog::info(" - Cell over voltage");
97 has_alerts = true;
98 }
99 if (battery_status.alerts.over_current_charging) {
100 spdlog::info(" - Over current charging");
101 has_alerts = true;
102 }
103 if (battery_status.alerts.over_current_discharging) {
104 spdlog::info(" - Over current discharging");
105 has_alerts = true;
106 }
107 if (battery_status.alerts.overload_discharging) {
108 spdlog::info(" - Overload discharging");
109 has_alerts = true;
110 }
111 if (battery_status.alerts.latched_overload_discharging) {
112 spdlog::info(" - Latched overload discharging");
113 has_alerts = true;
114 }
115 if (battery_status.alerts.short_circuit) {
116 spdlog::info(" - Short circuit");
117 has_alerts = true;
118 }
119 if (battery_status.alerts.latched_short_circuit) {
120 spdlog::info(" - Latched short circuit");
121 has_alerts = true;
122 }
123 if (battery_status.alerts.over_temperature_charging) {
124 spdlog::info(" - Over temperature charging");
125 has_alerts = true;
126 }
127 if (battery_status.alerts.over_temperature_discharging) {
128 spdlog::info(" - Over temperature discharging");
129 has_alerts = true;
130 }
131 if (battery_status.alerts.under_temperature_charging) {
132 spdlog::info(" - Under temperature charging");
133 has_alerts = true;
134 }
135 if (battery_status.alerts.under_temperature_discharging) {
136 spdlog::info(" - Under temperature discharging");
137 has_alerts = true;
138 }
139 if (battery_status.alerts.afe_alert) {
140 spdlog::info(" - AFE alert");
141 has_alerts = true;
142 }
143 if (battery_status.alerts.precharge_timeout) {
144 spdlog::info(" - Precharge timeout");
145 has_alerts = true;
146 }
147 if (battery_status.alerts.overcharge) {
148 spdlog::info(" - Overcharge");
149 has_alerts = true;
150 }
151 if (!has_alerts) {
152 spdlog::info(" - No alerts active");
153 }
154 }
155 first_call = false;
156 });
157}
The interface for retrieving general system information of an Avular robot.
Definition system_info_interface.hpp:28
virtual SubscriptionId subscribeToBatteryStatus(const std::function< void(const creos_messages::BatteryStatus &)> &callback)=0
Subscribe to battery status updates.
BatteryStatus message contains the current battery state.
Definition battery_status.hpp:28
@ kError
The battery is in an error state.
Definition battery_status.hpp:36
@ kOffline
The battery is offline or not connected.
Definition battery_status.hpp:32
@ kUnknown
The state is unknown.
Definition battery_status.hpp:31
@ kBalancing
The battery is balancing between cells.
Definition battery_status.hpp:35
@ kDischarging
The battery is discharging.
Definition battery_status.hpp:34
@ kCharging
The battery is charging.
Definition battery_status.hpp:33

control_source_notifier.hpp

1// Copyright (C) 2024 Avular Holding B.V. - All Rights Reserved
2// You may use this code under the terms of the Avular
3// Software End-User License Agreement.
4//
5// You should have received a copy of the Avular
6// Software End-User License Agreement license with
7// this file, or download it from: avular.com/eula
8//
9#pragma once
10
11#include <spdlog/spdlog.h>
12#include <creos/messages/control_source.hpp>
13#include <creos/setpoint_control_interface.hpp>
14
15void control_source_notifier(creos::ISetpointControlInterface* setpoint_control) {
16 setpoint_control->subscribeToCurrentControlSource([](const creos_messages::ControlSource& control_source) {
17 static creos_messages::ControlSource previous_control_source = static_cast<creos_messages::ControlSource>(-1);
18
19 if (control_source != previous_control_source) {
20 std::string control_source_str = "";
21 switch (control_source) {
23 control_source_str = "Disabled";
24 break;
26 control_source_str = "Manual";
27 break;
29 control_source_str = "Autonomous";
30 break;
32 control_source_str = "User";
33 break;
34 default:
35 throw std::runtime_error("Unknown control source");
36 }
37
38 spdlog::info("Control source: {}", control_source_str);
39 }
40 previous_control_source = control_source;
41 });
42}
The interface for sending control setpoints to an Avular robot.
Definition setpoint_control_interface.hpp:30
virtual SubscriptionId subscribeToCurrentControlSource(const std::function< void(const creos_messages::ControlSource &)> &callback)=0
Subscribe to the current control source of the robot.
ControlSource
Control source message containing the control source of the robot.
Definition control_source.hpp:28
@ kAutonomous
The robot is controlled autonomously.
@ kUser
The robot is controlled by a user.
@ kDisabled
The robot is disabled.
@ kManual
The robot is controlled manually.

state_notifier.hpp

1// Copyright (C) 2024 Avular Holding B.V. - All Rights Reserved
2// You may use this code under the terms of the Avular
3// Software End-User License Agreement.
4//
5// You should have received a copy of the Avular
6// Software End-User License Agreement license with
7// this file, or download it from: avular.com/eula
8//
9#pragma once
10
11#include <spdlog/spdlog.h>
12#include <creos/diagnostics_interface.hpp>
13#include <creos/messages/state.hpp>
14
15void state_notifier(creos::IDiagnosticsInterface* diagnostics_interface) {
16 diagnostics_interface->subscribeToState([](const creos_messages::State& state) {
17 static creos_messages::State previous_state;
18
19 if (state.current_action != previous_state.current_action || state.ready_state != previous_state.ready_state) {
20 std::string ready_state = "";
21 switch (state.ready_state) {
23 ready_state = "Unknown";
24 break;
26 ready_state = "NotReady";
27 break;
29 ready_state = "PreArm";
30 break;
32 ready_state = "Active";
33 break;
35 ready_state = "Waiting";
36 break;
38 ready_state = "Failsafe";
39 break;
41 ready_state = "Error";
42 break;
43 default:
44 throw std::runtime_error("Unknown ready state");
45 }
46
47 spdlog::info("State: {} - {}", ready_state, state.current_action);
48 }
49 previous_state = state;
50 });
51}
The interface for retrieving diagnostic information from an Avular robot.
Definition diagnostics_interface.hpp:28
virtual SubscriptionId subscribeToState(const std::function< void(const creos_messages::State &)> &callback)=0
Subscribe to state information of the robot.
The state of the robot.
Definition state.hpp:28
std::string current_action
A textual description of the current action the robot is performing.
Definition state.hpp:52
Ready ready_state
The ready state of the robot.
Definition state.hpp:47
@ kUnknown
The ready state is unknown.
@ kFailsafe
A safety system has been triggered, and the robot is in a failsafe state.
@ kActive
The robot is ready to perform operations.
@ kNotReady
The robot is not ready to perform operations. e.g. when the robot is booting.
@ kError
The robot has a platform error and is not able to perform operations. This should not be used for sof...
@ kWaiting
The robot is operational, but waiting for user input.
@ kPreArm
The robot is in a safety state where checks are being performed. User interaction may be required.

system_info.hpp

1// Copyright (C) 2024 Avular Holding B.V. - All Rights Reserved
2// You may use this code under the terms of the Avular
3// Software End-User License Agreement.
4//
5// You should have received a copy of the Avular
6// Software End-User License Agreement license with
7// this file, or download it from: avular.com/eula
8//
9#pragma once
10
11#include <spdlog/spdlog.h>
12#include <creos/messages/system_info.hpp>
13#include <creos/system_info_interface.hpp>
14
15void get_system_info(creos::ISystemInfoInterface* system_info_interface) {
16 auto system_info = system_info_interface->getSystemInfo();
17 spdlog::info("System info:");
18 spdlog::info(" - Name: {}", system_info.name);
19 spdlog::info(" - Hostname: {}", system_info.hostname);
20 spdlog::info(" - Serial: {}", system_info.serial);
21 spdlog::info(" - Platform: {}", system_info.platform);
22 spdlog::info(" - Components:");
23 for (const auto& component : system_info.component_versions) {
24 std::string type = "";
25 switch (component.type) {
27 type = "Unknown";
28 break;
30 type = "Operating system";
31 break;
33 type = "Container";
34 break;
35 default:
36 throw std::runtime_error("Unknown component type");
37 }
38 spdlog::info(" - {} ({}): {}", component.name, type, component.version);
39 }
40}
virtual creos_messages::SystemInfo getSystemInfo(int timeout_ms=1500)=0
Get the system info.
@ kOs
Operating system.
Definition system_info.hpp:28
@ kContainer
Container.
Definition system_info.hpp:29
@ kUnknown
Unknown type.
Definition system_info.hpp:27