Localização (control/localization)¶
Índice da documentação¶
| Doc | Escopo |
|---|---|
| Este README | Arquitetura, Executar, configuração do FCU, origem do EKF, SOP indoor, SITL, RViz |
| concepts.md | Teoria de SLAM / VIO / V-SLAM, matemática, fusão com o FCU, T265 vs cuVSLAM |
| legacy.md | Histórico e versões do T265 + vision_to_mavros (2023–2024) |
Papel¶
Integração de navegação externa (external-nav) para voo sem GPS (indoor). Alimenta o FCU com uma pose de Visual SLAM para que seu EKF (ArduPilot EKF3 / PX4 EKF2) possa estimar a posição sem GPS.
Vive sob control porque faz a ponte entre o producer de VSLAM e os transportes MAVROS e
MAVLink. O pipeline é dividido em um producer (RealSense + Isaac ROS Visual SLAM,
executado no container Isaac) e um consumer (uma bridge de vision-pose que encaminha a
pose ao FCU, executada do lado do SDK). Eles se comunicam por host networking com um
ROS_DOMAIN_ID compartilhado.
Topologia¶
flowchart LR
subgraph isaac [Isaac container]
rs[realsense2_camera infra1/2 + IMU]
vslam[isaac_ros_visual_slam]
rs --> vslam
end
subgraph sdk [SDK container or host]
bridge[vision_pose_node backend mavros/mavlink/dds]
mavros[MAVROS indoor]
end
vslam -->|"/visual_slam/tracking/vo_pose_covariance"| bridge
bridge -->|"mavros: /mavros/vision_pose/pose_cov"| mavros
bridge -->|"mavlink: VISION_POSITION_ESTIMATE"| fcu[FCU]
bridge -->|"dds: VehicleOdometry"| fcu
mavros --> fcu
Componentes¶
| Parte | Caminho | Papel |
|---|---|---|
| Launch do producer | nectar/launch/isaac_vslam_realsense.launch.py |
RealSense + Visual SLAM (container Isaac) |
| Launch do consumer | nectar/launch/vision_pose.launch.py |
MAVROS (opcional) + bridge de vision-pose |
| Relay MAVROS | control/localization/vision_pose_bridge.py (MavrosVisionRelay) |
republica a pose em /mavros/vision_pose/pose_cov |
| Bridge MAVLink | reaproveitado de nectar.control.mavlink.VisionPoseBridge |
envia VISION_POSITION_ESTIMATE |
| Bridge DDS | control/px4/vision_bridge.py (Px4VisionOdometryBridge) |
publica px4_msgs/VehicleOdometry em /fmu/in/vehicle_visual_odometry |
| Velocidade (opcional) | MavrosVisionSpeedRelay, nectar.control.mavlink.VisionSpeedBridge, speed_topic na bridge DDS |
veja Velocidade |
| Conversões de frame | control/localization/frames.py |
twist do corpo -> mundo -> NED |
| Node | control/localization/nodes/vision_pose_node.py |
seleciona o backend, conecta a bridge |
| Parâmetros VSLAM | control/localization/config/vslam_realsense.yaml |
ajuste (tuning) de RealSense + Visual SLAM |
| Config MAVROS | control/mavros/config/indoor_mavros.yaml, indoor_pluginlists.yaml |
perfil MAVROS indoor |
Executar¶
Pré-requisito: producer e consumer compartilham o
ROS_DOMAIN_ID(padrão14, vejascripts/lib/config.sh). Jetson, computador de bordo/host e o laptop opcional (RViz) devem usar o mesmo domínio.
1. Produtor (container Isaac)¶
make isaac-run # or: ./docker/isaac_vslam/run_docker.sh
# inside:
nectar-vslam # = ros2 launch nectar/launch/isaac_vslam_realsense.launch.py
Confirme que a RealSense é enumerada e que os tópicos do VSLAM publicam. Notas do Docker: Isaac ROS Visual SLAM (Jetson).
2. Consumidor — feeder de vision (manter em execução)¶
| Backend | Comando |
|---|---|
| MAVROS | ros2 launch nectar vision_pose.launch.py backend:=mavros fcu_url:=… |
| MAVLink direto | ros2 launch nectar vision_pose.launch.py backend:=mavlink mavlink_url:=… |
| PX4 DDS | ros2 launch nectar vision_pose.launch.py backend:=dds |
Ou: make driver DRONE=mavlink ENV=indoor. Verifique a pose fundida
(Procedimento indoor) e só então inicie a missão em um endpoint
MAVLink diferente do feeder.
mavlink_url / fcu_url são de formato livre — ajuste à sua linha serial ou ao fan-out do
roteador. Layout MAVProxy de exemplo no Jetson da Black Bee (GCS / missão / feeder):
14550 / 14551 / 14552.
Respeite a regra do feeder único: não inicie também um segundo feeder de vision no mesmo link do FCU a partir de uma missão.
3. Missão¶
PoseSource.VISION com auto_vision_feed=False (padrão): a missão assina o tópico do
VSLAM para navegação do companion e não envia VISION_*. Ative auto_vision_feed=True
para um feed em processo único (nesse caso, não execute também o feeder standalone de
mavlink no mesmo endpoint). Velocidade opcional nesse caminho: vision_send_speed=True.
Procedimento indoor¶
Checklist do dia de voo para o stack atual (D435i + cuVSLAM). Os comandos e as tabelas do FCU estão acima e em Configuração do FCU; esta seção trata apenas de ordem e prática.
Montagem (prática Black Bee)¶
VIO / V-SLAM assume que a câmera e a IMU se movem junto com a aeronave. Vibração ou uma fixação solta parece movimento para o estimador.
- Alinhe o eixo óptico da D435i com as extrinsics configuradas (
VISO_POS_*/ frames do launch do Isaac). - Fixação soft-mount: elásticos e espuma entre a câmera e o frame; espuma no case do sensor onde ajudar sem bloquear as lentes ou o USB.
- Depois de transportar ou remontar, reinicie o producer + a bridge e refaça as verificações abaixo — não reaproveite a sessão de mapa do dia anterior.
Bring-up¶
- Produtor — Executar §1.
- Consumidor — Executar §2.
- Verificação do pipeline — mova a aeronave manualmente; a pose local fundida do FCU
precisa mudar (
vision_fcu_check.pye/ou o MAVLink Inspector da GCS). RViz opcional: Visualização. - Origem do EKF — apenas quando necessário; veja Origem do EKF. Flag
opcional do feeder:
set_ekf_origin:=true. - Aquecimento (warm-up) — caminhe com o veículo lentamente pelo volume onde ele vai voar (quadrado / círculo / volta pela arena). Movimento suave; evite yaw abrupto e pessoas cruzando o FOV (modos de falha). Isso constrói a cobertura do mapa e permite abortar no chão se o tracking parecer ruim.
- Sanidade de escala / vertical — levante e translade manualmente; X/Y/Z fundidos devem se mover aproximadamente a distância certa. (O bring-up do T265 historicamente pedia um levantamento de ~1 m para a escala vertical — Legado; com D435i + cuVSLAM trate isso como uma verificação, não uma calibração oculta.)
- Primeiro voo — Stabilize ou AltHold → movimento suave observando a pose fundida → Loiter somente quando o tracking parecer estável (pronto para reverter imediatamente). Depois, missão / perfis mais exigentes. Padrão do LuckyBird Discourse parte 2.
Após muito tempo ligado, mudanças de fixação/USB/parâmetros, ou avisos estranhos na GCS: reinicie o producer + a bridge (e reinicie o FCU depois de mudanças de parâmetro).
Triagem¶
| Sintoma | Causa provável | O que tentar |
|---|---|---|
| Nenhum tópico VSLAM | Câmera / Isaac / USB | rs-enumerate-devices no container Isaac; USB3; reinicie o nectar-vslam |
| VSLAM OK, pose do FCU congelada | Bridge, domínio ou feeder duplicado | ROS_DOMAIN_ID compartilhado; reinicie o consumer; regra do feeder único |
| Vision no ROS, EKF não usa | Parâmetros / origem | Configuração do FCU, Origem do EKF; reinicie após mudar parâmetros |
| Caminho instável / divergindo | Vibração, textura, movimento abrupto, sessão obsoleta | Soft-mount; aquecimento mais lento; reinicie o producer |
| Loiter oscila / desloca | Delay / ruído; velocidade contada em dobro | Ajuste VISO_DELAY_MS / ruído; deixe send_speed desligado a menos que os logs mostrem benefício |
| Flags estranhas na GCS após muito tempo ligado | Nós obsoletos / estado do EKF | Reinicie FCU + producer + bridge |
Velocidade (opcional)¶
Por padrão, os feeders enviam apenas posição. send_speed:=true em
vision_pose.launch.py (ou vision_send_speed=True com auto_vision_feed) também envia a
velocidade do VSLAM; a pose continua sendo enviada normalmente. O EKF3 não inicializa
apenas com velocidade (ardupilot#23485).
| Backend | Portador da velocidade |
|---|---|
mavros |
geometry_msgs/TwistStamped em /mavros/vision_speed/speed_twist; o plugin vision_speed converte ENU -> NED e envia VISION_SPEED_ESTIMATE |
mavlink |
VISION_SPEED_ESTIMATE (#103) pelo mesmo link pymavlink usado pela pose |
dds |
velocity + velocity_frame = VELOCITY_FRAME_NED na VehicleOdometry já publicada para a pose |
ros2 launch nectar vision_pose.launch.py backend:=mavros send_speed:=true
ros2 launch nectar vision_pose.launch.py backend:=mavlink send_speed:=true mavlink_url:=…
Argumentos: speed_topic (padrão /visual_slam/tracking/odometry); o node também tem
speed_output_topic, speed_timeout_s.
O que o cuVSLAM realmente fornece¶
O cuVSLAM estima pose e covariância da pose; ele não tem estado de velocidade. O twist
em /visual_slam/tracking/odometry é produzido pelo wrapper ROS como uma diferença finita
sobre as últimas 10 poses,
dp = pose(t0)⁻¹ · pose(t1)
(PoseCache::GetVelocity).
Portanto, ele é derivado da mesma pose que já enviamos, não é uma medição independente. A
aceleração é uma entrada (IMU da RealSense, tracking_mode:=1), não uma saída.
Essa forma de dp torna o twist no frame do corpo (child_frame_id, FLU), como o
nav_msgs/Odometry exige. O VISION_SPEED_ESTIMATE não carrega atitude, então o FCU não
pode rotacioná-lo: as bridges rotacionam de corpo para mundo usando a atitude da mesma
amostra de odometria antes da troca ENU -> NED (frames.py). O ODOMETRY é o
contraexemplo — ele carrega o quaternion e o próprio ArduPilot rotaciona a velocidade
body-FRD.
Configuração do FCU para velocidade¶
O ArduPilot lista a velocidade como opcional, junto com a posição (Non-GPS Position Estimation). Ela só é fundida depois que a fonte é selecionada:
EK3_SRC1_VELXY = 6,EK3_SRC1_VELZ = 6(ExternalNav). Com0as mensagens são recebidas e logadas, mas não fundidas.VISO_VEL_M_NSEdefine o ruído de medição da velocidade. O ArduPilot ignora o campo de covariância doVISION_SPEED_ESTIMATEe sempre usa este parâmetro (AP_VisualOdom_MAV.cpp), então é o único ajuste para o quanto o EKF confia nessa entrada. Como o twist é derivado da posição que já enviamos, começar de forma conservadora (o padrão de0.1m/s) evita contar em dobro uma única medição como se fossem duas independentes.- PX4: o bit 2 de
EKF2_EV_CTRLhabilita a fusão de velocidade 3D.
Verifique as inovações de XKFS/XKF3 nos logs antes e depois de habilitar.
Configuração do FCU¶
A bridge apenas entrega a pose — o estimador do FCU ainda precisa ser configurado para
fundi-la. ArduPilot (EKF3) e PX4 (EKF2) usam parâmetros diferentes e uma taxa mínima
diferente. Os dois backends MAVLink enviam o
VISION_POSITION_ESTIMATE
(#102); o EKF o funde uma vez configurado. As regras de origem variam por firmware — veja
Origem do EKF.
Nossos voos indoor em hardware até hoje são em ArduPilot 4.6.x / 4.8-dev. O conjunto de PX4 abaixo é baseado na documentação do PX4 e corresponde ao pipeline de referência (o mesmo relay MAVROS) usado pelo tutorial VSLAM-UAV no PX4 v1.15.4. O SITL já exercita esse caminho (
ENV=indoor→indoor_room_px4+gz_vision_source); valide no seu Pixhawk antes de usar em competição.
ArduPilot (EKF3)¶
| Parâmetro | Valor | Finalidade |
|---|---|---|
VISO_TYPE |
1 (MAVLink) |
Habilita o backend external-nav que consome VISION_POSITION_ESTIMATE de um companion (o caminho T265 usa 2, veja Notas de hardware) |
EK3_SRC1_POSXY |
6 (ExternalNav) |
Posição horizontal a partir do VSLAM |
EK3_SRC1_VELXY |
6 ou 0 |
Velocidade horizontal — 6 apenas com send_speed:=true, veja Velocidade |
EK3_SRC1_POSZ |
6 (ExternalNav) |
Altura — veja Fonte de altura |
EK3_SRC1_VELZ |
6 ou 0 |
Velocidade vertical, mesma condição de VELXY |
EK3_SRC1_YAW |
6 (ExternalNav) |
Yaw a partir do VSLAM (com COMPASS_USE=0), ou 1 para manter a bússola |
VISO_POS_X/Y/Z |
offset da câmera (m) | Posição da câmera no frame do corpo |
GPS1_TYPE |
0 |
Desabilita o GPS indoor (renomeado de GPS_TYPE a partir da 4.5+) |
Taxa ≥ 4 Hz. Ajuste (tuning): VISO_POS_M_NSE, VISO_YAW_M_NSE, VISO_DELAY_MS,
VISO_QUAL_MIN. Referências:
EKF source selection,
Non-GPS position estimation,
VISO_TYPE,
EK3_SRC*.
PX4 (EKF2)¶
| Parâmetro | Valor | Finalidade |
|---|---|---|
EKF2_EV_CTRL |
bitmask — bit0 h-pos, bit1 v-pos, bit2 vel 3D, bit3 yaw (15 = todos) |
Habilita a fusão de external-vision. O PX4 lançado (≥1.14) já vem com 15, então a fusão inicia automaticamente quando os dados chegam — verifique no seu firmware |
EKF2_HGT_REF |
3 (Vision) |
Referência de altura — veja Fonte de altura |
EKF2_EV_DELAY |
~50 ms |
Delay do EV em relação à IMU; ajuste a partir dos logs |
EKF2_EV_POS_X/Y/Z |
offset da câmera (m) | Posição da câmera no frame do corpo |
EKF2_GPS_CTRL |
0 |
Desabilita o GNSS indoor |
EKF2_MAG_TYPE |
None |
Só se estiver usando yaw da visão |
Taxa de 30–50 Hz — o PX4 rejeita external vision quando a taxa é baixa demais (muito
mais estrito que o ArduPilot); o cuVSLAM a ~90 Hz atende esse requisito. Ajuste:
EKF2_EV_NOISE_MD, EKF2_EVP_NOISE, EKF2_EVA_NOISE, EKF2_EV_QMIN. Referências:
External position estimation,
VIO,
EKF2 tuning,
params_external_vision.yaml,
padrão de EKF2_EV_CTRL (#24298).
Os backends mavros/mavlink entregam essa estimativa como VISION_POSITION_ESTIMATE; o
backend nativo dds publica px4_msgs/VehicleOdometry em
/fmu/in/vehicle_visual_odometry no lugar (mesmos parâmetros do EKF2, sem MAVROS/MAVLink).
Veja Backends.
Origem do EKF¶
A origem do EKF é o lat/lon/alt global que define o NED local (0,0,0). Ela não é
o Home (ponto de retorno do RTL) e não é a origem do mapa do VSLAM. O Home permanece
com o FCU: o ArduPilot o inicializa depois da origem (e novamente ao armar, para o RTL do
Copter). A bridge nunca envia SET_HOME_POSITION.
Opt-in a partir do vision feeder (desligado por padrão):
ros2 launch nectar vision_pose.launch.py backend:=mavlink set_ekf_origin:=true
# optional overrides:
# origin_lat:=… origin_lon:=… origin_alt_m:=… origin_timeout_s:=2.0
Os padrões são o lat/lon do laboratório da Black Bee (-22.41434308754571,
-45.44843145453864) com origin_alt_m:=0.0 (defina a AMSL do local se a altura no mapa
da GCS precisar ficar correta). Se GPS_GLOBAL_ORIGIN já estiver presente, o envio é
ignorado. Suportado em mavros, mavlink e dds.
Alternativas manuais: Set EKF Origin Here do Mission Planner, SET_GPS_GLOBAL_ORIGIN, ou
ahrs-set-origin.lua.
ArduPilot (Non-GPS Position Estimation, Home / origin):
- Se nenhum GPS estiver fornecendo fix, defina a origem antes que o EKF possa estimar a posição (necessário para Loiter / Guided / Auto e para publicar a pose local).
- Os valores de lat/lon só precisam ser um WGS84 válido; são uma referência, não um levantamento topográfico.
- Uma vez definida, a origem não pode ser movida até o próximo reboot.
- Se um GPS estiver presente e obtiver fix, o ArduPilot normalmente define a origem por conta própria (Non-GPS Navigation).
- A partir da 4.7+,
AHRS_OPTIONSbit 3 (RecordOrigin) + bit 4 (UseRecordedOriginForNonGPS) podem salvar/restaurar a origem entre ciclos de energia, então não é preciso defini-la a cada boot. - O ícone do veículo no mapa do Mission Planner aparece quando existe uma origem (wiki do T265, LuckyBird); isso é visualização da GCS, não uma etapa de calibração separada.
Stabilize / AltHold não precisam de uma estimativa de posição. Se você "simplesmente
rodar" sem definir a origem e o Loiter ainda funcionar, a origem já estava definida (fix de
GPS, origem gravada na 4.7+, ou uma definição anterior via GCS/script/set_ekf_origin).
PX4 (External position estimation):
- A fusão EV local (Position / OFFBOARD local) usa o frame local vindo da visão; o guia de setup do VSLAM-UAV não exige definir uma origem para esse caminho.
SET_GPS_GLOBAL_ORIGINserve para construir uma estimativa global a partir da pose local, para que modos automáticos que precisam de posição global (Mission, Return, …) possam rodar indoor (set_ekf_origin:=truenos backendsdds/mavroscobre esse caso).
Nota histórica: o caminho ROS do LuckyBird e o set_origin.py / clique no MP eram
explícitos. O t265_to_mavlink.py upstream pode opcionalmente enviar
SET_GPS_GLOBAL_ORIGIN. O vision_to_mavros (ROS 2) da Black Bee apenas republica a pose.
Veja Legado.
Fonte de altura¶
Não usamos o barômetro indoor — ele deriva perto do solo e no fluxo de ar das hélices. Escolhemos o POSZ entre duas fontes e mantemos o resto do conjunto (POSXY / VELXY / YAW) na visão:
- Vision (
EK3_SRC1_POSZ=6/EKF2_HGT_REF=Vision): a altitude é relativa à origem do VSLAM, sem terrain following — o drone mantém uma altura constante ao cruzar plataformas ou obstáculos na arena. Este é o nosso padrão e tem sido útil em missões com plataformas elevadas. - Rangefinder voltado para baixo (
EK3_SRC1_POSZ=2/EKF2_HGT_REF=Range+EKF2_RNG_CTRL): a altitude acompanha o terreno. O ArduPilot avisa que isso é "só apropriado ... onde o piso é plano, sem obstruções no solo" (EKF sources); o PX4 observa que "a origem NED local vai subir e descer com o nível do solo" (EKF2 tuning). Sobre obstáculos fixos o veículo então sobe para compensar, então mascaramos as quedas abruptas upstream com oObstacleMaskFilterantes que o FCU chegue a vê-las.
Backends¶
mavros: oMavrosVisionRelayrepublica oPoseWithCovarianceStampeddo VSLAM (ENU) em/mavros/vision_pose/pose_cov; o MAVROS converte para NED para o FCU.mavlink:nectar.control.mavlink.VisionPoseBridgeconverte ENU->NED e enviaVISION_POSITION_ESTIMATEpor um link pymavlink dedicado.dds:nectar.control.px4.Px4VisionOdometryBridgeconverte ENU->NED e publicapx4_msgs/VehicleOdometryem/fmu/in/vehicle_visual_odometry(uXRCE-DDS nativo do PX4). Precisa de umMicroXRCEAgentem execução e depx4_msgs; definapx4_namespacepara corresponder a um cliente com namespace.
Cada backend ganha um caminho de velocidade com send_speed:=true
(Velocidade); o caminho de pose acima não é afetado.
Regra do feeder único¶
Exatamente um processo pode enviar vision externa para o FCU:
| Transporte | Feeder padrão | Papel na missão |
|---|---|---|
| MAVROS | vision_pose_node backend:=mavros |
Assina /mavros/vision_pose/… |
| pymavlink direto | vision_pose_node backend:=mavlink standalone em um endpoint dedicado |
PoseSource.VISION, auto_vision_feed=False (somente assinatura) |
| uXRCE-DDS | vision_pose_node backend:=dds |
Lê a pose fundida dos tópicos DDS do PX4 |
Opt-in auto_vision_feed=True: a missão envia VISION_* (opcional vision_send_speed).
Nunca execute também o feeder standalone de mavlink no mesmo endpoint.
SITL¶
Gazebo indoor: ground-truth → tópicos canônicos do VSLAM → mesmos backends → EKF3 / EKF2.
| Firmware | Terminal 1 | Terminal 2 (sim-bridge) |
Feeder | Missão |
|---|---|---|---|---|
ArduPilot PROTOCOL=mavlink (padrão) |
sim-start … ENV=indoor |
Gazebo + vision_pose_node no SERIAL0 (tcp:…:5760) |
node mavlink | SERIAL1 (tcp:…:5762) |
ArduPilot PROTOCOL=mavros |
igual | Gazebo + MAVROS + vision_pose_node |
node mavros | SERIAL0 |
PX4 mavros / dds |
sim-start FIRMWARE=px4 ENV=indoor |
producer + consumer | node mavros / dds | preset correspondente |
PX4 PROTOCOL=mavlink |
igual | apenas producer (UDP offboard único) | missão auto_vision_feed=True |
PX4_MAVLINK_SITL_VISION_CONFIG |
Arena compartilhada: o ArduPilot compõe nectar_indoor; o PX4 usa indoor_room_px4 +
x500_nectar (PosePublisher ~50 Hz). Parâmetros: ArduPilot indoor.parm; PX4
px4_indoor.env. O x500_vision padrão do PX4 só via override explícito. Matriz completa:
README de simulação.
Para exercitar a origem opcional do EKF no ArduPilot indoor:
make sim-start FIRMWARE=ardupilot ENV=indoor
make sim-bridge FIRMWARE=ardupilot ENV=indoor ARGS='set_ekf_origin:=true'
# vision_pose_node log: "EKF origin: sent …" or "already set, skip send"
Observação: o SITL padrão do ArduPilot ainda fixa uma origem SIM home (Camberra) mesmo com
GPS1_TYPE=0, então uma sobrescrita tardia geralmente não se mantém — use a linha de log
para confirmar o caminho do feeder; valide lat/lon em hardware sem GPS (ou depois de um FCU
limpo, sem origem).
ros2 topic hz /visual_slam/tracking/vo_pose_covariance # ~50 Hz
ros2 topic echo /mavros/vision_pose/pose_cov --once # PROTOCOL=mavros
Visualização¶
Os overlays de trajetória mostram a estimativa de SLAM / odometria para que você possa avaliar a qualidade do tracking e o loop closure — eles não são uma etapa de calibração. Use-os no bring-up para verificar: a trajetória acompanha o movimento manual, o ruído é aceitável para o Loiter, e a trajetória verde do SLAM se ajusta ao revisitar um local (loop closure).
A NVIDIA recomenda rodar o RViz em um PC remoto, não no Jetson (tutorial RealSense).
Dois perfis (rviz/vslam_light.rviz, rviz/vslam_full.rviz):
| Perfil | Mostra | Custo no producer |
|---|---|---|
light (padrão) |
TF + odometria + trajetória SLAM (verde) + trajetória VO (roxa) | nenhum (os tópicos de tracking são sempre publicados) |
full |
light + nuvens de landmarks / loop-closure + pose graph | exige enable_visualization:=true |
O perfil light desenha duas trajetórias sempre publicadas: a trajetória verde do SLAM
(/visual_slam/tracking/slam_path, corrigida por loop closure) e a trajetória roxa de
VO (/visual_slam/tracking/vo_path, odometria bruta). Quando um loop se fecha, a
trajetória verde se ajusta em relação à roxa — esse é o loop closure, visível sem custo no
producer. A nuvem de pontos roxa literal do loop closure vive no full (é um tópico
/visual_slam/vis/*, publicado apenas com enable_visualization:=true).
As duas trajetórias light são mostradas como um buffer deslizante (últimos 15 s por
padrão) para que a janela não se preencha com a trajetória inteira. O vslam_rviz.launch.py
executa um relay path_window_node junto com o RViz (sem custo no Jetson) que republica
/visual_slam/tracking/{slam,vo}_path recortado para os últimos window_seconds em
tópicos *_windowed, que o perfil light assina. Defina window_seconds como 0 para o
histórico completo.
Laptop (nectar buildado):
ros2 launch nectar vslam_rviz.launch.py profile:=light # or profile:=full
ros2 launch nectar vslam_rviz.launch.py window_seconds:=30 # longer buffer
Laptop (apenas o repo, sem build) — execute o relay também, senão as trajetórias light ficam vazias:
ros2 run nectar path_window_node.py # if built; otherwise: python3 .../nodes/path_window_node.py
rviz2 -d src/nectar-sdk/nectar/nectar/control/localization/rviz/vslam_light.rviz
O perfil full exige que o producer publique os tópicos /visual_slam/vis/*, que ficam
desligados por padrão para manter o Jetson leve:
Notas de hardware¶
Atual: Intel RealSense D435i + Isaac ROS Visual SLAM (cuVSLAM) em um Jetson Orin Nano; pose a ~90 Hz. Producer / consumer: Executar. Dia do voo: Procedimento indoor.
Legado / fallback: RealSense T265 +
vision_to_mavros (VISO_TYPE=2).
Histórico completo, versões e bring-up: Legado T265. Comparação conceitual:
Conceitos.
Referências¶
Teoria do módulo e uma bibliografia mais completa: Conceitos → Referências.