Ir al contenido

Monitorear robots Recon

Vigila una flota de Recon desde tus propias herramientas: conexión y batería, qué hace cada robot y cuánto ha avanzado, y el historial de cada actividad que ejecutó, con las operaciones de estado y de eventos del robot.

En esta página

Dos tipos de lecturas cubren una flota de robots: las operaciones de estado dicen qué hace cada robot ahora, y la operación de eventos dice qué hizo. Los ejemplos usan la función auxiliar robot_api de la descripción general.

Necesitas una clave de API con acceso de solo lectura a las ubicaciones de los robots.

Estado de la flota

getMinimalStateList devuelve una entrada por robot:

Python
for robot in robot_api("getMinimalStateList", {})["minimalStates"]:
    progress = ""
    if robot.get("activity") == "ROUTE_RUN" and robot.get("waypointTotal"):
        progress = f"stop {robot['waypointIndex'] + 1} of {robot['waypointTotal']}"
    print(f"{robot['name']}: {robot['connectionStatus']}, {robot.get('batteryPercent')}%, {robot.get('activity')} {progress}")
CampoSignificado
uuid, name, locationUuidEl robot, tal como lo identifican las demás operaciones de robots y la consola
connectionStatus, healthStatusGREEN, YELLOW, ORANGE o RED, de mejor a peor, como en todos los dispositivos
batteryPercentNivel de batería, de 0 a 100
activity, activityUuidLo que hace el robot (abajo) y el ID de esa actividad. En un envío, activityUuid es el routeRunUuid que devolvió deploy
event, phase, phaseEventEl último paso de la actividad: event es su ciclo de vida (abajo) y phase, la parte en curso, como NAVIGATING, DWELLING, UNDOCKING o CHARGING
routeUuid, waypointUuid, waypointIndex, waypointTotalDurante una patrulla: la ruta, la parada actual (un ID de parada de la ruta), su posición contada desde 0 y el número de paradas
goalPose, pose, mapIdHacia dónde va el robot, dónde está y el mapa en el que están esas poses
estimatedTimeRemainingSec, distanceRemainingTiempo (segundos) y distancia (metros) que faltan hasta el objetivo actual
failureReasonPor qué falló la última actividad, cuando falló
firmwareVersion, hwVariationFirmware y modelo de hardware

Para un solo robot, getFullState devuelve los mismos campos más las capacidades del robot. Incluye force (false sirve); sin él, la llamada se rechaza:

Python
state = robot_api("getFullState", {"deviceUuid": ROBOT_UUID, "force": False})["fullState"]
capability = state.get("robotPlatformCapability") or {}
print(state["activity"], state.get("phase"), capability.get("supportedActions"))

Usa activity y phase para saber si un robot está en su base, cargando o trabajando; los campos mode y charging no se informan.

Actividades

activityEl robot está
IDLEEsperando un comando
ROUTE_RUNEjecutando una patrulla o una ruta. phase es DWELLING mientras espera en una parada
NAVIGATE_TO_POSEYendo a un punto al que se le envió
NAVIGATE_TO_HOMEVolviendo a su base de carga porque se le envió a la base
IDLE_DOCKINGVolviendo a su base de carga por su cuenta, después de terminar su trabajo o de quedarse inactivo
LOW_BATTERY_DOCKINGVolviendo a su base de carga para recargarse. Rechaza trabajo nuevo hasta que la batería se recupere
MANUAL_CMD_VEL, MANUAL_ACTION, MANUAL_POSTUREConducido en vivo por un operador
EMERGENCYDetenido por una parada de emergencia, hasta que alguien lo libere
EXPLORE_AND_MAP, EXPLORE_AREA, MAINTENANCE_HOLDMapeando su espacio, o retenido por mantenimiento del mapa

Se pueden agregar valores nuevos. Trata como ocupado cualquier valor que no reconozcas.

Historial de eventos

findRobotEvents devuelve lo que hizo un robot entre startMs (incluido) y endMs (excluido). La respuesta es JSON delimitado por saltos de línea (application/x-ndjson), con un evento por línea, del más reciente al más antiguo:

Python
import json
import time

def robot_events(robot_uuid, start_ms, end_ms):
    response = requests.post(
        f"{API}/findRobotEvents",
        headers=HEADERS,
        json={"deviceUuid": robot_uuid, "startMs": start_ms, "endMs": end_ms},
        timeout=60,
    )
    response.raise_for_status()
    events = []
    for line in response.text.splitlines():
        if not line.strip():
            continue
        event = json.loads(line)
        if "_error" in event:
            raise RuntimeError(f"findRobotEvents stopped early: {event.get('_message')}")
        events.append(event)
    return events

now = int(time.time() * 1000)
for event in robot_events(ROBOT_UUID, now - 24 * 3600 * 1000, now):
    print(event["timestampMs"], event.get("activity"), event.get("event"), event.get("phase"), event.get("failureReason"))
  • No hay paginación. Pide una ventana que puedas manejar, por ejemplo un día, y retrocede ventana por ventana para periodos más largos.
  • Una última línea con _error significa que el flujo se detuvo antes del final, aunque el estado sea 200. Vuelve a pedir esa ventana.
  • Los eventos pueden llegar tarde. Un robot que estuvo desconectado sube lo que registró cuando se reconecta, con el timestampMs original. Si recopilas eventos de forma periódica, superpón las ventanas y omite los eventos cuyo uuid ya guardaste.
CampoSignificado
uuidEl ID del evento; úsalo para omitir duplicados
timestampMsCuándo ocurrió, según el reloj del robot
activity, activityUuidLa actividad a la que pertenece el evento
eventSTARTED, PROGRESS, SUSPENDED, RESUMED, COMPLETED, FAILED, CANCELED o REJECTED
phase, phaseEventEn PROGRESS, la fase y si empezó (STARTED) o terminó (COMPLETED)
routeUuid, waypointUuid, waypointIndex, waypointTotalLa ruta y la parada, durante una patrulla
preemptedByEn SUSPENDED o REJECTED, la actividad que tuvo prioridad
failureReasonEn FAILED, el motivo
originatorQuién o qué inició la actividad: type es USER, API_TOKEN o RULE, por ejemplo

Todas las actividades siguen el mismo ciclo de vida: STARTED, luego eventos PROGRESS a medida que avanza por sus fases (llegar a una parada es un evento PROGRESS cuyo phaseEvent es COMPLETED), posiblemente SUSPENDED y RESUMED cuando algo de mayor prioridad la interrumpe, y exactamente uno de COMPLETED, FAILED o CANCELED al final. Una actividad que el robot rechazó es un único evento REJECTED, con preemptedBy indicando lo que la bloqueó.

Genera alertas sobre lo que importa

CondiciónQué revisar
DesconectadoconnectionStatus no es GREEN en dos consultas seguidas
Batería baja lejos de la basebatteryPercent por debajo de tu umbral mientras activity no es una de las actividades de regreso a la base
Patrulla fallidaUn evento FAILED de un ROUTE_RUN, con su failureReason
Envío rechazadoUn evento REJECTED, con preemptedBy
AtascadoLos mismos activity, phase y waypointIndex durante mucho más tiempo del que suele tomar la ruta

Consultar la lista de estado cada uno o dos minutos queda muy por debajo de tu límite de tasa. Los eventos de robots no llegan por el WebSocket de eventos ni por los webhooks de organización; para recibir actualizaciones en tiempo real, conéctate al socket en vivo del robot.