adicionado regras taticas imu ao controle direcional
This commit is contained in:
parent
11ccdca22e
commit
c1f9b88e3c
|
|
@ -230,7 +230,12 @@ namespace AgroBase.Services.Operadores
|
||||||
("path_ia_module_params_ervas", VersionamentoService.ArquivoModeloModuleParamsWeedDetector.CaminhoCompleto),
|
("path_ia_module_params_ervas", VersionamentoService.ArquivoModeloModuleParamsWeedDetector.CaminhoCompleto),
|
||||||
("ia_backbone_ervas", "C:\\AgroBaseModels\\Backbones\\nvidia_mit_b1"),
|
("ia_backbone_ervas", "C:\\AgroBaseModels\\Backbones\\nvidia_mit_b1"),
|
||||||
("angulo_roll_max", VariaveisEquipamento.AnguloInclinacaoRollMax),
|
("angulo_roll_max", VariaveisEquipamento.AnguloInclinacaoRollMax),
|
||||||
("angulo_pitch_max", VariaveisEquipamento.AnguloInclinacaoPitchMax)
|
("angulo_pitch_max", VariaveisEquipamento.AnguloInclinacaoPitchMax),
|
||||||
|
("imu_roll_direita_sinal", 1),
|
||||||
|
("dir_angulo_direita_sinal", 1),
|
||||||
|
("imu_dir_roll_min_aux", 6.0),
|
||||||
|
("imu_dir_bias_attention_deg", 4.0),
|
||||||
|
("imu_dir_bias_risk_deg", 9.0)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
|
|
@ -356,6 +361,9 @@ namespace AgroBase.Services.Operadores
|
||||||
("frenagem_automatica", pControle.FrenagemAutomaticaAoParar),
|
("frenagem_automatica", pControle.FrenagemAutomaticaAoParar),
|
||||||
("oak_parada_por_bloqueio", pControle.OakParadaPorObstaculo),
|
("oak_parada_por_bloqueio", pControle.OakParadaPorObstaculo),
|
||||||
("imu_parada_por_inclinacao", pControle.ImuParadaPorInclinacao),
|
("imu_parada_por_inclinacao", pControle.ImuParadaPorInclinacao),
|
||||||
|
("imu_auxilio_movimento", false),
|
||||||
|
("imu_auxilio_direcional", false),
|
||||||
|
("imu_direcional_preferir_arco", false),
|
||||||
("dir_auxilio_sonar", pControle.DirAuxilioSonar),
|
("dir_auxilio_sonar", pControle.DirAuxilioSonar),
|
||||||
("mov_auxilio_sonar", pControle.MovAuxilioSonar),
|
("mov_auxilio_sonar", pControle.MovAuxilioSonar),
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,8 @@ def definir_comando(pid: PIDAdaptativo, envio_necessario: bool):
|
||||||
_contexto = ContextoGlobalRedis.get_contexto()
|
_contexto = ContextoGlobalRedis.get_contexto()
|
||||||
_equipamento = ContextoGlobalRedis.get_equipamento()
|
_equipamento = ContextoGlobalRedis.get_equipamento()
|
||||||
_trajetoria = _contexto.get("Trajetoria", {})
|
_trajetoria = _contexto.get("Trajetoria", {})
|
||||||
|
_imu = ContextoGlobalRedis.get_modulo(T_Code.Imu) or {}
|
||||||
|
imu_contexto = _montar_contexto_imu_direcional(_imu)
|
||||||
|
|
||||||
usar_auxilio_visual = _controle.get("dir_auxilio_sonar", False)
|
usar_auxilio_visual = _controle.get("dir_auxilio_sonar", False)
|
||||||
dados_visual_worker = None
|
dados_visual_worker = None
|
||||||
|
|
@ -140,6 +142,7 @@ def definir_comando(pid: PIDAdaptativo, envio_necessario: bool):
|
||||||
"PassosAtraso": _operacao.get("Dir", {}).get("mpc", {}).get("passos_atraso", 1),
|
"PassosAtraso": _operacao.get("Dir", {}).get("mpc", {}).get("passos_atraso", 1),
|
||||||
},
|
},
|
||||||
"VisualWorker": dados_visual_worker,
|
"VisualWorker": dados_visual_worker,
|
||||||
|
"IMU": imu_contexto,
|
||||||
"Equipamento": {
|
"Equipamento": {
|
||||||
"largura": _equipamento.get("largura", 0.85),
|
"largura": _equipamento.get("largura", 0.85),
|
||||||
"entre_eixos": _equipamento.get("distancia_entre_eixos", 0.92)
|
"entre_eixos": _equipamento.get("distancia_entre_eixos", 0.92)
|
||||||
|
|
@ -192,6 +195,7 @@ def definir_comando(pid: PIDAdaptativo, envio_necessario: bool):
|
||||||
"tipo": tipo_movimento.value,
|
"tipo": tipo_movimento.value,
|
||||||
"simulacao": []
|
"simulacao": []
|
||||||
}
|
}
|
||||||
|
_cmd = _aplicar_auxilio_imu_direcional(_cmd, contexto)
|
||||||
return _montar_comando_retorno(_cmd)
|
return _montar_comando_retorno(_cmd)
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
|
@ -239,6 +243,8 @@ def _comando_mapa_gps_mpc(contexto):
|
||||||
if (comando is None):
|
if (comando is None):
|
||||||
mostrar_log(f"🧭 Direcional MPC | Erro ao definir comando")
|
mostrar_log(f"🧭 Direcional MPC | Erro ao definir comando")
|
||||||
|
|
||||||
|
comando = _aplicar_auxilio_imu_direcional(comando, contexto)
|
||||||
|
|
||||||
#input("⏸️ Pressione Enter para continuar...")
|
#input("⏸️ Pressione Enter para continuar...")
|
||||||
|
|
||||||
return _montar_comando_retorno(comando)
|
return _montar_comando_retorno(comando)
|
||||||
|
|
@ -544,3 +550,179 @@ def _montar_costmap_direcional(
|
||||||
"debug": {}
|
"debug": {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def _montar_contexto_imu_direcional(_imu: dict):
|
||||||
|
try:
|
||||||
|
ts = float(_imu.get("timestamp", 0.0) or 0.0)
|
||||||
|
ts_s = ts / 1000.0 if ts > 100000000000.0 else ts
|
||||||
|
atualizado = (time.time() - ts_s) <= 1.0 if ts_s > 0 else False
|
||||||
|
|
||||||
|
saude_status = StatusModulo(
|
||||||
|
_imu.get("saude", {}).get("status", StatusModulo.DESCONECTADO.value)
|
||||||
|
)
|
||||||
|
|
||||||
|
operante = saude_status in [StatusModulo.OPERANTE, StatusModulo.ALERTA]
|
||||||
|
|
||||||
|
return {
|
||||||
|
"Valido": bool(_imu.get("valido", False)) and atualizado and operante,
|
||||||
|
"Operante": operante,
|
||||||
|
"Atualizado": atualizado,
|
||||||
|
"StatusSaude": saude_status.value,
|
||||||
|
|
||||||
|
"Roll": float(_imu.get("roll_filtrado", _imu.get("roll_seg", _imu.get("roll", 0.0))) or 0.0),
|
||||||
|
"Pitch": float(_imu.get("pitch_filtrado", _imu.get("pitch_seg", _imu.get("pitch", 0.0))) or 0.0),
|
||||||
|
|
||||||
|
"RollRateDps": float(_imu.get("roll_rate_dps", 0.0) or 0.0),
|
||||||
|
"PitchRateDps": float(_imu.get("pitch_rate_dps", 0.0) or 0.0),
|
||||||
|
|
||||||
|
"RiskLevel": str(_imu.get("risk_level", "unknown") or "unknown"),
|
||||||
|
"RiskLevelNum": int(_imu.get("risk_level_num", 0) or 0),
|
||||||
|
"RiskScore": float(_imu.get("risk_score", 0.0) or 0.0),
|
||||||
|
|
||||||
|
"VelocidadeFactor": float(_imu.get("velocidade_factor", 1.0) or 1.0),
|
||||||
|
"Stop": bool(_imu.get("stop", False)),
|
||||||
|
"EmergencyStop": bool(_imu.get("emergency_stop", False)),
|
||||||
|
"BloquearAvanco": bool(_imu.get("bloquear_avanco", False)),
|
||||||
|
"Motivos": _imu.get("motivos_risco", []) or [],
|
||||||
|
}
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
mostrar_log(f"⚠️ Erro ao montar contexto IMU direcional: {e}")
|
||||||
|
return {
|
||||||
|
"Valido": False,
|
||||||
|
"Operante": False,
|
||||||
|
"Atualizado": False,
|
||||||
|
"RiskLevelNum": 4,
|
||||||
|
"Stop": True,
|
||||||
|
"EmergencyStop": True,
|
||||||
|
"BloquearAvanco": True,
|
||||||
|
"Motivos": [str(e)],
|
||||||
|
}
|
||||||
|
|
||||||
|
def _aplicar_auxilio_imu_direcional(comando: dict, contexto: dict):
|
||||||
|
try:
|
||||||
|
if not isinstance(comando, dict):
|
||||||
|
return comando
|
||||||
|
|
||||||
|
_controle = ContextoGlobalRedis.get_controle()
|
||||||
|
_operacao = ContextoGlobalRedis.get_operacao()
|
||||||
|
_equipamento = ContextoGlobalRedis.get_equipamento()
|
||||||
|
|
||||||
|
usar_auxilio = bool(_controle.get("imu_auxilio_direcional", True))
|
||||||
|
if not usar_auxilio:
|
||||||
|
return comando
|
||||||
|
|
||||||
|
imu = contexto.get("IMU", {}) or {}
|
||||||
|
|
||||||
|
if not bool(imu.get("Valido", False)):
|
||||||
|
return comando
|
||||||
|
|
||||||
|
risk_num = int(imu.get("RiskLevelNum", 0) or 0)
|
||||||
|
|
||||||
|
# Critical/emergency não é trabalho do direcional.
|
||||||
|
# RegrasTaticas deve parar.
|
||||||
|
if risk_num >= 3:
|
||||||
|
return comando
|
||||||
|
|
||||||
|
# Sem risco, não mexe.
|
||||||
|
if risk_num <= 0:
|
||||||
|
return comando
|
||||||
|
|
||||||
|
roll = float(imu.get("Roll", 0.0) or 0.0)
|
||||||
|
pitch = float(imu.get("Pitch", 0.0) or 0.0)
|
||||||
|
roll_rate = float(imu.get("RollRateDps", 0.0) or 0.0)
|
||||||
|
|
||||||
|
# O auxílio direcional é principalmente para roll lateral.
|
||||||
|
# Pitch é melhor tratar com velocidade/parada.
|
||||||
|
roll_abs = abs(roll)
|
||||||
|
|
||||||
|
roll_min_aux = float(_equipamento.get("imu_dir_roll_min_aux", 6.0))
|
||||||
|
if roll_abs < roll_min_aux:
|
||||||
|
return comando
|
||||||
|
|
||||||
|
ang_max = float(_operacao.get("Dir", {}).get("angulo_max", _controle.get("angulo_max", 30.0)) or 30.0)
|
||||||
|
|
||||||
|
angulo_atual = float(comando.get("angulo", 0.0) or 0.0)
|
||||||
|
tipo_atual = comando.get("tipo", TipoMovimentoDirecional.RodasDianteiras.value)
|
||||||
|
|
||||||
|
# Convenções configuráveis:
|
||||||
|
# imu_roll_direita_sinal:
|
||||||
|
# +1 se roll positivo significa tombando/inclinando para direita
|
||||||
|
# -1 se roll negativo significa direita
|
||||||
|
#
|
||||||
|
# dir_angulo_direita_sinal:
|
||||||
|
# +1 se ângulo positivo esterça para direita
|
||||||
|
# -1 se ângulo negativo esterça para direita
|
||||||
|
roll_direita_sinal = float(_equipamento.get("imu_roll_direita_sinal", 1.0) or 1.0)
|
||||||
|
angulo_direita_sinal = float(_equipamento.get("dir_angulo_direita_sinal", 1.0) or 1.0)
|
||||||
|
|
||||||
|
lado_queda = np.sign(roll * roll_direita_sinal)
|
||||||
|
|
||||||
|
if lado_queda == 0:
|
||||||
|
return comando
|
||||||
|
|
||||||
|
# Direção de esterço que tende a aliviar a rolagem:
|
||||||
|
# se está caindo para direita, viés para direita.
|
||||||
|
sinal_angulo_estabilizante = lado_queda * angulo_direita_sinal
|
||||||
|
|
||||||
|
# Intensidade conservadora.
|
||||||
|
bias_max_attention = float(_equipamento.get("imu_dir_bias_attention_deg", 4.0))
|
||||||
|
bias_max_risk = float(_equipamento.get("imu_dir_bias_risk_deg", 9.0))
|
||||||
|
|
||||||
|
# Usa risk_score e roll para modular.
|
||||||
|
risk_score = float(imu.get("RiskScore", 0.0) or 0.0)
|
||||||
|
intensidade_roll = min(1.0, max(0.0, (roll_abs - roll_min_aux) / max(1e-6, 12.0 - roll_min_aux)))
|
||||||
|
intensidade_risk = min(1.0, max(0.0, risk_score / 100.0))
|
||||||
|
intensidade_rate = min(1.0, abs(roll_rate) / 60.0)
|
||||||
|
|
||||||
|
intensidade = max(intensidade_roll, intensidade_risk, intensidade_rate)
|
||||||
|
|
||||||
|
bias_max = bias_max_risk if risk_num >= 2 else bias_max_attention
|
||||||
|
bias = sinal_angulo_estabilizante * bias_max * intensidade
|
||||||
|
|
||||||
|
# Se o comando atual está contra a estabilidade, reduz mais.
|
||||||
|
comando_contra_estabilidade = (angulo_atual * sinal_angulo_estabilizante) < 0
|
||||||
|
|
||||||
|
if comando_contra_estabilidade:
|
||||||
|
# Remove parte do comando contrário e aplica viés estabilizante.
|
||||||
|
angulo_novo = (angulo_atual * 0.35) + bias
|
||||||
|
else:
|
||||||
|
# Se já está para o lado certo, só ajuda de leve.
|
||||||
|
angulo_novo = angulo_atual + (bias * 0.50)
|
||||||
|
|
||||||
|
angulo_novo = max(-ang_max, min(ang_max, angulo_novo))
|
||||||
|
|
||||||
|
comando["angulo_original_sem_imu"] = round(angulo_atual, 2)
|
||||||
|
comando["angulo"] = round(angulo_novo, 2)
|
||||||
|
|
||||||
|
debug = comando.get("debug_custo", {})
|
||||||
|
if not isinstance(debug, dict):
|
||||||
|
debug = {}
|
||||||
|
|
||||||
|
debug["imu_direcional"] = {
|
||||||
|
"ativo": True,
|
||||||
|
"risk_num": risk_num,
|
||||||
|
"roll": round(roll, 3),
|
||||||
|
"pitch": round(pitch, 3),
|
||||||
|
"roll_rate_dps": round(roll_rate, 3),
|
||||||
|
"lado_queda": float(lado_queda),
|
||||||
|
"bias_deg": round(float(bias), 3),
|
||||||
|
"angulo_original": round(float(angulo_atual), 3),
|
||||||
|
"angulo_final": round(float(angulo_novo), 3),
|
||||||
|
"comando_contra_estabilidade": bool(comando_contra_estabilidade),
|
||||||
|
}
|
||||||
|
|
||||||
|
comando["debug_custo"] = debug
|
||||||
|
|
||||||
|
# Em risco 2, preferir MovimentoArco pode ser melhor que rodas dianteiras,
|
||||||
|
# desde que o robô suporte isso com suavidade.
|
||||||
|
usar_arco_imu = bool(_controle.get("imu_direcional_preferir_arco", True))
|
||||||
|
|
||||||
|
if usar_arco_imu and risk_num >= 2:
|
||||||
|
comando["tipo_original_sem_imu"] = tipo_atual
|
||||||
|
comando["tipo"] = TipoMovimentoDirecional.MovimentoArco.value
|
||||||
|
|
||||||
|
return comando
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
mostrar_log(f"⚠️ Erro ao aplicar auxílio direcional IMU: {e}")
|
||||||
|
return comando
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue