This commit is contained in:
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user