update sounds ang transtions
Some checks failed
Test / test (push) Has been cancelled

This commit is contained in:
2026-06-22 17:16:36 +07:00
parent d70a4e45af
commit 523f98b74c
28 changed files with 2449 additions and 138 deletions

View File

@@ -1,6 +1,10 @@
#include "mission/mission_queue.hpp"
#include "mission/mission_store.hpp"
#include "mission/position_resolver.hpp"
#include "storage/database.hpp"
#include "storage/map_store.hpp"
#include "storage/transition_store.hpp"
#include "util/id_util.hpp"
#include <chrono>
@@ -40,7 +44,8 @@ double paramNumber(const nlohmann::json& params, const std::string& key, double
} // namespace
MissionQueue::MissionQueue(Database& db) : db_(db)
MissionQueue::MissionQueue(Database& db, MapStore& maps, TransitionStore& transitions, MissionStore& missions)
: db_(db), maps_(maps), transitions_(transitions), missions_(missions), position_resolver_(maps)
{
load();
ensureRunnerDefaults();
@@ -450,10 +455,103 @@ void MissionQueue::runMissionActions(nlohmann::json& entry)
cancel_ = false;
}
void MissionQueue::runAutoTransitionIfNeeded(const std::string& from_map_id,
const std::string& to_map_id,
const nlohmann::json& parameters,
nlohmann::json& log,
int loop_depth)
{
if (from_map_id.empty() || to_map_id.empty() || from_map_id == to_map_id)
return;
const auto transition = transitions_.findBetween(from_map_id, to_map_id);
if (!transition)
{
log.push_back({{"ts", IdUtil::nowIso8601()},
{"level", "error"},
{"message", "No transition configured: " + from_map_id + "" + to_map_id}});
throw std::runtime_error("no transition between maps");
}
std::string from_label = from_map_id;
std::string to_label = to_map_id;
const auto maps = maps_.list();
if (maps.is_array())
{
for (const auto& map : maps)
{
if (!map.is_object())
continue;
if (map.value("id", "") == from_map_id)
from_label = map.value("name", from_map_id);
if (map.value("id", "") == to_map_id)
to_label = map.value("name", to_map_id);
}
}
log.push_back({{"ts", IdUtil::nowIso8601()},
{"level", "info"},
{"message", "Auto transition: " + from_label + "" + to_label}});
const std::string start_id = transition->value("start_position_id", "");
const std::string goal_id = transition->value("goal_position_id", "");
if (!start_id.empty())
{
const auto start_pos = position_resolver_.resolve(start_id, from_map_id);
log.push_back({{"ts", IdUtil::nowIso8601()},
{"level", "info"},
{"message",
"Move to transition start → " + (start_pos ? start_pos->label : start_id)}});
sleepMs(1200);
if (cancel_)
throw MissionCancelled();
}
const std::string mission_id = transition->value("mission_id", "");
if (!mission_id.empty())
{
const auto mission = missions_.findMission(mission_id);
if (mission && mission->contains("actions") && (*mission)["actions"].is_array())
{
log.push_back({{"ts", IdUtil::nowIso8601()},
{"level", "info"},
{"message", "Run transition mission: " + mission->value("name", mission_id)}});
executeActionsUnlocked((*mission)["actions"], parameters, log, loop_depth + 1, false);
if (cancel_)
throw MissionCancelled();
}
else
{
log.push_back({{"ts", IdUtil::nowIso8601()},
{"level", "warn"},
{"message", "Transition mission not found: " + mission_id}});
}
}
std::string err;
if (!setActiveMapOnRobotRuntimeDoc(db_, to_map_id, err))
{
log.push_back({{"ts", IdUtil::nowIso8601()}, {"level", "error"}, {"message", "Switch map failed: " + err}});
throw std::runtime_error("switch_map failed after transition");
}
if (!goal_id.empty())
{
const auto goal_pos = position_resolver_.resolve(goal_id, to_map_id);
log.push_back({{"ts", IdUtil::nowIso8601()},
{"level", "info"},
{"message", "Move to transition goal → " + (goal_pos ? goal_pos->label : goal_id)}});
sleepMs(1200);
if (cancel_)
throw MissionCancelled();
}
}
MissionQueue::LoopControl MissionQueue::executeActionsUnlocked(const nlohmann::json& actions,
const nlohmann::json& parameters,
nlohmann::json& log,
int loop_depth)
int loop_depth,
bool allow_auto_transition)
{
if (loop_depth > 8)
throw std::runtime_error("loop depth exceeded");
@@ -491,7 +589,7 @@ MissionQueue::LoopControl MissionQueue::executeActionsUnlocked(const nlohmann::j
if (action.contains("resolved_mission") && action["resolved_mission"].is_object())
{
const auto& nested_actions = action["resolved_mission"]["actions"];
const LoopControl nested = executeActionsUnlocked(nested_actions, parameters, log, loop_depth);
const LoopControl nested = executeActionsUnlocked(nested_actions, parameters, log, loop_depth, allow_auto_transition);
if (nested == LoopControl::Break)
return LoopControl::Break;
if (nested == LoopControl::Continue)
@@ -533,7 +631,7 @@ MissionQueue::LoopControl MissionQueue::executeActionsUnlocked(const nlohmann::j
{"level", "info"},
{"message", "Loop " + std::to_string(i + 1) + "/" + std::to_string(iterations)}});
}
const LoopControl ctrl = executeActionsUnlocked(children, parameters, log, loop_depth + 1);
const LoopControl ctrl = executeActionsUnlocked(children, parameters, log, loop_depth + 1, allow_auto_transition);
if (ctrl == LoopControl::Break)
break;
if (ctrl == LoopControl::Continue)
@@ -556,16 +654,58 @@ MissionQueue::LoopControl MissionQueue::executeActionsUnlocked(const nlohmann::j
if (type == "move_to_position" || type == "adjust_localization" || type == "pick_cart" || type == "drop_cart")
{
const std::string pos = paramValue(action_id, params, "position", parameters);
std::string pos_ref = paramValue(action_id, params, "position_id", parameters);
if (pos_ref.empty())
pos_ref = paramValue(action_id, params, "position", parameters);
if (allow_auto_transition && (type == "move_to_position" || type == "adjust_localization") && !pos_ref.empty())
{
const std::string active_map = getActiveMapIdFromDb(db_);
const auto resolved = position_resolver_.resolve(pos_ref, active_map);
if (resolved)
{
if (!active_map.empty() && active_map != resolved->map_id)
{
runAutoTransitionIfNeeded(active_map, resolved->map_id, parameters, log, loop_depth);
if (cancel_)
throw MissionCancelled();
}
log.push_back({{"ts", IdUtil::nowIso8601()},
{"level", "info"},
{"message", label + "" + resolved->label}});
sleepMs(1200);
if (cancel_)
throw MissionCancelled();
continue;
}
}
log.push_back({{"ts", IdUtil::nowIso8601()},
{"level", "info"},
{"message", label + "" + (pos.empty() ? "?" : pos)}});
{"message", label + "" + (pos_ref.empty() ? "?" : pos_ref)}});
sleepMs(1200);
if (cancel_)
throw MissionCancelled();
continue;
}
if (type == "switch_map")
{
const std::string map_id = paramValue(action_id, params, "map_id", parameters);
std::string err;
if (!setActiveMapOnRobotRuntimeDoc(db_, map_id, err))
{
log.push_back({{"ts", IdUtil::nowIso8601()}, {"level", "error"}, {"message", "Switch map failed: " + err}});
throw std::runtime_error("switch_map failed");
}
log.push_back(
{{"ts", IdUtil::nowIso8601()}, {"level", "info"}, {"message", "Switch map → " + map_id}});
sleepMs(300);
if (cancel_)
throw MissionCancelled();
continue;
}
if (type == "move_to_marker")
{
const std::string marker = paramValue(action_id, params, "marker", parameters);