SkillEventRenderer.h
Go to the documentation of this file.
1/*
2 * This file is part of ArmarX.
3 *
4 * ArmarX is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 *
8 * ArmarX is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * @package RobotAPI::ArmarXObjects::OpossumLogger
17 * @author Joana Plewnia ( joana dot plewnia at kit dot edu )
18 * @date 2026
19 * @copyright http://www.gnu.org/licenses/gpl-2.0.txt
20 * GNU General Public License
21 */
22
23#pragma once
24
25#include <functional>
26#include <optional>
27#include <set>
28#include <string>
29#include <vector>
30
31#include <SimoxUtility/json/json.hpp>
32
34
35namespace armarx::opossum
36{
37
38 /**
39 * @brief One skill lifecycle event, as stored in the Skill memory's
40 * `SkillEvent` core segment.
41 *
42 * `parameters` and `result` are expected in the self-describing Aron JSON
43 * format (the one with `_ARON_VALUE` / `_ARON_ELEMENTS` wrappers), which is
44 * both what `aron::data::converter::AronNlohmannJSONConverter` produces and
45 * what an LTM export writes to `data.aron.json`. This lets the same renderer
46 * run on live memory data and on exported files.
47 */
49 {
50 std::string skillName;
51
52 /// One of the `armarx::skills::SkillStatus` names, e.g. "Running", "Succeeded".
53 std::string status;
54
55 /// The call stack of the execution, e.g. "ServeDrinks->ServeDrinks::BringObjectFromCart".
56 std::string executorName;
57
58 nlohmann::json parameters;
59 nlohmann::json result;
60
62 };
63
64 /**
65 * @brief Resolves an object class to its natural-language ("spoken") name.
66 *
67 * Returns `std::nullopt` if the class is unknown, in which case the renderer
68 * falls back to a humanized class name. Injected rather than hardcoded so
69 * that the renderer stays free of PriorKnowledge/filesystem dependencies and
70 * can be unit-tested; see `ObjectSpokenNames.h` for the production lookup.
71 */
72 using SpokenNameLookup = std::function<std::optional<std::string>(
73 const std::string& dataset, const std::string& className)>;
74
75 /**
76 * @brief Converts skill events into OPOSSUM log lines.
77 *
78 * The output format is one `key:value` line per event, e.g.
79 * @code
80 * skill:LookAtObject, object:dining table, called_by:ServeDrinks::ApproachAndAskForDrink, state:started, time_stamp:2026-07-08T16:45:40.341
81 * @endcode
82 *
83 * This is a port of `tools/gen_armar7_logs.py` in the `opossum_euROBIN`
84 * repository, which produces the same lines offline from an LTM export.
85 * Function names are kept in sync with that script on purpose, so the two
86 * can be compared when the format changes.
87 */
89 {
90 public:
92 SkillEventRenderer(std::set<std::string> noiseSkills, SpokenNameLookup spokenNameLookup);
93
94 /**
95 * @brief Render one event.
96 * @return The log line, or `std::nullopt` if the event is not reportable
97 * (unknown/intermediate status, or a skill on the noise list).
98 */
99 std::optional<std::string> render(const SkillEvent& event) const;
100
101 /// Whether `render()` would drop this skill as noise. Lets a caller skip
102 /// the event before paying to fetch it.
103 bool isNoiseSkill(const std::string& skillName) const;
104
105 /// Pure body/gaze control and primitives that only implement a skill
106 /// already logged above them. These say nothing at scene level.
107 static const std::set<std::string>& DefaultNoiseSkills();
108
109 /// `DefaultNoiseSkills()` as a comma-separated string (for property defaults).
110 static std::string DefaultNoiseSkillsString();
111
112 /// Split a comma-separated list into a set, trimming whitespace.
113 static std::set<std::string> ParseSkillList(const std::string& commaSeparated);
114
115 private:
116 /// Natural-language name of an ObjectID `{dataset, className, instanceName}`.
117 std::string objectName(const nlohmann::json& objectID) const;
118
119 /// `Kitchen/serving-cart-at-lab/on-upper-shelf:with-drinks`
120 /// -> `on upper shelf of serving cart`.
121 std::string locationName(const std::string& value) const;
122
123 /// The parameters that carry scene-level meaning, keyed by what they mean.
124 std::vector<std::string> subjectFields(const nlohmann::json& parameters) const;
125
126 std::set<std::string> noiseSkills;
127 SpokenNameLookup spokenNameLookup;
128 };
129
130 /**
131 * @brief Helpers of `SkillEventRenderer`, exposed for testing.
132 *
133 * Each is a port of the equally-named function in `gen_armar7_logs.py`.
134 */
135 namespace detail
136 {
137 /// Decode a self-describing Aron JSON tree into plain JSON.
138 nlohmann::json flat(const nlohmann::json& node);
139
140 /// `serving-cart-at-lab` -> `serving cart at lab`; `laundryBasket` -> `laundry basket`.
141 std::string humanize(const std::string& text);
142
143 /// Whether `value` is an ObjectID (has className, dataset and instanceName).
144 bool isObjectID(const nlohmann::json& value);
145
146 /// Fetch a parameter by name, supporting `outer.inner` nesting.
147 const nlohmann::json* lookup(const nlohmann::json& parameters, const std::string& key);
148
149 /// Pull the human-readable reason out of an ArmarX error message.
150 std::string errorText(const std::string& message);
151
152 /// Free text needs quoting: it may contain commas, which separate fields.
153 std::string quoted(const std::string& text);
154
155 /// Map a `SkillStatus` name to the reported state, if it is reportable.
156 std::optional<std::string> stateOf(const std::string& status);
157
158 /// The last segment of the executor call stack, i.e. the calling skill.
159 std::string calledBy(const std::string& executorName);
160
161 /// Local time as `2026-07-08T16:45:40.341` (milliseconds, truncated).
162 std::string timestamp(const armarx::core::time::DateTime& time);
163 } // namespace detail
164
165} // namespace armarx::opossum
std::string timestamp()
Represents a point in time.
Definition DateTime.h:25
static std::string DefaultNoiseSkillsString()
DefaultNoiseSkills() as a comma-separated string (for property defaults).
bool isNoiseSkill(const std::string &skillName) const
Whether render() would drop this skill as noise.
static const std::set< std::string > & DefaultNoiseSkills()
Pure body/gaze control and primitives that only implement a skill already logged above them.
static std::set< std::string > ParseSkillList(const std::string &commaSeparated)
Split a comma-separated list into a set, trimming whitespace.
std::optional< std::string > render(const SkillEvent &event) const
Render one event.
std::string errorText(const std::string &message)
Pull the human-readable reason out of an ArmarX error message.
nlohmann::json flat(const nlohmann::json &node)
Decode a self-describing Aron JSON tree into plain JSON.
const nlohmann::json * lookup(const nlohmann::json &parameters, const std::string &key)
Fetch a parameter by name, supporting outer.inner nesting.
std::string quoted(const std::string &text)
Free text needs quoting: it may contain commas, which separate fields.
std::string calledBy(const std::string &executorName)
The last segment of the executor call stack, i.e. the calling skill.
bool isObjectID(const nlohmann::json &value)
Whether value is an ObjectID (has className, dataset and instanceName).
std::optional< std::string > stateOf(const std::string &status)
Map a SkillStatus name to the reported state, if it is reportable.
std::string humanize(const std::string &text)
serving-cart-at-lab -> serving cart at lab; laundryBasket -> laundry basket.
std::function< std::optional< std::string >( const std::string &dataset, const std::string &className)> SpokenNameLookup
Resolves an object class to its natural-language ("spoken") name.
One skill lifecycle event, as stored in the Skill memory's SkillEvent core segment.
std::string status
One of the armarx::skills::SkillStatus names, e.g. "Running", "Succeeded".
armarx::core::time::DateTime timestamp
std::string executorName
The call stack of the execution, e.g. "ServeDrinks->ServeDrinks::BringObjectFromCart".