DEBUG C++ ——size_t类型!=int

   如下代码:   

    string sa[6]={"a1","b2","c3","d4","e5","f6"}; 

    vector<string> svec(sa,&sa[6]);//赋值

     cout<<"The value of sa[3]= "<<sa[3]<<endl;//True

     cout<<"The value of svec[3]="<<svec[3]<<endl;//Error!!

    我看了很久没有发现这个错误的根源是什么。难道vector没有索引操作符?

    后面一想,不对啊,vector作为顺序容器,应该具备与string对象的一些基本操作符。

   后面一查,原来在vector里面的索引值必须是size_t类型,修改程序如下,即可运行!

     size_t  index=3;

     cout<<"The value of svec[3]="<<svec[index]<<endl;//True!!

   所以大家在以后的操作中一定要小心小心再小心,不要像我这样。 

#include <stdlib.h> #include <stdio.h> #include <string.h> #include <inttypes.h> #include "pins_arduino.h" #include "io_pin_remap.h" #include "HardwareSerial.h" #include "soc/soc_caps.h" #include "driver/uart.h" #include "freertos/queue.h" #ifndef ARDUINO_SERIAL_EVENT_TASK_STACK_SIZE #define ARDUINO_SERIAL_EVENT_TASK_STACK_SIZE 2048 #endif #ifndef ARDUINO_SERIAL_EVENT_TASK_PRIORITY #define ARDUINO_SERIAL_EVENT_TASK_PRIORITY (configMAX_PRIORITIES-1) #endif #ifndef ARDUINO_SERIAL_EVENT_TASK_RUNNING_CORE #define ARDUINO_SERIAL_EVENT_TASK_RUNNING_CORE -1 #endif void serialEvent(void) __attribute__((weak)); #if SOC_UART_NUM > 1 void serialEvent1(void) __attribute__((weak)); #endif /* SOC_UART_NUM > 1 */ #if SOC_UART_NUM > 2 void serialEvent2(void) __attribute__((weak)); #endif /* SOC_UART_NUM > 2 */ #if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_SERIAL) #if ARDUINO_USB_CDC_ON_BOOT //Serial used for USB CDC HardwareSerial Serial0(0); #else HardwareSerial Serial(0); #endif #if SOC_UART_NUM > 1 HardwareSerial Serial1(1); #endif #if SOC_UART_NUM > 2 HardwareSerial Serial2(2); #endif void serialEventRun(void) { // UART0 is default serialEvent() if(serialEvent && Serial.available()) serialEvent(); #if SOC_UART_NUM > 1 if(serialEvent1 && Serial1.available()) serialEvent1(); #endif #if SOC_UART_NUM > 2 if(serialEvent2 && Serial2.available()) serialEvent2(); #endif } #endif #if !CONFIG_DISABLE_HAL_LOCKS #define HSERIAL_MUTEX_LOCK() do {} while (xSemaphoreTake(_lock, portMAX_DELAY) != pdPASS) #define HSERIAL_MUTEX_UNLOCK() xSemaphoreGive(_lock) #else #define HSERIAL_MUTEX_LOCK() #define HSERIAL_MUTEX_UNLOCK() #endif HardwareSerial::HardwareSerial(uint8_t uart_nr) : _uart_nr(uart_nr), _uart(NULL), _rxBufferSize(256), _txBufferSize(0), _onReceiveCB(NULL), _onReceiveErrorCB(NULL), _onReceiveTimeout(false), _rxTimeout(2), _rxFIFOFull(0), _eventTask(NULL) #if !CONFIG_DISABLE_HAL_LOCKS ,_lock(NULL) #endif { #if !CONFIG_DISABLE_HAL_LOCKS if(_lock == NULL){ _lock = xSemaphoreCreateMutex(); if(_lock == NULL){ log_e("xSemaphoreCreateMutex failed"); return; } } #endif // do the same as boot time, that will set default UART0 pins RX, TX. if(uart_nr == 0) uartSetPins(0, SOC_RX0, SOC_TX0, -1, -1); } HardwareSerial::~HardwareSerial() { end(); // explicit Full UART termination #if !CONFIG_DISABLE_HAL_LOCKS if(_lock != NULL){ vSemaphoreDelete(_lock); } #endif } void HardwareSerial::_createEventTask(void *args) { // Creating UART event Task xTaskCreateUniversal(_uartEventTask, "uart_event_task", ARDUINO_SERIAL_EVENT_TASK_STACK_SIZE, this, ARDUINO_SERIAL_EVENT_TASK_PRIORITY, &_eventTask, ARDUINO_SERIAL_EVENT_TASK_RUNNING_CORE); if (_eventTask == NULL) { log_e(" -- UART%d Event Task not Created!", _uart_nr); } } void HardwareSerial::_destroyEventTask(void) { if (_eventTask != NULL) { vTaskDelete(_eventTask); _eventTask = NULL; } } void HardwareSerial::onReceiveError(OnReceiveErrorCb function) { HSERIAL_MUTEX_LOCK(); // function may be NULL to cancel onReceive() from its respective task _onReceiveErrorCB = function; // this can be called after Serial.begin(), therefore it shall create the event task if (function != NULL && _uart != NULL && _eventTask == NULL) { _createEventTask(this); } HSERIAL_MUTEX_UNLOCK(); } void HardwareSerial::onReceive(OnReceiveCb function, bool onlyOnTimeout) { HSERIAL_MUTEX_LOCK(); // function may be NULL to cancel onReceive() from its respective task _onReceiveCB = function; // setting the callback to NULL will just disable it if (_onReceiveCB != NULL) { // When Rx timeout is Zero (disabled), there is only one possible option that is callback when FIFO reaches 120 bytes _onReceiveTimeout = _rxTimeout > 0 ? onlyOnTimeout : false; // in case that onReceive() shall work only with RX Timeout, FIFO shall be high // this is a work around for an IDF issue with events and low FIFO Full value (< 3) if (_onReceiveTimeout) { uartSetRxFIFOFull(_uart, 120); log_w("OnReceive is set to Timeout only, thus FIFO Full is now 120 bytes."); } // this method can be called after Serial.begin(), therefore it shall create the event task if (_uart != NULL && _eventTask == NULL) { _createEventTask(this); // Create event task } } HSERIAL_MUTEX_UNLOCK(); } // This function allow the user to define how many bytes will trigger an Interrupt that will copy RX FIFO to the internal RX Ringbuffer // ISR will also move data from FIFO to RX Ringbuffer after a RX Timeout defined in HardwareSerial::setRxTimeout(uint8_t symbols_timeout) // A low value of FIFO Full bytes will consume more CPU time within the ISR // A high value of FIFO Full bytes will make the application wait longer to have byte available for the Stkech in a streaming scenario // Both RX FIFO Full and RX Timeout may affect when onReceive() will be called bool HardwareSerial::setRxFIFOFull(uint8_t fifoBytes) { HSERIAL_MUTEX_LOCK(); // in case that onReceive() shall work only with RX Timeout, FIFO shall be high // this is a work around for an IDF issue with events and low FIFO Full value (< 3) if (_onReceiveCB != NULL && _onReceiveTimeout) { fifoBytes = 120; log_w("OnReceive is set to Timeout only, thus FIFO Full is now 120 bytes."); } bool retCode = uartSetRxFIFOFull(_uart, fifoBytes); // Set new timeout if (fifoBytes > 0 && fifoBytes < SOC_UART_FIFO_LEN - 1) _rxFIFOFull = fifoBytes; HSERIAL_MUTEX_UNLOCK(); return retCode; } // timout is calculates in time to receive UART symbols at the UART baudrate. // the estimation is about 11 bits per symbol (SERIAL_8N1) bool HardwareSerial::setRxTimeout(uint8_t symbols_timeout) { HSERIAL_MUTEX_LOCK(); // Zero disables timeout, thus, onReceive callback will only be called when RX FIFO reaches 120 bytes // Any non-zero value will activate onReceive callback based on UART baudrate with about 11 bits per symbol _rxTimeout = symbols_timeout; if (!symbols_timeout) _onReceiveTimeout = false; // only when RX timeout is disabled, we also must disable this flag bool retCode = uartSetRxTimeout(_uart, _rxTimeout); // Set new timeout HSERIAL_MUTEX_UNLOCK(); return retCode; } void HardwareSerial::eventQueueReset() { QueueHandle_t uartEventQueue = NULL; if (_uart == NULL) { return; } uartGetEventQueue(_uart, &uartEventQueue); if (uartEventQueue != NULL) { xQueueReset(uartEventQueue); } } void HardwareSerial::_uartEventTask(void *args) { HardwareSerial *uart = (HardwareSerial *)args; uart_event_t event; QueueHandle_t uartEventQueue = NULL; uartGetEventQueue(uart->_uart, &uartEventQueue); if (uartEventQueue != NULL) { for(;;) { //Waiting for UART event. if(xQueueReceive(uartEventQueue, (void * )&event, (TickType_t)portMAX_DELAY)) { hardwareSerial_error_t currentErr = UART_NO_ERROR; switch(event.type) { case UART_DATA: if(uart->_onReceiveCB && uart->available() > 0 && ((uart->_onReceiveTimeout && event.timeout_flag) || !uart->_onReceiveTimeout) ) uart->_onReceiveCB(); break; case UART_FIFO_OVF: log_w("UART%d FIFO Overflow. Consider adding Hardware Flow Control to your Application.", uart->_uart_nr); currentErr = UART_FIFO_OVF_ERROR; break; case UART_BUFFER_FULL: log_w("UART%d Buffer Full. Consider increasing your buffer size of your Application.", uart->_uart_nr); currentErr = UART_BUFFER_FULL_ERROR; break; case UART_BREAK: log_v("UART%d RX break.", uart->_uart_nr); currentErr = UART_BREAK_ERROR; break; case UART_PARITY_ERR: log_v("UART%d parity error.", uart->_uart_nr); currentErr = UART_PARITY_ERROR; break; case UART_FRAME_ERR: log_v("UART%d frame error.", uart->_uart_nr); currentErr = UART_FRAME_ERROR; break; default: log_v("UART%d unknown event type %d.", uart->_uart_nr, event.type); break; } if (currentErr != UART_NO_ERROR) { if(uart->_onReceiveErrorCB) uart->_onReceiveErrorCB(currentErr); } } } } vTaskDelete(NULL); } void HardwareSerial::begin(unsigned long baud, uint32_t config, int8_t rxPin, int8_t txPin, bool invert, unsigned long timeout_ms, uint8_t rxfifo_full_thrhd) { if(_uart_nr >= SOC_UART_NUM) { log_e("Serial number is invalid, please use a number from 0 to %u", SOC_UART_NUM - 1); return; } #if !CONFIG_DISABLE_HAL_LOCKS if(_lock == NULL){ log_e("MUTEX Lock failed. Can't begin."); return; } #endif // map logical pins to GPIO numbers rxPin = digitalPinToGPIONumber(rxPin); txPin = digitalPinToGPIONumber(txPin); HSERIAL_MUTEX_LOCK(); // First Time or after end() --> set default Pins if (!uartIsDriverInstalled(_uart)) { // get previously used RX/TX pins, if any. int8_t _rxPin = uart_get_RxPin(_uart_nr); int8_t _txPin = uart_get_TxPin(_uart_nr); switch (_uart_nr) { case UART_NUM_0: if (rxPin < 0 && txPin < 0) { // do not change RX0/TX0 if it has already been set before rxPin = _rxPin < 0 ? (int8_t)SOC_RX0 : _rxPin; txPin = _txPin < 0 ? (int8_t)SOC_TX0 : _txPin; } break; #if SOC_UART_NUM > 1 // may save some flash bytes... case UART_NUM_1: if (rxPin < 0 && txPin < 0) { // do not change RX1/TX1 if it has already been set before rxPin = _rxPin < 0 ? (int8_t)RX1 : _rxPin; txPin = _txPin < 0 ? (int8_t)TX1 : _txPin; } break; #endif #if SOC_UART_NUM > 2 // may save some flash bytes... case UART_NUM_2: if (rxPin < 0 && txPin < 0) { // do not change RX2/TX2 if it has already been set before rxPin = _rxPin < 0 ? (int8_t)RX2 : _rxPin; txPin = _txPin < 0 ? (int8_t)TX2 : _txPin; } break; #endif } } // IDF UART driver keeps Pin setting on restarting. Negative Pin number will keep it unmodified. // it will detach previous UART attached pins // indicates that uartbegin() has to initilize a new IDF driver if (_testUartBegin(_uart_nr, baud ? baud : 9600, config, rxPin, txPin, _rxBufferSize, _txBufferSize, invert, rxfifo_full_thrhd)) { _destroyEventTask(); // when IDF uart driver must be restarted, _eventTask must finish too } // IDF UART driver keeps Pin setting on restarting. Negative Pin number will keep it unmodified. // it will detach previous UART attached pins _uart = uartBegin(_uart_nr, baud ? baud : 9600, config, rxPin, txPin, _rxBufferSize, _txBufferSize, invert, rxfifo_full_thrhd); if (_uart == NULL) { log_e("UART driver failed to start. Please check the logs."); HSERIAL_MUTEX_UNLOCK(); return; } if (!baud) { // using baud rate as zero, forces it to try to detect the current baud rate in place uartStartDetectBaudrate(_uart); time_t startMillis = millis(); unsigned long detectedBaudRate = 0; while(millis() - startMillis < timeout_ms && !(detectedBaudRate = uartDetectBaudrate(_uart))) { yield(); } if(detectedBaudRate) { delay(100); // Give some time... _uart = uartBegin(_uart_nr, detectedBaudRate, config, rxPin, txPin, _rxBufferSize, _txBufferSize, invert, rxfifo_full_thrhd); #if CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S3 // S3 and C3 have a limitation and both can't detect a baud rate lower than 9600 if (detectedBaudRate == 9600) log_w("The baud detected, as 9600, may be wrong. ESP32-C3 and ESP32-S3 can't detect a baud rate under 9600."); #endif } else { log_e("Could not detect baudrate. Serial data at the port must be present within the timeout for detection to be possible"); _uart = NULL; } } // create a task to deal with Serial Events when, for example, calling begin() twice to change the baudrate, // or when setting the callback before calling begin() if (_uart != NULL && (_onReceiveCB != NULL || _onReceiveErrorCB != NULL) && _eventTask == NULL) { _createEventTask(this); } // Set UART RX timeout uartSetRxTimeout(_uart, _rxTimeout); // Set UART FIFO Full depending on the baud rate. // Lower baud rates will force to emulate byte-by-byte reading // Higher baud rates will keep IDF default of 120 bytes for FIFO FULL Interrupt // It can also be changed by the application at any time if (!_rxFIFOFull) { // it has not being changed before calling begin() // set a default FIFO Full value for the IDF driver uint8_t fifoFull = 1; if (baud > 57600 || (_onReceiveCB != NULL && _onReceiveTimeout)) { fifoFull = 120; } uartSetRxFIFOFull(_uart, fifoFull); _rxFIFOFull = fifoFull; } HSERIAL_MUTEX_UNLOCK(); } void HardwareSerial::updateBaudRate(unsigned long baud) { uartSetBaudRate(_uart, baud); } void HardwareSerial::end() { // default Serial.end() will completely disable HardwareSerial, // including any tasks or debug message channel (log_x()) - but not for IDF log messages! _onReceiveCB = NULL; _onReceiveErrorCB = NULL; if (uartGetDebug() == _uart_nr) { uartSetDebug(0); } _rxFIFOFull = 0; uartEnd(_uart_nr); // fully detach all pins and delete the UART driver _destroyEventTask(); // when IDF uart driver is deleted, _eventTask must finish too _uart = NULL; } void HardwareSerial::setDebugOutput(bool en) { if(_uart == 0) { return; } if(en) { uartSetDebug(_uart); } else { if(uartGetDebug() == _uart_nr) { uartSetDebug(NULL); } } } int HardwareSerial::available(void) { return uartAvailable(_uart); } int HardwareSerial::availableForWrite(void) { return uartAvailableForWrite(_uart); } int HardwareSerial::peek(void) { if (available()) { return uartPeek(_uart); } return -1; } int HardwareSerial::read(void) { uint8_t c = 0; if (uartReadBytes(_uart, &c, 1, 0) == 1) { return c; } else { return -1; } } // read characters into buffer // terminates if size characters have been read, or no further are pending // returns the number of characters placed in the buffer // the buffer is NOT null terminated. size_t HardwareSerial::read(uint8_t *buffer, size_t size) { return uartReadBytes(_uart, buffer, size, 0); } // Overrides Stream::readBytes() to be faster using IDF size_t HardwareSerial::readBytes(uint8_t *buffer, size_t length) { return uartReadBytes(_uart, buffer, length, (uint32_t)getTimeout()); } void HardwareSerial::flush(void) { uartFlush(_uart); } void HardwareSerial::flush(bool txOnly) { uartFlushTxOnly(_uart, txOnly); } size_t HardwareSerial::write(uint8_t c) { uartWrite(_uart, c); return 1; } size_t HardwareSerial::write(const uint8_t *buffer, size_t size) { uartWriteBuf(_uart, buffer, size); return size; } uint32_t HardwareSerial::baudRate() { return uartGetBaudRate(_uart); } HardwareSerial::operator bool() const { return uartIsDriverInstalled(_uart); } void HardwareSerial::setRxInvert(bool invert) { uartSetRxInvert(_uart, invert); } // negative Pin value will keep it unmodified // can be called after or before begin() bool HardwareSerial::setPins(int8_t rxPin, int8_t txPin, int8_t ctsPin, int8_t rtsPin) { // map logical pins to GPIO numbers rxPin = digitalPinToGPIONumber(rxPin); txPin = digitalPinToGPIONumber(txPin); ctsPin = digitalPinToGPIONumber(ctsPin); rtsPin = digitalPinToGPIONumber(rtsPin); // uartSetPins() checks if pins are valid and, if necessary, detaches the previous ones return uartSetPins(_uart_nr, rxPin, txPin, ctsPin, rtsPin); } // Enables or disables Hardware Flow Control using RTS and/or CTS pins // must use setAllPins() in order to set RTS/CTS pins // SerialHwFlowCtrl = UART_HW_FLOWCTRL_DISABLE, UART_HW_FLOWCTRL_RTS, // UART_HW_FLOWCTRL_CTS, UART_HW_FLOWCTRL_CTS_RTS bool HardwareSerial::setHwFlowCtrlMode(SerialHwFlowCtrl mode, uint8_t threshold) { return uartSetHwFlowCtrlMode(_uart, mode, threshold); } // Sets the uart mode in the esp32 uart for use with RS485 modes // HwFlowCtrl must be disabled and RTS pin set // SerialMode = UART_MODE_UART, UART_MODE_RS485_HALF_DUPLEX, UART_MODE_IRDA, // or testing mode: UART_MODE_RS485_COLLISION_DETECT, UART_MODE_RS485_APP_CTRL bool HardwareSerial::setMode(SerialMode mode) { return uartSetMode(_uart, mode); } // minimum total RX Buffer size is the UART FIFO space (128 bytes for most SoC) + 1. IDF imposition. size_t HardwareSerial::setRxBufferSize(size_t new_size) { if (_uart) { log_e("RX Buffer can't be resized when Serial is already running. Set it before calling begin()."); return 0; } if (new_size <= SOC_UART_FIFO_LEN) { log_w("RX Buffer set to minimum value: %d.", SOC_UART_FIFO_LEN + 1); // ESP32, S2, S3 and C3 means higher than 128 new_size = SOC_UART_FIFO_LEN + 1; } _rxBufferSize = new_size; return _rxBufferSize; } // minimum total TX Buffer size is the UART FIFO space (128 bytes for most SoC). size_t HardwareSerial::setTxBufferSize(size_t new_size) { if (_uart) { log_e("TX Buffer can't be resized when Serial is already running. Set it before calling begin()."); return 0; } if (new_size <= SOC_UART_FIFO_LEN) { log_w("TX Buffer set to minimum value: %d.", SOC_UART_FIFO_LEN); // ESP32, S2, S3 and C3 means higher than 128 _txBufferSize = 0; // it will use just UART FIFO with SOC_UART_FIFO_LEN bytes (128 for most SoC) return SOC_UART_FIFO_LEN; } // if new_size is higher than SOC_UART_FIFO_LEN, TX Ringbuffer will be active and it will be used to report back "availableToWrite()" _txBufferSize = new_size; return _txBufferSize; } #include "esp_uart_driver.h" #include "main.h" #include <HardwareSerial.h> static bool uart0_en = false;//定义了三个静态布尔变量,用于控制UART(通用异步收发传输器)接口的使能状态 static bool uart1_en = false;//禁用 static bool uart2_en = false; // 创建软件串口对象 Uart_Typedef uart1_info={0}; #define UART_ID uart0//默认使用UART0接口 #define UART_ID_1 uart1//备用使用UART1接口 #define BAUD_RATE 115200//波特率为115200bps #define DATA_BITS 8//8位数据位 #define STOP_BITS 1//1位停止位 #define PARITY UART_PARITY_NONE//无奇偶校验 uart_rx_data_callback uart0_rx_callback = NULL;//处理UART接收到的数据 uart_rx_data_callback uart1_rx_callback = NULL;//UART1的接收回调函数指针 uart_rx_data_callback uart2_rx_callback = NULL;//全部初始化为NULL表示默认无回调处理 int uart0_init(uint32_t baud_rate, void *callback)//UART0串口的初始化函数 { Serial.setRxBufferSize(1024);//接收缓冲区大小为1024字节 Serial.setTimeout(50);//串口超时时间为50ms Serial.begin(baud_rate);//指定波特率启动串口 uart0_en = true; uart0_rx_callback = (uart_rx_data_callback )callback;//强制类型转换为uart_rx_data_callback return 0; } int uart1_init(uint32_t baud_rate, uint8_t rx, uint8_t tx, void *callback) { uart1_en = true; Serial1.setRxBufferSize(1024); Serial1.setTimeout(50); Serial.printf("uart1_init... baud_rate=%d,rx= %d,tx= %d\r\n", baud_rate, rx, tx); Serial1.begin(baud_rate, SERIAL_8N1, rx, tx); uart1_rx_callback = (uart_rx_data_callback )callback; return 0; } int uart2_init(uint32_t baud_rate, uint8_t rx, uint8_t tx, void *callback) { uart2_en = true; Serial2.begin(baud_rate, SERIAL_8N1, rx, tx); Serial2.setRxBufferSize(1024); Serial2.setTimeout(50); uart2_rx_callback = (uart_rx_data_callback )callback; return 0; } int uart0_process(void)//UART0串口数据的轮询处理功能 { if (uart0_en)//检查UART0使能状态 { char date[UART_RX_MAXSIZE] = {0}; int rev=0; rev = Serial.available();//通过Serial.available()检测接收缓冲区数据量 if (Serial.available()) { int rev_len = Serial.available(); if (rev_len > 1000)//限制单次处理最大数据量为1000字节 { return 0; } Serial.readBytes(date, rev_len); if (uart0_rx_callback)//调用注册的回调函数处理接收数据 { uart0_rx_callback((uint8_t *)date, rev_len); } } // Serial.printf("uart0_process... %d\r\n", rev); } return 0; } static void uart1_rev_timeout(void)// 串口接收超时处理 { if (uart1_info.timerun) { if (doDelayMillisTime(50, &uart1_info.timecount,false))// 50ms超时判断,timerun激活时启动50ms计时 { /* code */ uart1_info.timerun=0; uart1_info.RxState = 1;//切换状态 uart1_info.RxNum = uart1_info.RxCnt;//超时后保存接收字节数 uart1_info.RxCnt = 0;// 重置计数器 } } if (uart1_info.RxState==1)// 检测到RxState=1时触发回调 { uart1_info.RxState=0;// 复位 /* code */ if (uart1_rx_callback) { uart1_rx_callback((uint8_t *)uart1_info.RxBuf, uart1_info.RxNum);// 通过uart1_rx_callback传递接收缓冲区和数据长度 } } } uint32_t uart1_rev_timeout_cnt = 0; int uart1_process(void)// 串口数据的接收处理与超时管理机制 { if (uart1_en) { static char date[UART_RX_MAXSIZE] = {0};// 使用静态缓冲区date临时存储接收数据 if (Serial1.available()) { int rev_len = Serial1.available();// 限制单次处理最大数据量为1000字节 if (rev_len > 1000) { return 0; } memset(date, 0, sizeof(date)); Serial1.readBytes(date, rev_len); Serial.printf("uart1_process... %d\r\n", rev_len); if((uart1_info.RxCnt+rev_len)>UART_RX_MAXSIZE)// 缓冲区溢出保护 { uart1_info.RxCnt = 0; uart1_info.RxNum= 0; uart1_info.RxState = 0; return 0; } memcpy(uart1_info.RxBuf+uart1_info.RxCnt, date, rev_len); uart1_info.RxCnt += rev_len; if(uart1_info.RxCnt>0) { uart1_info.timerun=1;// 接收到数据时激活定时器 uart1_info.timecount=(uint32_t)SYSTEM_TIMER_MS();// 记录当前系统时间作为超时基准 } } } uart1_rev_timeout();//通过uart1_rev_timeout()实现超时判断 return 0; } int uart2_process(void)// 串口数据的轮询处理 { if (uart2_en) { char date[1024] = {0}; if (Serial2.available()) { int rev_len = Serial2.available(); if (rev_len > 1000)// 限制单次处理最大数据量为1000字节 { return 0; } Serial2.readBytes(date, rev_len); if (uart2_rx_callback) { uart2_rx_callback((uint8_t *)date, rev_len); } // 处理接收到的数据 } } return 0; } int uart0_send(uint8_t *data, uint16_t len)// UART0串口发送函数,data指针指向要发送的数据缓冲区,len表示数据长度 { Serial.write(data, len); return 0;// 固定返回0 } int uart1_send(uint8_t *data, uint16_t len) { Serial1.write(data, len); return 0; } int uart2_send(uint8_t *data, uint16_t len) { Serial2.write(data, len); return 0; } int uart_process(void) { uart0_process(); uart1_process(); // uart2_process(); return 0; } // void UartPrintf(const char *format, ...) // { // if (init == 0) // { // return; // } // mySerial->printf(format); // } // void AiqiUartDriver::aiqi_uart_init(void *init) // { // uart_init_p =(main_uart_init_parms *)init; // gpio_set_function(UART_TX_PIN, GPIO_FUNC_UART); // gpio_set_function(UART_RX_PIN, GPIO_FUNC_UART); // // SoftwareSerial _mySerial(uart_init_p->uart1_rx_pin, uart_init_p->uart1_tx_pin); // 创建软件串口对象 // // mySerial = &_mySerial; // // mySerial->begin(115200); // uart_puts(UART_ID, " Hello, UART 0617\n"); // } 实际上所写的程序中setRxBufferSize就是在Serial.begin之前的
最新发布
11-20
import PySimpleGUI as Py import time import os image_path3 = "D:/software/demo/pythonProject/images/image3.png" image_path4 = "D:/software/demo/pythonProject/images/image4.png" image_path5 = "D:/software/demo/pythonProject/images/image5.png" image_path6 = "D:/software/demo/pythonProject/images/image6.png" image_path7 = "D:/software/demo/pythonProject/images/image7.png" # 检查图片是否存在 if not os.path.exists(image_path3): print(f"[!] 图片3不存在: {image_path3}") image_path3 = None if not os.path.exists(image_path4): print(f"[!] 图片4不存在: {image_path4}") image_path4 = None if not os.path.exists(image_path5): print(f"[!] 图片5不存在: {image_path5}") image_path5 = None if not os.path.exists(image_path6): print(f"[!] 图片6不存在: {image_path6}") image_path6 = None if not os.path.exists(image_path7): print(f"[!] 图片7不存在: {image_path7}") image_path7 = None b = 'zbjszj' layout1 = [[Py.Text('jdsq---')], [Py.Button('tips:zb'), Py.Button('wykd')]] window_position = (435, 0) # 定义主窗口的布局,这里设置了窗口在屏幕上的起始位置为(横坐标50, 纵坐标50) window1 = Py.Window('jdsq', layout1, size=(1665, 68), no_titlebar=True, location=window_position, finalize=True) window1.keep_on_top_set() Py.theme('DarkBlue3') # PySimpleGUI 设置主题颜色 # 全局标志防止重复运行 reminder_running = False def run_periodic_reminder(): global reminder_running if reminder_running: print("[!] 提醒功能已在运行,忽略重复调用") return reminder_running = True layout7 = [[Py.Image(key='img7', filename=image_path7) if image_path7 else Py.Text("加载失败")], [Py.Text("txdj")], [Py.Text("📌 周期性提醒已激活:每次取消后10秒自动重试")], [Py.Multiline("", size=(60, 4), key='-OUTPUT-', disabled=True, autoscroll=True)], [Py.Button('yzxpc', key='EXIT')]] window7 = Py.Window('jbdz:cc', layout7, size=(475, 480), finalize=True) window7.keep_on_top_set() next_popup_time = time.time() + 1 reminder_active = True popup_active = False input_popup = None def show_input_popup(): layout_popup = [[Py.Text('mbwbyd')], [Py.Input(key='-INPUT-', size=(15, 1), focus=True)], [Py.Button('fsydlc', bind_return_key=True), Py.Button('bsyyd')]] return Py.Window('xkdz', layout_popup, keep_on_top=True, modal=True, finalize=True, grab_anywhere=False) try: while True: # === 安全 read():用 try-except 捕获 TclError === try: event7, values7 = window7.read(timeout=100) except (RuntimeError, Exception) as e: # 常见于窗口关闭后底层 TK 资源已释放 if "wrapped C/C++ object has been deleted" in str(e) or "TclError" in str(e): print("[INFO] 窗口已被系统关闭,yzxpc提醒循环。") break else: print(f"[ERROR] Unexpected error: {e}") break if event7 in (None, 'EXIT', Py.WINDOW_CLOSED): # 如果 read 返回 None,说明窗口被关闭 break now = time.time() # 自动弹出输入框逻辑 if reminder_active and not popup_active and next_popup_time and now >= next_popup_time: popup_active = True try: input_popup = show_input_popup() except Exception as e: print(f"[Error] 无法创建弹窗: {e}") popup_active = False next_popup_time = now + 10 continue if input_popup: # 处理输入弹窗 try: event_p, values_p = input_popup.read(timeout=100) except (RuntimeError, Exception): input_popup = None popup_active = False continue if event_p == 'fsydlc': user_input = values_p['-INPUT-'].strip() try: num = float(user_input) formatted_num = int(num) if num.is_integer() else num window7['-OUTPUT-'].update(f"✔️ 录入成功:{formatted_num} —— 提醒停止\n", append=True) reminder_active = False next_popup_time = None except ValueError: window7['-OUTPUT-'].update(f"❌ 输入无效:'{user_input}',10秒后重试...\n", append=True) next_popup_time = time.time() + 10 finally: try: input_popup.close() except: pass input_popup = None popup_active = False elif event_p in (None, 'bsyyd', Py.WINDOW_CLOSED): try: input_popup.close() except: pass input_popup = None popup_active = False window7['-OUTPUT-'].update("⛔ 用户取消,10秒后将再次提醒...\n", append=True) next_popup_time = time.time() + 10 finally: # 确保清理 if 'window7' in locals() or window7 is not None: try: window7.close() except: pass if input_popup is not None: try: input_popup.close() except: pass reminder_running = False def run_single_flow(): """运行一次完整的 window3 流程""" Py.theme('LightBlue') input_history = [] # 存储已确认的数字 last_input_time = None INPUT_TIMEOUT = 5.0 current_text = '' # 使用一个固定宽度的 Text 框实现横向排列 + 自动换行 layout3 = [[Py.Image(key='img3', filename=image_path3) if image_path3 else Py.Text("加载失败")], [Py.Text("rmxglx")], [Py.Text("请在5秒内输入当前数字,之后5秒无操作将自动记录:")], [Py.Input(key='-INPUT-', size=(20, 1), focus=True)], [Py.Text("", size=(60, 1), key='-STATUS-')], [Py.Text("已记录的数字(横向排列,自动换行):")], # 设置 size=(None, 10) 表示不限宽度列,高度最多10行;text_color 和 background_color 提升可读性 [Py.Frame('', [[Py.Text("", size=(590, 10), key='-HISTORY-', relief='sunken', background_color='white', text_color='black', font=('Courier', 10))]], size=(590, 50), pad=10)], # 长度约600 字符,超出则自动换行,最多10行,控制整体显示区域大小以便触发换行 [Py.Button('mphcxxl'), Py.Button('jchdj')], # 用一个大括号使他们在同一行显示 [Py.Button('txlxk'), Py.Button('bfhycg')]] window3 = Py.Window('jbdz:pddb', layout3, size=(630, 565), resizable=True, finalize=True) window3.keep_on_top_set() while True: event3, values3 = window3.read(timeout=100) if event3 == Py.WINDOW_CLOSED: break new_text = values3['-INPUT-'].strip() input_changed = new_text != current_text current_text = new_text valid_number = False # 验证是否为有效数字 try: if current_text: float(current_text) valid_number = True except ValueError: pass if input_changed and valid_number: # 输入变化且合法 → 重置计时器 last_input_time = time.time() window3['-STATUS-'].update(f"✅ 输入中 '{current_text}' ... 5秒无操作将自动提交") if last_input_time is not None: # 超时自动提交 elapsed = time.time() - last_input_time if elapsed >= INPUT_TIMEOUT: try: num = float(current_text) formatted_num = int(num) if num.is_integer() else num input_history.append(formatted_num) history_str = ' '.join(map(str, input_history)) # 更新历史显示:空格分隔,让系统自动换行 window3['-HISTORY-'].update(history_str) window3['-STATUS-'].update("🎉 已自动记录!") window3['-INPUT-'].update('') current_text = '' last_input_time = None except Exception as e: window3['-STATUS-'].update("❌ 提交失败") last_input_time = None elif last_input_time is None and current_text and not valid_number: # 状态栏提示 window3['-STATUS-'].update("❌ 请输入有效的数字") elif last_input_time and valid_number: remaining = max(0, int(INPUT_TIMEOUT - (time.time() - last_input_time) + 0.9)) if remaining > 0: window3['-STATUS-'].update(f"⏳ 还剩 {remaining} 秒自动提交...") if event3 in (Py.WIN_CLOSED, 'bfhycg'): window3.close() elif event3 == 'mphcxxl': window1.hide() elif event3 == 'txlxk': window3.close() layout4 = [[Py.Image(key='img4', filename=image_path4) if image_path4 else Py.Text("加载失败")], [Py.Text("请在5秒内输入当前数字,之后5秒无操作将自动记录:")], [Py.Input(key='-INPUT-', size=(20, 1), focus=True)], [Py.Text("", size=(60, 1), key='-STATUS-')], [Py.Text("已记录的数字(横向排列,自动换行):")], # 设置 size=(None, 10) 表示不限宽度列,高度最多10行;text_color 和 background_color 提升可读性 [Py.Frame('', [[Py.Text("", size=(410, 10), key='-HISTORY-', relief='sunken', background_color='white', text_color='black', font=('Courier', 10))]], size=(410, 50), pad=10)], # 控制整体显示区域大小以便触发换行 [Py.Button('jrrsby'), Py.Button('jrqsby')]] window4 = Py.Window('jbdz:pdbyqr', layout4, size=(450, 440), resizable=True, finalize=True) window4.keep_on_top_set() while True: event4, values4 = window4.read(timeout=100) if event4 == Py.WINDOW_CLOSED: break new_text = values4['-INPUT-'].strip() input_changed = new_text != current_text current_text = new_text valid_number = False # 验证是否为有效数字 try: if current_text: float(current_text) valid_number = True except ValueError: pass if input_changed and valid_number: # 输入变化且合法 → 重置计时器 last_input_time = time.time() window4['-STATUS-'].update(f"✅ 输入中 '{current_text}' ... 5秒无操作将自动提交") if last_input_time is not None: # 超时自动提交 elapsed = time.time() - last_input_time if elapsed >= INPUT_TIMEOUT: try: num = float(current_text) formatted_num = int(num) if num.is_integer() else num input_history.append(formatted_num) history_str = ' '.join(map(str, input_history)) # 更新历史显示:空格分隔,让系统自动换行 window4['-HISTORY-'].update(history_str) window4['-STATUS-'].update("🎉 已自动记录!") window4['-INPUT-'].update('') current_text = '' last_input_time = None except Exception as e: window4['-STATUS-'].update("❌ 提交失败") last_input_time = None elif last_input_time is None and current_text and not valid_number: # 状态栏提示 window4['-STATUS-'].update("❌ 请输入有效的数字") elif last_input_time and valid_number: remaining = max(0, int(INPUT_TIMEOUT - (time.time() - last_input_time) + 0.9)) if remaining > 0: window4['-STATUS-'].update(f"⏳ 还剩 {remaining} 秒自动提交...") elif event4 == 'jrrsby': window4.close() Py.theme('LightBlue') recorded_numbers = [] # 历史记录列表 layout5 = [[Py.Image(key='img5', filename=image_path5) if image_path5 else Py.Text("加载失败")], [Py.Text("请输入当前数字:")], [Py.Input(key='-INPUT-', size=(30, 1), do_not_clear=False)], # do_not_clear=False 表示默认清空 [Py.Button('cxzjqpqh', bind_return_key=True), Py.Button('bsyjcxh')], [Py.HorizontalSeparator()], [Py.Text("已保留的数字(横向排列,自动换行):")], [Py.Text("", size=(50, 2), key='-HISTORY-', relief='sunken', background_color='white', text_color='black')]] window5 = Py.Window('jbdz:rsby', layout5, finalize=True) window5.keep_on_top_set() while True: event5, values5 = window5.read() if event5 == Py.WINDOW_CLOSED: break input_value = values5['-INPUT-'].strip() if event5 == 'cxzjqpqh': window5.close() run_periodic_reminder() if input_value == '': window4['-HISTORY-'].update("⚠️ 输入为空,无法保留") else: try: num = float(input_value) formatted_num = int(num) if num.is_integer() else num recorded_numbers.append(formatted_num) history_text = ' '.join(map(str, recorded_numbers)) # 更新历史显示(横向空格分隔,自动换行) window5['-HISTORY-'].update(history_text) window5['-INPUT-'].update('') # 清空输入框(do_not_clear=False 已自动处理,但仍显式更新以防万一) except ValueError: window5['-STATUS-'].update("❌ 不是有效数字!") elif event5 == 'bsyjcxh': window5['-INPUT-'].update('') # 直接清空输入框 elif event4 == 'jrqsby': window4.close() Py.theme('LightBlue') recorded_numbers = [] # 历史记录列表 layout6 = [[Py.Image(key='img6', filename=image_path6) if image_path6 else Py.Text("加载失败")], [Py.Text("请输入当前数字:")], [Py.Input(key='-INPUT-', size=(30, 1), do_not_clear=False)], # do_not_clear=False 表示默认清空 [Py.Button('cxzcpb', bind_return_key=True), Py.Button('bsyjcxh')], [Py.HorizontalSeparator()], [Py.Text("已保留的数字(横向排列,自动换行):")], [Py.Text("", size=(50, 2), key='-HISTORY-', relief='sunken', background_color='white', text_color='black')]] window6 = Py.Window('jbdz:qsby', layout6, finalize=True) window6.keep_on_top_set() while True: event6, values6 = window6.read() if event6 == Py.WINDOW_CLOSED: break input_value = values6['-INPUT-'].strip() if event6 == 'cxzcpb': window6.close() run_periodic_reminder() if input_value == '': window6['-HISTORY-'].update("⚠️ 输入为空,无法保留") else: try: num = float(input_value) formatted_num = int(num) if num.is_integer() else num recorded_numbers.append(formatted_num) history_text = ' '.join(map(str, recorded_numbers)) # 更新历史显示(横向空格分隔,自动换行) window6['-HISTORY-'].update(history_text) window6['-INPUT-'].update('') # 清空输入框(do_not_clear=False 已自动处理,但仍显式更新以防万一) except ValueError: window6['-STATUS-'].update("❌ 不是有效数字!") elif event6 == 'bsyjcxh': # 直接清空输入框 window6['-INPUT-'].update('') elif event3 == 'jchdj': window3.close() window1.un_hide() run_periodic_reminder() # 弹出礼物窗口 while True: # 主事件循环 event1, values1 = window1.read() if event1 == Py.WIN_CLOSED: break if event1 == 'tips:zb': layout2 = [[Py.Text(b, size=(170, 2), auto_size_text=True)]] window2 = Py.Window('ktrx', layout2, size=(940, 210), finalize=True, keep_on_top=True) window2.read(timeout=5000, close=True) if event1 == 'wykd': run_single_flow() 代码增强与优化防崩溃完美全版本
11-10
#include "EnvInfoProcessor.h" #include <log_custom.h> #include <fmt/format.h> #include "lib/sd_navigation/routing_map_debug.h" namespace cem { namespace fusion { namespace navigation { EnvInfoProcessor::EnvInfoProcessor() : env_info_(std::make_unique<EnvInfo>()), is_switched_to_LD_(false), last_remain_dis_(-1.0), accumulated_distance_(0.0), is_entered_ramp_(false), is_accumulated_valid_(false) { // is_entered_ramp_ = CheckIfInRamp(*INTERNAL_PARAMS.sd_map_data.GetSDRouteInfoPtr()); // if (is_entered_ramp_) { // is_switched_to_LD_ = true; // 如果初始化时已在匝道内,设置标志位为 true // } } void EnvInfoProcessor::Process(const std::vector<cem::message::env_model::StopLine> &stop_line_obj) { auto *sensor_manager = SensorDataManager::Instance(); if (!sensor_manager) { AWARN << "SensorDataManager instance is null"; SD_ENV_INFO_LOG << fmt::format("SensorDataManager instance is null, exiting"); return; } MapEventPtr map_event_ptr; sensor_manager->GetLatestSensorFrame(map_event_ptr); if (!map_event_ptr) { AWARN << "Failed to get latest sensor frame"; SD_ENV_INFO_LOG << fmt::format("Failed to get latest MapEvent, exiting"); return; } const auto &map_event = *map_event_ptr; // 获取 SDRouteInfo if (INTERNAL_PARAMS.sd_map_data.GetSDRouteInfoPtr() == nullptr) { AWARN << "[EnvInfoProcessor] SDRouteInfo is null"; SD_ENV_INFO_LOG << fmt::format("SDRouteInfo is null, exiting"); return; } const auto &sd_route = *INTERNAL_PARAMS.sd_map_data.GetSDRouteInfoPtr(); // SD_ENV_INFO_LOG << fmt::format("{}", sd_route); // 清空并重新初始化 env_info_ // env_info_ = std::make_unique<EnvInfo>(); env_info_->v2_road_classes.clear(); env_info_->v2_turn_info.clear(); env_info_->traffic_flows.clear(); env_info_->v2_curvatures.clear(); env_info_->v2_non_odd_info.clear(); // 从 MapEvent 提取字段 env_info_->v2_valid = (map_event.navi_stat != NaviStatus::NO_NAVAGATION); env_info_->v2_has_navigation = (map_event.navi_stat != NaviStatus::NO_NAVAGATION); SD_ENV_INFO_LOG << fmt::format("Set v2_valid: {}, v2_has_navigation: {}", env_info_->v2_valid, env_info_->v2_has_navigation); // 处理 v2_dist_to_ramp if (CheckIfInRamp(sd_route)) { env_info_->v2_dist_to_ramp = 0.0; SD_ENV_INFO_LOG << fmt::format("Vehicle is in ramp, set v2_dist_to_ramp: 0.0"); } else if (map_event.control_waypoint_type == ControlWayPoint::COMING_LEFT_ONTO_THE_RAMP || map_event.control_waypoint_type == ControlWayPoint::COMING_RIGHT_ONTO_THE_RAMP) { env_info_->v2_dist_to_ramp = map_event.control_waypoint_dis; SD_ENV_INFO_LOG << fmt::format("Approaching ramp, set v2_dist_to_ramp: {}", env_info_->v2_dist_to_ramp); } else { env_info_->v2_dist_to_ramp = DEFAULT_LARGE_DISTANCE; SD_ENV_INFO_LOG << fmt::format("No ramp detected, set v2_dist_to_ramp: {}", DEFAULT_LARGE_DISTANCE); } // 处理 v2_dist_to_toll 和 v2_dist_to_tunnel env_info_->v2_dist_to_toll = DEFAULT_LARGE_DISTANCE; env_info_->v2_dist_to_tunnel = DEFAULT_LARGE_DISTANCE; for (const auto &reminder_info : map_event.reminder_way_info) { if (reminder_info.reminder_waypoint_type == ReminderWayPoint::TOLL_BOOTH) { env_info_->v2_dist_to_toll = reminder_info.reminder_waypoint_dis; SD_ENV_INFO_LOG << fmt::format("Toll booth detected, set v2_dist_to_toll: {}", env_info_->v2_dist_to_toll); } else if (reminder_info.reminder_waypoint_type == ReminderWayPoint::TUNNEL) { env_info_->v2_dist_to_tunnel = reminder_info.reminder_waypoint_dis; SD_ENV_INFO_LOG << fmt::format("Tunnel detected, set v2_dist_to_tunnel: {}", env_info_->v2_dist_to_tunnel); } } // 处理 v2_curvatures env_info_->v2_curvatures.clear(); for (const auto &curvature_info : map_event.curvature_info) { V2Curvature v2_curvature; v2_curvature.distance = curvature_info.remain_dis; v2_curvature.curvature = curvature_info.curvature; env_info_->v2_curvatures.emplace_back(v2_curvature); } SD_ENV_INFO_LOG << fmt::format("Set v2_curvatures with size: {}", env_info_->v2_curvatures.size()); // 处理 traffic_flows env_info_->traffic_flows.clear(); V2TrafficFlow traffic_flow; traffic_flow.start_s = map_event.traffic_info.dist_to_start_traffic_jam; traffic_flow.end_s = traffic_flow.start_s + map_event.traffic_info.traffic_jam_dist; switch (map_event.traffic_info.traffic_jam_status) { case 1: traffic_flow.type = V2TrafficFlow::V2TrafficFlowType::SMOOTH_FLOW; break; case 2: traffic_flow.type = V2TrafficFlow::V2TrafficFlowType::SLOW_FLOW; break; case 3: traffic_flow.type = V2TrafficFlow::V2TrafficFlowType::JAMMED_FLOW; break; case 4: traffic_flow.type = V2TrafficFlow::V2TrafficFlowType::SEVERE_JAMMED_FLOW; break; default: traffic_flow.type = V2TrafficFlow::V2TrafficFlowType::UNKNOWN_FLOW; break; } env_info_->traffic_flows.emplace_back(traffic_flow); SD_ENV_INFO_LOG << fmt::format("Set traffic_flows with size: {}", env_info_->traffic_flows.size()); // 从 sd_route 计算 v2_dist_to_subpath 和 v2_dist_to_split_routelanenum_dec env_info_->v2_dist_to_subpath = CalculateDistanceToSubpath(); env_info_->v2_dist_to_split_routelanenum_dec = CalculateDistanceToSplitRouteLaneNumDec(); SD_ENV_INFO_LOG << fmt::format("Set v2_dist_to_subpath: {}, v2_dist_to_split_routelanenum_dec: {}", env_info_->v2_dist_to_subpath, env_info_->v2_dist_to_split_routelanenum_dec); env_info_->v2_road_classes = CalculateV2RoadClasses(); env_info_->v2_turn_info = CalculateV2TurnInfo(stop_line_obj); env_info_->is_switched_to_LD_ = UpdateIsSwitchedToLD(map_event, sd_route); // SD_ENV_INFO_LOG << fmt::format( // "Exiting ProcessEnvInfo with env_info: v2_valid={}, v2_has_navigation={}, v2_dist_to_ramp={}, v2_dist_to_toll={}, " // "v2_dist_to_tunnel={}, v2_dist_to_subpath={}, v2_dist_to_split_routelanenum_dec={}, v2_curvatures_size={}, " // "traffic_flows_size={}, is_switched_to_LD_={}", // env_info_->v2_valid, env_info_->v2_has_navigation, env_info_->v2_dist_to_ramp, env_info_->v2_dist_to_toll, // env_info_->v2_dist_to_tunnel, env_info_->v2_dist_to_subpath, env_info_->v2_dist_to_split_routelanenum_dec, // env_info_->v2_curvatures.size(), env_info_->traffic_flows.size(), env_info_->is_switched_to_LD_); PrintEnvInfo(*env_info_); } bool EnvInfoProcessor::UpdateIsSwitchedToLD(const MapEvent &map_event, const SDRouteInfo &sd_route) { //城区不更新is_switched_to_LD_高速切图标志位 const bool on_highway = (env_info_ && env_info_->is_on_highway_); if (!on_highway) { is_switched_to_LD_ = false; accumulated_distance_ = 0.0; } ControlWayPoint control_type = map_event.control_waypoint_type; double control_dis = map_event.control_waypoint_dis; double remain_dis = -1.0; for (const auto &remain_info : map_event.remain_dis_info) { if (remain_info.remain_dis_type == RemainType::NAVI_MAP_MATCHED_END) { remain_dis = remain_info.remain_dis; break; } } static double s_last_ego_s = std::numeric_limits<double>::quiet_NaN(); const double ego_s = GetEgoGlobalS(sd_route); double ds = 0.0; if (std::isfinite(s_last_ego_s)) { ds = std::max(0.0, ego_s - s_last_ego_s); // 抗回退 } s_last_ego_s = ego_s; // 判断当前是否在闸道内 const bool in_ramp = CheckIfInRamp(sd_route); // —— 兜底触发用:高速→非高速的下降沿(防止错过“出闸道”边沿)—— static bool s_last_on_highway = false; const bool highway_fall_edge = (!on_highway && s_last_on_highway); // —— 边沿:刚刚“出闸道” —— const bool ramp_exit_edge = (!in_ramp && last_in_ramp_); // 判断是否即将进入闸道(控制点为进入闸道类型且距离小于 800 米) bool approaching_ramp = (control_type == ControlWayPoint::COMING_LEFT_ONTO_THE_RAMP || control_type == ControlWayPoint::COMING_RIGHT_ONTO_THE_RAMP) && control_dis <= LD_MAP_ACTIVATION_DIST_THRESH; // 状态1:在闸道内,切换到 LD 模式 if (in_ramp) { is_switched_to_LD_ = true; is_accumulated_valid_ = false; accumulated_distance_ = 0.0; last_in_ramp_ = in_ramp; last_remain_dis_ = remain_dis; SD_ENV_INFO_LOG << fmt::format("Vehicle is in ramp, set is_switched_to_LD_: true"); return is_switched_to_LD_; } // 状态2:不在闸道内,即将进入闸道(控制点距离 < 800 米) if (approaching_ramp) { is_switched_to_LD_ = true; is_accumulated_valid_ = false; accumulated_distance_ = 0.0; last_in_ramp_ = in_ramp; last_remain_dis_ = remain_dis; SD_ENV_INFO_LOG << fmt::format("Approaching ramp (<= {} m), set is_switched_to_LD_: true", LD_MAP_ACTIVATION_DIST_THRESH); return is_switched_to_LD_; } // 状态3:不在闸道内,控制点距离 > 800 米 // else if (control_type == ControlWayPoint::COMING_LEFT_ONTO_THE_RAMP || control_type == ControlWayPoint::COMING_RIGHT_ONTO_THE_RAMP) { // is_switched_to_LD_ = false; // SD_ENV_INFO_LOG << fmt::format("Control point distance > 800m, set is_switched_to_LD_: false"); // } // 状态4 和 5:不在闸道内,根据离开闸道后的累积距离判断 if (ramp_exit_edge || (highway_fall_edge && is_switched_to_LD_ && !is_accumulated_valid_)) { is_accumulated_valid_ = true; accumulated_distance_ = 0.0; SD_ENV_INFO_LOG << fmt::format("Just exited ramp, reset accumulated_distance_ (edge={}, onHW_fall={})", ramp_exit_edge, highway_fall_edge); } if (is_accumulated_valid_) { // 计算累积行驶距离,过滤异常跳变 // double delta = std::abs(last_remain_dis_ - remain_dis); // if (delta <= MAX_REMAIN_DIS_JUMP) { // accumulated_distance_ += delta; // SD_ENV_INFO_LOG << fmt::format("Normal remain_dis change: {} meters, accumulated_distance_: {}", delta, accumulated_distance_); // } else { // SD_ENV_INFO_LOG << fmt::format("Detected abnormal remain_dis jump: {} meters, skip accumulation", delta); // } accumulated_distance_ += ds; SD_ENV_INFO_LOG << fmt::format("Accumulating: +{:.2f}m → {:.2f}m", ds, accumulated_distance_); // 根据累积距离判断 LD 模式 if (accumulated_distance_ >= LD_MAP_DEACTIVATION_DIST_THRESH) { is_switched_to_LD_ = false; // 状态5:累积距离 >= 300 米 is_accumulated_valid_ = false; SD_ENV_INFO_LOG << fmt::format("Accumulated distance >= 300m, exit LD mode"); } else { is_switched_to_LD_ = true; // 状态4:累积距离 < 300 米 SD_ENV_INFO_LOG << fmt::format("Accumulated distance < 300m, maintain LD mode"); } last_in_ramp_ = in_ramp; last_remain_dis_ = remain_dis; s_last_on_highway = on_highway; return is_switched_to_LD_; } // 不在闸道、无冷却、也不临近闸道, 默认使用感知 is_switched_to_LD_ = false; last_remain_dis_ = remain_dis; s_last_on_highway = on_highway; return is_switched_to_LD_; } const EnvInfo *EnvInfoProcessor::GetEnvInfo() const { return env_info_.get(); } bool EnvInfoProcessor::CheckIfInRamp(const SDRouteInfo &sd_route) { // SD_ENV_INFO_LOG << fmt::format("Entering CheckIfInRamp"); uint64_t ego_section_id = sd_route.navi_start.section_id; for (const auto &sec : sd_route.mpp_sections) { if (sec.id == ego_section_id) { bool is_ramp = IsRampSection(sec); SD_ENV_INFO_LOG << fmt::format("Section {} is_ramp: {}", ego_section_id, is_ramp); return is_ramp; } } // SD_ENV_INFO_LOG << fmt::format("No matching section found, returning false"); return false; } bool EnvInfoProcessor::IsRampSection(const SDSectionInfo &section_info) { SD_ENV_INFO_LOG << fmt::format("Entering IsRampSection for section_id: {}", section_info.id); // if ((section_info.link_type & static_cast<uint32_t>(SDLinkTypeMask::SDLT_RAMP)) == static_cast<uint32_t>(SDLinkTypeMask::SDLT_RAMP)) { // SD_ENV_INFO_LOG << "Section is ramp due to link_type"; // return true; // } if (section_info.direction == SDDirectionType::BIDIRECTIONAL_PASSABLE) { return false; } uint32_t section_type = section_info.link_type; if ((section_type & (uint32_t)SDLinkTypeMask::SDLT_JCT) == (uint32_t)SDLinkTypeMask::SDLT_JCT || (section_type & (uint32_t)SDLinkTypeMask::SDLT_IC) == (uint32_t)SDLinkTypeMask::SDLT_IC || (section_type & (uint32_t)SDLinkTypeMask::SDLT_SERVICE) == (uint32_t)SDLinkTypeMask::SDLT_SERVICE || (section_type & (uint32_t)SDLinkTypeMask::SDLT_PARK) == (uint32_t)SDLinkTypeMask::SDLT_PARK || (section_type & (uint32_t)SDLinkTypeMask::SDLT_RAMP) == (uint32_t)SDLinkTypeMask::SDLT_RAMP || (section_info.road_class == SDRoadClass::SD_OTHER_ROAD && (section_type & (uint32_t)SDLinkTypeMask::SDLT_POICONNECTION) == (uint32_t)SDLinkTypeMask::SDLT_POICONNECTION)) { return true; } else { return false; } //测试发现ld地图存在非闸道section里面存在lane是RAMP问题,先注销该逻辑 // for (const auto &lg_idx : section_info.lane_group_idx) { // const auto *lane_group = INTERNAL_PARAMS.sd_map_data.GetSDLaneGroupInfoById(lg_idx.id); // if (lane_group) { // for (const auto &lane : lane_group->lane_info) { // if (lane.type == LaneType::LANE_RAMP) { // SD_ENV_INFO_LOG << "Section is ramp due to lane type"; // return true; // } // } // } // } // SD_ENV_INFO_LOG << "Section is not ramp"; return false; } double EnvInfoProcessor::CalculateDistanceToSubpath() { SD_ENV_INFO_LOG << fmt::format("Entering CalculateDistanceToSubpath"); if (INTERNAL_PARAMS.sd_map_data.GetSDRouteInfoPtr() == nullptr) { AWARN << "[EnvInfoProcessor] SDRouteInfo is null in CalculateDistanceToSubpath"; SD_ENV_INFO_LOG << fmt::format("SDRouteInfo is null, returning default large distance"); return DEFAULT_LARGE_DISTANCE; } const auto &sd_route = *INTERNAL_PARAMS.sd_map_data.GetSDRouteInfoPtr(); double ego_global_s = GetEgoGlobalS(sd_route); double min_dist = DEFAULT_LARGE_DISTANCE; std::unordered_set<uint64_t> route_section_ids; for (const auto &sec : sd_route.mpp_sections) { route_section_ids.insert(sec.id); } for (const auto &subpath : sd_route.subpaths) { if (subpath.path_type == SDPathType::MERGE || subpath.path_type == SDPathType::SPLIT) { uint64_t enter_section_id = subpath.enter_section_id; if (route_section_ids.find(enter_section_id) == route_section_ids.end()) { SD_ENV_INFO_LOG << fmt::format("Subpath section_id {} not in route, skipping", enter_section_id); continue; } auto enter_section = INTERNAL_PARAMS.sd_map_data.GetSDSectionInfoById(enter_section_id); if (!enter_section) { SD_ENV_INFO_LOG << fmt::format("Enter section {} not found, skipping", enter_section_id); continue; } double section_start_s = GetSectionStartS(*enter_section, sd_route); double section_end_s = section_start_s + enter_section->length; double target_s = (subpath.path_type == SDPathType::MERGE) ? section_start_s : section_end_s; double dist = target_s - ego_global_s; if (dist >= 0 && dist < min_dist) { min_dist = dist; // SD_ENV_INFO_LOG << "Updated min_dist to " << min_dist << " for subpath section_id: " << enter_section_id; } } } // SD_ENV_INFO_LOG << "Returning min_dist: " << min_dist; return min_dist; } double EnvInfoProcessor::CalculateDistanceToSplitRouteLaneNumDec() { // SD_ENV_INFO_LOG << fmt::format("Entering CalculateDistanceToSplitRouteLaneNumDec"); if (INTERNAL_PARAMS.sd_map_data.GetSDRouteInfoPtr() == nullptr) { AWARN << "[EnvInfoProcessor] SDRouteInfo is null in CalculateDistanceToSplitRouteLaneNumDec"; SD_ENV_INFO_LOG << fmt::format("SDRouteInfo is null, returning default large distance"); return DEFAULT_LARGE_DISTANCE; } const auto &sd_route = *INTERNAL_PARAMS.sd_map_data.GetSDRouteInfoPtr(); double ego_global_s = GetEgoGlobalS(sd_route); double min_dist = DEFAULT_LARGE_DISTANCE; for (const auto &subpath : sd_route.subpaths) { if (subpath.path_type != SDPathType::SPLIT) { // SD_ENV_INFO_LOG << fmt::format("Subpath is not SPLIT, skipping"); continue; } uint64_t enter_section_id = subpath.enter_section_id; auto enter_section = INTERNAL_PARAMS.sd_map_data.GetSDSectionInfoById(enter_section_id); if (!enter_section) { SD_ENV_INFO_LOG << fmt::format("Enter section {} not found, skipping", enter_section_id); continue; } // 获取 enter_section 的最后一个 lanegroup if (enter_section->lane_group_idx.empty()) { // SD_ENV_INFO_LOG << fmt::format("No lane groups in section {}, skipping", enter_section_id); continue; } // 获取 enter_section 的车道数 int enter_lane_num = -1; uint64_t last_lg_id = enter_section->lane_group_idx.back().id; const auto *last_lg = INTERNAL_PARAMS.sd_map_data.GetSDLaneGroupInfoById(last_lg_id); if (!last_lg) { enter_lane_num = GetLaneNumWithoutEmergency(last_lg); } else { // SD_ENV_INFO_LOG << fmt::format("Last lane group {} not found, skipping", last_lg_id); enter_lane_num = static_cast<int>(enter_section->lane_num); } // 遍历后继 section for (uint64_t successor_id : enter_section->successor_section_id_list) { auto successor_section = INTERNAL_PARAMS.sd_map_data.GetSDSectionInfoById(successor_id); if (!successor_section || !successor_section->is_mpp_section) { // SD_ENV_INFO_LOG << fmt::format("Successor section {} not found or not MPP, skipping", successor_id); continue; } // 获取 successor_section 的第一个 lanegroup if (successor_section->lane_group_idx.empty()) { // SD_ENV_INFO_LOG << fmt::format("No lane groups in successor section {}, skipping", successor_id); continue; } uint64_t first_successor_lg_id = successor_section->lane_group_idx.front().id; const auto *first_successor_lg = INTERNAL_PARAMS.sd_map_data.GetSDLaneGroupInfoById(first_successor_lg_id); if (!first_successor_lg) { SD_ENV_INFO_LOG << fmt::format("First successor lane group {} not found, skipping", first_successor_lg_id); continue; } // 检查车道后继 bool all_successors_in_first_lg = true; for (const auto &lane : last_lg->lane_info) { for (uint64_t successor_lane_id : lane.next_lane_ids) { bool found = false; for (const auto &successor_lane : first_successor_lg->lane_info) { if (successor_lane.id == successor_lane_id) { found = true; break; } } if (!found) { all_successors_in_first_lg = false; break; } } if (!all_successors_in_first_lg) { break; } } // 获取 successor_section 的车道数 int next_lane_num = GetSDSectionMinLaneNumNOTEmergency(*successor_section); // 判断条件:车道数减少 或 后继车道不全部在下一个 lanegroup 中 if (enter_lane_num > next_lane_num || !all_successors_in_first_lg) { double split_s = GetSectionStartS(*enter_section, sd_route) + enter_section->length; double dist = split_s - ego_global_s; if (dist >= 0 && dist < min_dist) { min_dist = dist; // SD_ENV_INFO_LOG << fmt::format("Condition met at section {} (lane decrease: {}, successor check: {}), updated min_dist: {}", // enter_section_id, (enter_lane_num > next_lane_num), !all_successors_in_first_lg, min_dist); } } } } // SD_ENV_INFO_LOG << fmt::format("Returning min_dist: {}", min_dist); return min_dist; } double EnvInfoProcessor::GetEgoGlobalS(const SDRouteInfo &sd_route) const { // SD_ENV_INFO_LOG << fmt::format("Entering GetEgoGlobalS"); double ego_global_s = 0.0; uint64_t ego_section_id = sd_route.navi_start.section_id; double ego_s_offset = sd_route.navi_start.s_offset; for (const auto &sec : sd_route.mpp_sections) { if (sec.id == ego_section_id) { ego_global_s += ego_s_offset; break; } ego_global_s += sec.length; } // SD_ENV_INFO_LOG << fmt::format("Returning ego_global_s: {}", ego_global_s); return ego_global_s; } double EnvInfoProcessor::GetSectionStartS(const SDSectionInfo &section, const SDRouteInfo &sd_route) const { // SD_ENV_INFO_LOG << "Entering GetSectionStartS for section_id: " << section.id; double current_s = 0.0; for (const auto &sec : sd_route.mpp_sections) { if (sec.id == section.id) { // SD_ENV_INFO_LOG << fmt::format("Returning current_s: {}", current_s); return current_s; } current_s += sec.length; } // SD_ENV_INFO_LOG << fmt::format("Section not found, returning current_s: {}", current_s); return current_s; } int EnvInfoProcessor::GetLaneNumWithoutEmergency(const SDLaneGroupInfo *lanegroup) { SD_ENV_INFO_LOG << fmt::format("Entering GetLaneNumWithoutEmergency"); if (!lanegroup) { SD_ENV_INFO_LOG << fmt::format("Lane group is null, returning 0"); return 0; } int count = 0; for (const auto &lane : lanegroup->lane_info) { if (lane.type != LaneType::LANE_EMERGENCY) { count++; } } SD_ENV_INFO_LOG << fmt::format("Returning non-emergency lane count: {}", count); return count; } int EnvInfoProcessor::GetSDSectionMinLaneNumNOTEmergency(const SDSectionInfo &section_info) { // SD_ENV_INFO_LOG << fmt::format("Entering GetSDSectionMinLaneNumNOTEmergency for section_id: {}", section_info.id); if (section_info.lane_group_idx.empty()) { SD_ENV_INFO_LOG << fmt::format("No lane groups, returning section lane_num: {}", section_info.lane_num); return static_cast<int>(section_info.lane_num); } int min_lane_num = std::numeric_limits<int>::max(); for (const auto &lane_group_id_tmp : section_info.lane_group_idx) { auto lane_group = INTERNAL_PARAMS.sd_map_data.GetSDLaneGroupInfoById(lane_group_id_tmp.id); if (lane_group) { int emergency_lane_count = 0; for (const auto &lane_info_tmp : lane_group->lane_info) { if (lane_info_tmp.type == LaneType::LANE_EMERGENCY) { emergency_lane_count++; } } int current_lane_num = lane_group->lane_info.size() - emergency_lane_count; if (current_lane_num < min_lane_num) { min_lane_num = current_lane_num; } } } if (min_lane_num == std::numeric_limits<int>::max()) { SD_ENV_INFO_LOG << fmt::format("No valid lane groups, returning section lane_num: {}", section_info.lane_num); return section_info.lane_num != 0 ? static_cast<int>(section_info.lane_num) : 0; } int result = min_lane_num == 0 ? static_cast<int>(section_info.lane_num) : min_lane_num; // SD_ENV_INFO_LOG << fmt::format("Returning min non-emergency lane count: {}", result); return result; } V2RoadClassType EnvInfoProcessor::ConvertSDRoadClassToV2RoadClassType(SDRoadClass sd_road_class) const { switch (sd_road_class) { case SDRoadClass::SD_HIGHWAY: return V2RoadClassType::HIGH_WAY_ROAD; case SDRoadClass::SD_CITY_FAST_WAY: return V2RoadClassType::EXPRESS_WAY_ROAD; case SDRoadClass::SD_NATIONAL_ROAD: return V2RoadClassType::NATIOANL_ROAD; case SDRoadClass::SD_PROVINCIAL_ROAD: return V2RoadClassType::PROVINCIAL_ROAD; case SDRoadClass::SD_COUNTY_ROAD: case SDRoadClass::SD_TOWNSHIP_ROAD: return V2RoadClassType::MAIN_ROAD; case SDRoadClass::SD_OTHER_ROAD: case SDRoadClass::SD_LEVEL_9_ROAD: case SDRoadClass::SD_FERRY: case SDRoadClass::SD_WALY_WAY: case SDRoadClass::SD_INVALID: return V2RoadClassType::UNKNOWN_ROAD; default: return V2RoadClassType::UNKNOWN_ROAD; } } std::vector<V2RoadClass> EnvInfoProcessor::CalculateV2RoadClasses() const { if (INTERNAL_PARAMS.sd_map_data.GetSDRouteInfoPtr() == nullptr) { AWARN << "[EnvInfoProcessor] SDRouteInfo is null"; SD_ENV_INFO_LOG << fmt::format("SDRouteInfo is null, exiting"); return {}; } const auto &sd_route = *INTERNAL_PARAMS.sd_map_data.GetSDRouteInfoPtr(); if (sd_route.mpp_sections.empty()) { return {}; } double ego_global_s = GetEgoGlobalS(sd_route); std::vector<V2RoadClass> v2_road_classes; v2_road_classes.clear(); double first_start_s = GetSectionStartS(sd_route.mpp_sections[0], sd_route); double first_end_s = first_start_s + sd_route.mpp_sections[0].length; V2RoadClass current{first_start_s - ego_global_s, first_end_s - ego_global_s, ConvertSDRoadClassToV2RoadClassType(sd_route.mpp_sections[0].road_class)}; // Process remaining sections for (size_t i = 1; i < sd_route.mpp_sections.size(); ++i) { const auto &section = sd_route.mpp_sections[i]; double start_s = GetSectionStartS(section, sd_route); double end_s = start_s + section.length; auto type = ConvertSDRoadClassToV2RoadClassType(section.road_class); // SD_ENV_INFO_LOG << "Section_id: " << section.id <<" start_s: " << start_s << " end_s: " << end_s << " type: " << static_cast<int>(section.road_class); if (type == current.road_class) { // Same road class type, extend the current segment current.end = end_s - ego_global_s; } else { // Different road class type, save current and start a new segment v2_road_classes.push_back(current); current = {start_s - ego_global_s, // Start relative to ego end_s - ego_global_s, // End relative to ego type}; } } // Add the last segment v2_road_classes.push_back(current); return v2_road_classes; } UTurnPosition EnvInfoProcessor::FindUTurnLanePosition(const std::vector<TurnType> &lane_arrows) { if (lane_arrows.empty()) return UTurnPosition::UNKNOWN; // 查找最左侧和最右侧的 U-turn 车道 bool leftmost_has_uturn = false; bool rightmost_has_uturn = false; for (size_t i = 0; i < lane_arrows.size(); ++i) { if (lane_arrows[i] == TurnType::STRAIGHT_AND_U_TURN || lane_arrows[i] == TurnType::LEFT_TURN_AND_U_TURN || lane_arrows[i] == TurnType::STRAIGHT_AND_LEFT_TURN_AND_U_TURN) { if (i == 0) leftmost_has_uturn = true; } if (lane_arrows[i] == TurnType::STRAIGHT_AND_U_TURN || lane_arrows[i] == TurnType::RIGHT_TURN_AND_U_TURN || lane_arrows[i] == TurnType::STRAIGHT_AND_RIGHT_TURN_AND_U_TURN) { if (i == lane_arrows.size() - 1) rightmost_has_uturn = true; } } if (leftmost_has_uturn) return UTurnPosition::LEFTMOST; if (rightmost_has_uturn) return UTurnPosition::RIGHTMOST; return UTurnPosition::UNKNOWN; } std::pair<V2TurnInfo::V2TurnType, V2TurnInfo::V2DetailTurnType> EnvInfoProcessor::GetTurnInfoForRoadSplit(JunctionAction action) { static const std::map<JunctionAction, std::pair<V2TurnInfo::V2TurnType, V2TurnInfo::V2DetailTurnType>> turn_map = { {JunctionAction::TurnLeft, {V2TurnInfo::V2TurnType::LEFT, V2TurnInfo::V2DetailTurnType::SLIGHT_LEFT}}, {JunctionAction::TurnRight, {V2TurnInfo::V2TurnType::RIGHT, V2TurnInfo::V2DetailTurnType::SLIGHT_RIGHT}}, {JunctionAction::GoStraight, {V2TurnInfo::V2TurnType::STRAIGHT, V2TurnInfo::V2DetailTurnType::CONTINUE}}}; auto it = turn_map.find(action); if (it != turn_map.end()) { return it->second; } return {V2TurnInfo::V2TurnType::UNKNOWN, V2TurnInfo::V2DetailTurnType::NONE}; } std::vector<V2TurnInfo> EnvInfoProcessor::CalculateV2TurnInfo(const std::vector<cem::message::env_model::StopLine> &stop_line_obj) { if (!env_info_) { SD_ENV_INFO_LOG << fmt::format("EnvInfo is null, returning empty turn info"); return {}; } // 根据Master层计算的is_on_highway_ 区分处理高速还是城区逻辑 if (env_info_->is_on_highway_) { SD_ENV_INFO_LOG << fmt::format("is_on_highway_ is: {}, Processing highway logic.", env_info_->is_on_highway_); auto highway_junctions_ptr = INTERNAL_PARAMS.navigation_info_data.GetJunctionInfoPtr(); if (highway_junctions_ptr) { return ProcessHighwayJunctions(stop_line_obj, *highway_junctions_ptr); } else { SD_ENV_INFO_LOG << fmt::format("Highway junctions pointer is null, returning empty turn info"); return {}; } } else { SD_ENV_INFO_LOG << fmt::format("is_on_highway_ is: {}, Processing city logic.", env_info_->is_on_highway_); auto city_junctions_ptr = INTERNAL_PARAMS.navigation_info_data.GetJunctionInfoCityPtr(); if (city_junctions_ptr) { return ProcessCityJunctions(stop_line_obj, *city_junctions_ptr); } else { SD_ENV_INFO_LOG << fmt::format("City junctions pointer is null, returning empty turn info"); return {}; } } } std::vector<V2TurnInfo> EnvInfoProcessor::ProcessCityJunctions(const std::vector<cem::message::env_model::StopLine> &stop_line_obj, const std::vector<navigation::JunctionInfoCity> &city_junctions) { if (city_junctions.empty()) { return {}; } std::vector<V2TurnInfo> turn_infos; turn_infos.clear(); std::vector<uint64_t> v2_junction_ids = INTERNAL_PARAMS.navigation_info_data.get_v2_junction_ids(); for (const auto &junction : city_junctions) { auto find_v2 = std::find(v2_junction_ids.begin(), v2_junction_ids.end(), junction.junction_id); if (find_v2 == v2_junction_ids.end()) { continue; } SD_ENV_INFO_LOG << fmt::format("{}", junction); V2TurnInfo turn_info; turn_info.id = junction.junction_id; turn_info.is_valid = true; // 处理 RoadSplit 路口的特殊逻辑 if (junction.junction_type_city == JunctionTypeCity::RoadSplit) { // 检查是否为右转专用道 if (junction.is_dedicated_right_turn_lane && junction.split_merge_direction == DirectionSplitMerge::Right) { turn_info.turn_type = V2TurnInfo::V2TurnType::RIGHT; turn_info.detail_turn_type = V2TurnInfo::V2DetailTurnType::TURN_RIGHT_ONLY; } else { // 非右转专用道的RoadSplit路口,使用原默认逻辑 auto [turn_type, detail_turn_type] = GetTurnInfoForRoadSplit(junction.junction_action); turn_info.turn_type = turn_type; turn_info.detail_turn_type = detail_turn_type; } } else { // 其他路口类型的原有逻辑 switch (junction.junction_action) { case JunctionAction::TurnLeft: turn_info.turn_type = V2TurnInfo::V2TurnType::LEFT; turn_info.detail_turn_type = V2TurnInfo::V2DetailTurnType::TURN_LEFT; break; case JunctionAction::TurnRight: turn_info.turn_type = V2TurnInfo::V2TurnType::RIGHT; turn_info.detail_turn_type = V2TurnInfo::V2DetailTurnType::TURN_RIGHT; break; case JunctionAction::GoStraight: turn_info.turn_type = V2TurnInfo::V2TurnType::STRAIGHT; turn_info.detail_turn_type = V2TurnInfo::V2DetailTurnType::CONTINUE; break; case JunctionAction::UTurn: { UTurnPosition uturn_pos = FindUTurnLanePosition(junction.map_lane_arrows_plan); if (uturn_pos == UTurnPosition::LEFTMOST) { turn_info.turn_type = V2TurnInfo::V2TurnType::U_TURN_LEFT; } else if (uturn_pos == UTurnPosition::RIGHTMOST) { turn_info.turn_type = V2TurnInfo::V2TurnType::U_TURN_RIGHT; } turn_info.detail_turn_type = V2TurnInfo::V2DetailTurnType::UTURN; break; } default: turn_info.turn_type = V2TurnInfo::V2TurnType::UNKNOWN; turn_info.detail_turn_type = V2TurnInfo::V2DetailTurnType::NONE; break; } } turn_info.v2_dist = junction.offset; if (!stop_line_obj.empty() && (std::fabs(stop_line_obj.at(0).distance_to_stopline - turn_info.v2_dist) < 30.0)) { SD_ENV_INFO_LOG << fmt::format("Using stopline dist to calib dist_v2"); turn_info.dist = stop_line_obj.at(0).distance_to_stopline; } else { turn_info.dist = turn_info.v2_dist; } turn_info.before_turn.lane_num = junction.main_road_lane_nums; turn_info.after_turn.lane_num = junction.target_road_lane_nums; if (!junction.junction_ids.empty()) { uint64_t before_section_id = junction.junction_ids.front(); auto before_section = INTERNAL_PARAMS.sd_map_data.GetSDSectionInfoById(before_section_id); if (before_section) { turn_info.before_turn.road_class = ConvertSDRoadClassToV2RoadClassType(before_section->road_class); } else { turn_info.before_turn.road_class = V2RoadClassType::UNKNOWN_ROAD; SD_ENV_INFO_LOG << fmt::format("Before section {} not found for junction {}", before_section_id, junction.junction_id); } uint64_t after_section_id = junction.junction_ids.back(); auto after_section = INTERNAL_PARAMS.sd_map_data.GetSDSectionInfoById(after_section_id); if (after_section) { turn_info.after_turn.road_class = ConvertSDRoadClassToV2RoadClassType(after_section->road_class); } else { turn_info.after_turn.road_class = V2RoadClassType::UNKNOWN_ROAD; SD_ENV_INFO_LOG << fmt::format("After section {} not found for junction {}", after_section_id, junction.junction_id); } } else { turn_info.before_turn.road_class = V2RoadClassType::UNKNOWN_ROAD; turn_info.after_turn.road_class = V2RoadClassType::UNKNOWN_ROAD; SD_ENV_INFO_LOG << fmt::format("Junction {} has empty junction_ids", junction.junction_id); } turn_infos.push_back(turn_info); } return turn_infos; } std::vector<V2TurnInfo> EnvInfoProcessor::ProcessHighwayJunctions(const std::vector<cem::message::env_model::StopLine> &stop_line_obj, const std::vector<navigation::JunctionInfo> &highway_junctions) { std::vector<V2TurnInfo> turn_infos; std::vector<uint64_t> v2_junction_ids = INTERNAL_PARAMS.navigation_info_data.get_v2_junction_ids(); // 定义闸道里分叉路口类型集合 std::unordered_set<JunctionType> split_types = {JunctionType::RampSplitLeft, JunctionType::RampSplitRight, JunctionType::RampSplitMiddle}; for (const auto &junction : highway_junctions) { auto find_v2 = std::find(v2_junction_ids.begin(), v2_junction_ids.end(), junction.junction_id); if (find_v2 == v2_junction_ids.end()) { continue; } SD_ENV_INFO_LOG << fmt::format("Evaluating highway junction ID: {}, type: {}, SplitDirection: {}, offset: {}", junction.junction_id, static_cast<int>(junction.junction_type), static_cast<int>(junction.split_direction), junction.offset); V2TurnInfo turn_info; turn_info.id = junction.junction_id; turn_info.is_valid = true; // 检查是否为闸道里分叉路口类型 if (split_types.count(junction.junction_type)) { // 对于分叉路口,使用 split_direction 设置转向信息 switch (junction.split_direction) { case SplitDirection::Straight: turn_info.turn_type = V2TurnInfo::V2TurnType::STRAIGHT; turn_info.detail_turn_type = V2TurnInfo::V2DetailTurnType::CONTINUE; break; case SplitDirection::SplitLeft: turn_info.turn_type = V2TurnInfo::V2TurnType::LEFT; turn_info.detail_turn_type = V2TurnInfo::V2DetailTurnType::SLIGHT_LEFT; break; case SplitDirection::SplitRight: turn_info.turn_type = V2TurnInfo::V2TurnType::RIGHT; turn_info.detail_turn_type = V2TurnInfo::V2DetailTurnType::SLIGHT_RIGHT; break; default: turn_info.turn_type = V2TurnInfo::V2TurnType::UNKNOWN; turn_info.detail_turn_type = V2TurnInfo::V2DetailTurnType::NONE; break; } } else { // 对于非分叉路口,保留原有 junction_type 逻辑 switch (junction.junction_type) { case JunctionType::RampInto: turn_info.turn_type = V2TurnInfo::V2TurnType::RIGHT; turn_info.detail_turn_type = V2TurnInfo::V2DetailTurnType::SLIGHT_RIGHT; break; case JunctionType::ApproachRampInto: turn_info.turn_type = V2TurnInfo::V2TurnType::STRAIGHT; turn_info.detail_turn_type = V2TurnInfo::V2DetailTurnType::CONTINUE; break; default: turn_info.turn_type = V2TurnInfo::V2TurnType::UNKNOWN; turn_info.detail_turn_type = V2TurnInfo::V2DetailTurnType::NONE; break; } } turn_info.v2_dist = junction.offset; turn_info.dist = turn_info.v2_dist; turn_info.before_turn.lane_num = junction.main_road_lane_nums; turn_info.after_turn.lane_num = junction.target_road_lane_nums; if (!junction.junction_ids.empty()) { uint64_t before_section_id = junction.junction_ids.front(); auto before_section = INTERNAL_PARAMS.sd_map_data.GetSDSectionInfoById(before_section_id); if (before_section) { turn_info.before_turn.road_class = ConvertSDRoadClassToV2RoadClassType(before_section->road_class); } else { turn_info.before_turn.road_class = V2RoadClassType::UNKNOWN_ROAD; SD_ENV_INFO_LOG << fmt::format("Before section {} not found for junction {}", before_section_id, junction.junction_id); } uint64_t after_section_id = junction.junction_ids.back(); auto after_section = INTERNAL_PARAMS.sd_map_data.GetSDSectionInfoById(after_section_id); if (after_section) { turn_info.after_turn.road_class = ConvertSDRoadClassToV2RoadClassType(after_section->road_class); } else { turn_info.after_turn.road_class = V2RoadClassType::UNKNOWN_ROAD; SD_ENV_INFO_LOG << fmt::format("After section {} not found for junction {}", after_section_id, junction.junction_id); } } else { turn_info.before_turn.road_class = V2RoadClassType::UNKNOWN_ROAD; turn_info.after_turn.road_class = V2RoadClassType::UNKNOWN_ROAD; SD_ENV_INFO_LOG << fmt::format("Junction {} has empty junction_ids", junction.junction_id); } turn_infos.push_back(turn_info); } return turn_infos; } void EnvInfoProcessor::SetIsOnHighway(bool is_on_highway) { if (env_info_) { env_info_->is_on_highway_ = is_on_highway; // SD_ENV_INFO_LOG << fmt::format("Set value is_on_highway:{}", env_info_->is_on_highway_); } } void EnvInfoProcessor::PrintEnvInfo(const EnvInfo &env_info) const { SD_ENV_INFO_LOG << fmt::format("{}", env_info); } } // namespace navigation } // namespace fusion } // namespace cem详细解释下代码
08-29
import PySimpleGUI as Py import time import os # ======== 全局设置 ======== Py.theme('Default') a = ' 漫息!' b = '【' # 图片路径定义(请确保这些路径在你电脑上真实存在) image_path2 = "D:/software/demo/pythonProject/images/image2.png" image_path3 = "D:/software/demo/pythonProject/images/image3.png" image_path4 = "D:/software/demo/pythonProject/images/image4.png" image_path5 = "D:/software/demo/pythonProject/images/image5.png" image_path6 = "D:/software/demo/pythonProject/images/image6.png" image_path7 = "D:/software/demo/pythonProject/images/image7.png" image_path8 = "D:/software/demo/pythonProject/images/image8.png" image_path9 = "D:/software/demo/pythonProject/images/image9.png" # 检查图片是否存在 def check_image(path): if not os.path.exists(path): print(f"[!] 图片不存在: {path}") return None return path image_path2 = check_image(image_path2) image_path3 = check_image(image_path3) image_path4 = check_image(image_path4) image_path5 = check_image(image_path5) image_path6 = check_image(image_path6) image_path7 = check_image(image_path7) image_path8 = check_image(image_path8) image_path9 = check_image(image_path9) # ======== 全局窗口变量 ======== window10 = None # 用于保存 window10 的引用 # ======== 关闭 window10 的安全函数 ======== def close_window10(): global window10 if window10: try: window10.close() except Exception: pass window10 = None # ======== 周期性提醒功能 ======== reminder_running = False def run_periodic_reminder(): global reminder_running if reminder_running: print("[!] 提醒功能已在运行,忽略重复调用") return reminder_running = True layout9 = [ [Py.Image(key='img9', filename=image_path9) if image_path9 else Py.Text("加载失败")], [Py.Text("天", font=("华文楷体", 10), text_color='blue')], [Py.Text("📌 周期性提醒已激活:每次取消后10秒自动重试")], [Py.Multiline("", size=(60, 4), key='-OUTPUT-', disabled=True, autoscroll=True)], [Py.Button('退出', key='EXIT', button_color=('#800000', 'Silver')), Py.Text("", font=("华文楷体", 10), text_color='red')] ] window9_position = (1795, 300) window9 = Py.Window('', layout9, size=(460, 490), finalize=True, location=window9_position) window9.keep_on_top_set() next_popup_time = time.time() + 1 reminder_active = True popup_active = False input_popup = None can_exit = False # 控制是否允许退出 def show_input_popup(): layout_popup = [ [Py.Text(':')], [Py.Input(key='-INPUT-', size=(6, 1), font=("Arial", 20), focus=True), Py.Text('或', font=("华文楷体", 16), text_color='#000000'), Py.Text('动', font=("华文楷体", 22), text_color='red', background_color='#86A8FF')], [Py.Button('属于', key='BELONG', button_color=('#800000', 'white'), bind_return_key=True), Py.Push(), Py.Button('不属于', key='NOT_BELONG', button_color=('#000000', 'white'))] ] windowpopup_position = (1890, 680) return Py.Window('', layout_popup, keep_on_top=True, modal=True, location=windowpopup_position, finalize=True) try: while True: # 主窗口读取事件 try: event9, values9 = window9.read(timeout=100) except Exception as e: if "wrapped C/C++ object has been deleted" in str(e) or "TclError" in str(e): print("[INFO] 窗口已被系统关闭,退出提醒循环。") break else: print(f"[ERROR] Unexpected error: {e}") break # 处理退出按钮:只有 can_exit 为 True 时才响应 if event9 == 'EXIT': if not can_exit: window9['-OUTPUT-'].update("⚠️ 尚未完成验证,无法退出\n", append=True) continue else: close_window10() layout10 = [ [Py.Image(key='img2', filename=image_path2) if image_path2 else Py.Text("加载失败")], [Py.Text(a, size=(23, 200), auto_size_text=True)] ] window10_pos = (2340, 145) global window10 window10 = Py.Window('', layout10, size=(220, 750), location=window10_pos, finalize=True) window10.keep_on_top_set() break if event9 in (None, Py.WINDOW_CLOSED): break now = time.time() # 触发新弹窗 if reminder_active and not popup_active and next_popup_time and now >= next_popup_time: popup_active = True try: input_popup = show_input_popup() except Exception as e: print(f"[Error] 无法创建弹窗: {e}") popup_active = False next_popup_time = now + 10 continue # 处理 input_popup 弹窗逻辑 if input_popup: try: event_p, values_p = input_popup.read(timeout=100) except Exception as e: print(f"[Popup Error] {e}") input_popup = None popup_active = False window9['-OUTPUT-'].update("⚠️ 弹窗异常关闭,60秒后重试...\n", append=True) next_popup_time = time.time() + 60 continue if event_p == Py.WINDOW_CLOSED or event_p is None: try: input_popup.close() except Exception: pass input_popup = None popup_active = False window9['-OUTPUT-'].update("⛔ 弹窗被用户关闭,60秒后将再次提醒...\n", append=True) next_popup_time = time.time() + 60 continue user_input = values_p.get('-INPUT-', '').strip() valid_number = False try: if user_input: float(user_input) valid_number = True except ValueError: pass # 安全更新按钮状态 try: input_popup['BELONG'].update(disabled=not valid_number) except Exception: pass # 忽略失效窗口更新 if event_p == 'BELONG' and valid_number: try: num = float(user_input) formatted_num = int(num) if num.is_integer() else num window9['-OUTPUT-'].update(f"✔️ 录入成功:{formatted_num} —— 提醒停止\n", append=True) reminder_active = False next_popup_time = None can_exit = True except Exception: window9['-OUTPUT-'].update(f"❌ 输入处理失败:'{user_input}'\n", append=True) next_popup_time = time.time() + 60 finally: try: input_popup.close() except Exception: pass input_popup = None popup_active = False elif event_p == 'NOT_BELONG': try: input_popup.close() except Exception: pass input_popup = None popup_active = False window9['-OUTPUT-'].update("⛔ 用户取消,60秒后将再次提醒...\n", append=True) next_popup_time = time.time() + 60 finally: try: window9.close() except Exception: pass reminder_running = False # ======== 单次流程函数 run_single_flow ======== def run_single_flow(): input_history = [] current_text = '' layout4 = [ [Py.Image(key='img4', filename=image_path4) if image_path4 else Py.Text("加载失败")], [Py.Text("请在5秒内输入当前动量,之后5秒无操作将自动记录:")], [Py.Input(key='-INPUT-', size=(10, 1), font=("Arial", 20), focus=True), Py.Text("", size=(60, 1), key='-STATUS-')], [Py.Text(":")], [Py.Frame('', [[Py.Text("", size=(48, 15), key='-HISTORY-', relief='sunken', background_color='white', text_color='black', font=('Courier', 15))]], size=(590, 75), pad=10)], [Py.Button('美边', key='MEIBIAN', button_color=('#006400', 'Silver'), disabled=True)], [Py.Button('同向', key='TONGXIANG', button_color=('#000000', 'white'), disabled=True), Py.Button('不符合', key='CANCEL', button_color=('#800000', 'Silver'))] ] window4_position = (1795, 300) window4 = Py.Window('', layout4, size=(460, 500), resizable=True, location=window4_position, finalize=True) window4.keep_on_top_set() last_input_time = None while True: event4, values4 = window4.read(timeout=100) if event4 == Py.WINDOW_CLOSED or event4 == 'CANCEL': window4.close() return raw_input = values4['-INPUT-'].strip() changed = raw_input != current_text current_text = raw_input # 验证是否为有效数字 valid_number = False try: if current_text: float(current_text) valid_number = True except ValueError: pass # 更新按钮状态 window4['MEIBIAN'].update(disabled=not valid_number) window4['TONGXIANG'].update(disabled=not valid_number) if valid_number: window4['-STATUS-'].update(f"✅ 输入中 '{current_text}' ... 可提交") elif current_text: window4['-STATUS-'].update("❌ 请输入有效的数字") else: window4['-STATUS-'].update("") # 自动提交逻辑 if valid_number and changed: last_input_time = time.time() elif valid_number and last_input_time is not None: elapsed = time.time() - last_input_time remaining = max(0, int(5 - elapsed + 0.9)) if remaining > 0: window4['-STATUS-'].update(f"⏳ 还剩 {remaining} 秒自动提交...") else: try: num = float(current_text) formatted_num = int(num) if num.is_integer() else num input_history.append(formatted_num) history_str = ' '.join(map(str, input_history)) window4['-HISTORY-'].update(history_str) window4['-STATUS-'].update("🎉 已自动记录!") window4['-INPUT-'].update('') current_text = '' last_input_time = None except Exception: window4['-STATUS-'].update("❌ 提交失败") finally: window4['MEIBIAN'].update(disabled=True) window4['TONGXIANG'].update(disabled=True) # 处理按钮事件 if event4 == 'MEIBIAN' and valid_number: close_window10() window2.close() window4.close() run_periodic_reminder() return elif event4 == 'TONGXIANG' and valid_number: window4.close() _run_tongxiang_flow(input_history) return def _run_tongxiang_flow(input_history): current_text = '' layout5 = [ [Py.Image(key='img5', filename=image_path5) if image_path5 else Py.Text("加载失败")], [Py.Text("请在5秒内输入当前动量,之后5秒无操作将自动记录:")], [Py.Input(key='-INPUT-', size=(10, 1), font=("Arial", 20)), Py.Text("", size=(60, 1), key='-STATUS-')], [Py.Frame('', [[Py.Text("", size=(49, 15), key='-HISTORY-', relief='sunken', background_color='white', text_color='black', font=('Courier', 15))]], size=(410, 50), pad=10)], [Py.Button('进入弱', key='RUO', button_color=('#000000', 'Silver'), disabled=True), Py.Button('进入强', key='QIANG', button_color=('#000000', 'Silver'), disabled=True)] ] window5_position = (1795, 300) window5 = Py.Window('', layout5, size=(460, 430), resizable=True, location=window5_position, finalize=True) window5.keep_on_top_set() last_input_time = None while True: event5, values5 = window5.read(timeout=100) if event5 == Py.WINDOW_CLOSED: window5.close() return raw_input = values5['-INPUT-'].strip() changed = raw_input != current_text current_text = raw_input valid_number = False try: if current_text: float(current_text) valid_number = True except ValueError: pass window5['RUO'].update(disabled=not valid_number) window5['QIANG'].update(disabled=not valid_number) if valid_number: window5['-STATUS-'].update(f"✅ 输入中 '{current_text}' ... 可提交") elif current_text: window5['-STATUS-'].update("❌ 请输入有效的数字") else: window5['-STATUS-'].update("") if valid_number and changed: last_input_time = time.time() if valid_number and last_input_time is not None: elapsed = time.time() - last_input_time if elapsed >= 5.0: try: num = float(current_text) formatted_num = int(num) if num.is_integer() else num input_history.append(formatted_num) history_str = ' '.join(map(str, input_history)) window5['-HISTORY-'].update(history_str) window5['-STATUS-'].update("🎉 已自动记录!") window5['-INPUT-'].update('') current_text = '' last_input_time = None except Exception: window5['-STATUS-'].update("❌ 提交失败") finally: window5['RUO'].update(disabled=True) window5['QIANG'].update(disabled=True) if event5 == 'RUO' and valid_number: window5.close() _run_zhongjin_flow('RUO') return elif event5 == 'QIANG' and valid_number: window5.close() _run_zhongjin_flow('QIANG') return def _run_zhongjin_flow(mode): recorded_numbers = [] title = "【中进】" if mode == 'RUO' else "出现【再" btn_key = 'ZHONGJIN' if mode == 'RUO' else 'CHUXIAN_ZAI' layout = [ [Py.Image(key='img6' if mode == 'RUO' else 'img7', filename=image_path6 if mode == 'RUO' else image_path7)], [Py.Input(key='-INPUT-', size=(10, 1), font=("Arial", 20), do_not_clear=False)], [Py.Button(title, key=btn_key, button_color=('#006400', 'Silver'), bind_return_key=True, disabled=True), Py.Button('不于进', key='CLEAR_INPUT', button_color=('#800000', 'Silver'))], [Py.HorizontalSeparator()], [Py.Text("", size=(50, 2), key='-HISTORY-', relief='sunken', background_color='white', text_color='black')] ] pos_y = 300 if mode == 'RUO' else 350 window = Py.Window('', layout, size=(460, 395), location=(1795, pos_y), finalize=True) window.keep_on_top_set() while True: event, values = window.read() if event in (None, Py.WINDOW_CLOSED): break user_input = values['-INPUT-'].strip() valid_number = False try: if user_input: float(user_input) valid_number = True except ValueError: pass window[btn_key].update(disabled=not valid_number) if event == btn_key and valid_number: close_window10() window2.close() try: num = float(user_input) formatted_num = int(num) if num.is_integer() else num recorded_numbers.append(formatted_num) history_text = ' '.join(map(str, recorded_numbers)) window['-HISTORY-'].update(history_text) window['-INPUT-'].update('') except Exception: pass window.close() run_periodic_reminder() break elif event == 'CLEAR_INPUT': window['-INPUT-'].update('') window.close() # ======== 新增:_run_juezhan_flow ======== def _run_juezhan_flow(): current_text = '' layout8 = [ [Py.Image(key='img8', filename=image_path8) if image_path8 else Py.Text("加载失败")], [Py.Text("决战", font=("华文楷体", 13), text_color='blue')], [Py.Input(key='-INPUT-', size=(10, 1), font=("Arial", 20), focus=True), Py.Text("", size=(60, 1), key='-STATUS-')], [Py.Frame('', [[Py.Text("", size=(48, 15), key='-HISTORY-', relief='sunken', background_color='white', text_color='black', font=('Courier', 15))]], size=(590, 75), pad=10)], [Py.Button('败退', key='BUTUI', button_color=('#006400', 'Silver'), disabled=True), Py.Button('反击', key='FANJI', button_color=('#006400', 'Silver'), disabled=True), Py.Button('不符合', key='CANCEL', button_color=('#800000', 'Silver'))] ] window8_position = (1795, 300) window8 = Py.Window('', layout8, size=(460, 470), resizable=True, location=window8_position, finalize=True) window8.keep_on_top_set() input_history = [] last_input_time = None while True: event8, values8 = window8.read(timeout=100) if event8 == Py.WINDOW_CLOSED or event8 == 'CANCEL': window8.close() return raw_input = values8['-INPUT-'].strip() changed = raw_input != current_text current_text = raw_input valid_number = False try: if current_text: float(current_text) valid_number = True except ValueError: pass window8['BUTUI'].update(disabled=not valid_number) window8['FANJI'].update(disabled=not valid_number) if valid_number: window8['-STATUS-'].update(f"✅ 输入中 '{current_text}' ... 可提交") elif current_text: window8['-STATUS-'].update("❌ 请输入有效的数字") else: window8['-STATUS-'].update("") if valid_number and changed: last_input_time = time.time() if valid_number and last_input_time is not None: elapsed = time.time() - last_input_time if elapsed >= 5.0: try: num = float(current_text) formatted_num = int(num) if num.is_integer() else num input_history.append(formatted_num) history_str = ' '.join(map(str, input_history)) window8['-HISTORY-'].update(history_str) window8['-STATUS-'].update("🎉 已自动记录!") window8['-INPUT-'].update('') current_text = '' last_input_time = None except Exception: window8['-STATUS-'].update("❌ 提交失败") finally: window8['BUTUI'].update(disabled=True) window8['FANJI'].update(disabled=True) if event8 in ('BUTUI', 'FANJI') and valid_number: close_window10() window2.close() window8.close() run_periodic_reminder() return # ======== 主窗口 layout1 & window1 ======== layout1 = [[Py.Button(b, button_color=('#006400', 'white'), font=("华文楷体", 12))]] window1_position = (514, 24) window1 = Py.Window('', layout1, size=(1532, 44), no_titlebar=True, location=window1_position, finalize=True) window1.keep_on_top_set() # ======== 辅助窗口 layout2 & window2 ======== layout2 = [ [Py.Image(key='img2', filename=image_path2) if image_path2 else Py.Text("加载失败")], [Py.Text(a, size=(23, 200), auto_size_text=True)] ] window2_position = (2340, 145) window2 = Py.Window('', layout2, size=(220, 750), no_titlebar=True, location=window2_position, finalize=True) window2.keep_on_top_set() # ======== 主事件循环 ======== while True: event1, values1 = window1.read() if event1 == Py.WIN_CLOSED: break if event1 == b: layout3 = [ [Py.Image(key='img3', filename=image_path3) if image_path3 else Py.Text("加载失败")], [Py.Button('第1', key='TYPE1', button_color=('#006400', 'white')), Py.Push(), Py.Button('第3', key='TYPE3', button_color=('#006400', 'white'))] ] window3_position = (1795, 400) window3 = Py.Window('交易类型', layout3, size=(460, 190), location=window3_position, finalize=True, keep_on_top=True) window3.keep_on_top_set() while True: event3, values3 = window3.read() if event3 == Py.WINDOW_CLOSED: break if event3 == 'TYPE1': window3.close() run_single_flow() break if event3 == 'TYPE3': window3.close() _run_juezhan_flow() break try: window3.close() except Exception: pass # ======== 清理资源 ======== try: window1.close() window2.close() close_window10() except Exception: pass 在窗口中点击【中进】或者出现【再,run_periodic_reminder()不起作用
11-15
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值