wait_yn.c

  #include <stdio.h>
#include <ctype.h>
#include <conio.h>

void main(void)
 {
   char letter;               // Letter typed by the user

   printf("Do you want to continue? (Y/N): ");

   letter = getch();                  // Get the letter
   letter = toupper(letter);          // Convert letter to uppercase
  
   while ((letter != 'Y') && (letter != 'N'))
     {
       putch(7);                        // Beep the speaker
       letter = getch();                // Get the letter
       letter = toupper(letter);         // Convert letter to uppercase
     }

   printf("/nYour response was %c/n", letter);
 }

 

# 地质AI工作流系统完整部署方案(终极详细版) ## 📋 部署前准备 ### 系统要求检查 - ✅ 操作系统:Windows 11 - ✅ 可用存储空间:D盘至少100GB - ✅ 网络连接:稳定的互联网连接 --- ## 第一步:创建项目文件夹结构 ### 操作说明: 在D盘创建所有必要的文件夹,确保数据不会存储在C盘 ### 具体步骤: 1. **打开文件资源管理器** - 按 `Win + E` 打开文件资源管理器 - 点击左侧的"**此电脑**" - 双击进入"**D盘**" 2. **创建主文件夹** - 在D盘空白处右键点击 - 选择"**新建**" → "**文件夹**" - 输入文件夹名称:`GeologyAI` - 按回车确认 3. **创建自动化脚本** - 在桌面上右键 → **新建** → **文本文档** - 重命名为:`01-创建文件夹.bat` - 右键点击此文件 → 选择"**编辑**" - 复制粘贴以下代码: ```batch @echo off chcp 65001 >nul title 地质AI系统 - 文件夹创建工具 setlocal enabledelayedexpansion echo ========================================== echo 地质AI工作流系统部署工具 echo 步骤1:创建文件夹 echo ========================================== echo. :: 设置变量 set "RootPath=D:\GeologyAI" set "LogFile=%RootPath%\部署日志.txt" :: 创建根目录 echo [1/3] 创建根目录... if not exist "%RootPath%" ( mkdir "%RootPath%" if exist "%RootPath%" ( echo ✅ 成功创建根目录: %RootPath% ) else ( echo ❌ 错误:无法创建根目录 pause exit /b 1 ) ) else ( echo ⚠ 根目录已存在: %RootPath% ) :: 创建子文件夹 echo [2/3] 创建子文件夹结构... set folders[0]=DockerData set folders[1]=Ollama set folders[2]=RAGFlow set folders[3]=Dify set folders[4]=Templates set folders[5]=Templates\矿产勘查 set folders[6]=Templates\水工环地质 set folders[7]=Templates\岩土工程 set folders[8]=Templates\通用模板 set folders[9]=数据备份 set folders[10]=项目文档 set folders[11]=日志文件 set folders[12]=系统配置 for /l %%i in (0,1,12) do ( set "folder=!folders[%%i]!" if not exist "%RootPath%\!folder!" ( mkdir "%RootPath%\!folder!" echo ✅ 创建: !folder! ) else ( echo ⚠ 已存在: !folder! ) ) :: 设置权限 echo [3/3] 设置文件夹权限... for /l %%i in (0,1,12) do ( set "folder=!folders[%%i]!" icacls "%RootPath%\!folder!" /grant:r "Users:(OI)(CI)F" >nul 2>&1 ) echo ✅ 权限设置完成 :: 显示结果 echo. echo ========================================== echo ✅ 文件夹创建完成! echo 📁 根目录: %RootPath% echo. echo 创建的文件夹结构: tree "%RootPath%" /A echo. echo 下一步:请运行 "02-安装WSL.bat" echo 按任意键退出... pause >nul ``` 4. **运行脚本** - 右键点击 `01-创建文件夹.bat` - 选择"**以管理员身份运行**" - 等待脚本执行完成 - 查看创建的文件夹结构 ### 验证结果: 打开D盘,应该看到以下结构: ``` D:\GeologyAI\ ├── DockerData\ ├── Ollama\ ├── RAGFlow\ ├── Dify\ ├── Templates\ │ ├── 矿产勘查\ │ ├── 水工环地质\ │ ├── 岩土工程\ │ └── 通用模板\ ├── 数据备份\ ├── 项目文档\ ├── 日志文件\ └── 系统配置\ ``` --- ## 第二步:安装WSL和Ubuntu ### 操作说明: 安装Windows子系统Linux,为后续部署提供环境 ### 具体步骤: 1. **创建WSL安装脚本** - 在桌面上创建新文件:`02-安装WSL.bat` - 右键编辑,粘贴以下代码: ```batch @echo off chcp 65001 >nul title 地质AI系统 - 安装WSL setlocal enabledelayedexpansion echo ========================================== echo 地质AI工作流系统部署工具 echo 步骤2:安装WSL echo ========================================== echo. :: 检查管理员权限 echo [1/5] 检查管理员权限... net session >nul 2>&1 if %errorlevel% neq 0 ( echo ❌ 请以管理员身份运行此脚本! echo 右键点击脚本,选择"以管理员身份运行" pause exit /b 1 ) echo ✅ 管理员权限确认 :: 启用WSL功能 echo [2/5] 启用WSL功能... dism.exe /online /enable-feature /featurename:Microsoft-Windows-Subsystem-Linux /all /norestart if %errorlevel% equ 0 ( echo ✅ WSL功能已启用 ) else ( echo ❌ WSL功能启用失败 pause exit /b 1 ) :: 启用虚拟机平台 echo [3/5] 启用虚拟机平台... dism.exe /online /enable-feature /featurename:VirtualMachinePlatform /all /norestart if %errorlevel% equ 0 ( echo ✅ 虚拟机平台已启用 ) else ( echo ❌ 虚拟机平台启用失败 pause exit /b 1 ) :: 设置WSL 2为默认版本 echo [4/5] 配置WSL 2... wsl --set-default-version 2 if %errorlevel% equ 0 ( echo ✅ WSL 2配置成功 ) else ( echo ⚠ WSL 2配置警告(可能需要重启后生效) ) echo [5/5] 安装完成! echo. echo ========================================== echo ✅ WSL安装完成! echo. echo 重要:现在需要重启计算机! echo. echo 重启后,请继续运行下一步脚本: echo "03-安装Ubuntu.bat" echo. echo 按任意键重启计算机... pause >nul :: 重启计算机 shutdown /r /t 5 ``` 2. **运行WSL安装脚本** - 右键点击 `02-安装WSL.bat` - 选择"**以管理员身份运行**" - 等待完成,计算机会自动重启 3. **创建Ubuntu安装脚本** - 重启后,在桌面创建:`03-安装Ubuntu.bat` - 右键编辑,粘贴: ```batch @echo off chcp 65001 >nul title 地质AI系统 - 安装Ubuntu echo ========================================== echo 地质AI工作流系统部署工具 echo 步骤3:安装Ubuntu echo ========================================== echo. echo [1/4] 打开Microsoft Store... echo 请在商店中搜索并安装 Ubuntu 22.04 LTS echo. echo 操作步骤: echo 1. 按 Win + S,输入 Microsoft Store echo 2. 搜索 "Ubuntu 22.04 LTS" echo 3. 点击"获取"安装 echo 4. 安装完成后点击"启动" echo 5. 设置用户名和密码(请记住密码!) echo. echo 按任意键打开Microsoft Store... pause >nul :: 打开Microsoft Store的Ubuntu页面 start ms-windows-store://pdp/?productid=9PN20MVRCQQW echo. echo [2/4] 等待Ubuntu安装完成... echo 请完成Ubuntu的安装和初始设置 echo 设置用户名和密码后,返回此窗口继续 echo. echo 按任意键继续... pause >nul echo [3/4] 验证Ubuntu安装... wsl --list if %errorlevel% equ 0 ( echo ✅ Ubuntu安装验证成功 ) else ( echo ❌ Ubuntu安装验证失败 echo 请检查Ubuntu是否安装成功 pause exit /b 1 ) echo [4/4] 配置完成! echo. echo ========================================== echo ✅ Ubuntu安装完成! echo. echo 下一步:请运行 "04-安装Docker.bat" echo 按任意键退出... pause >nul ``` 4. **运行Ubuntu安装脚本** - 右键点击 `03-安装Ubuntu.bat` - 选择"**以管理员身份运行**" - 按照提示完成Ubuntu安装 ### Ubuntu设置说明: - **用户名**:建议使用英文,如 `geology` - **密码**:设置一个强密码并牢记 - **确认密码**:再次输入相同密码 --- ## 第三步:安装Docker Desktop ### 操作说明: 安装Docker容器平台,用于部署AI应用 ### 具体步骤: 1. **创建Docker安装脚本** - 在桌面创建:`04-安装Docker.bat` - 右键编辑,粘贴: ```batch @echo off chcp 65001 >nul title 地质AI系统 - 安装Docker Desktop echo ========================================== echo 地质AI工作流系统部署工具 echo 步骤4:安装Docker echo ========================================== echo. echo [1/6] 下载Docker Desktop... echo 正在打开Docker下载页面... echo 请下载 Docker Desktop for Windows echo. echo 下载地址: echo https://www.docker.com/products/docker-desktop/ echo. echo 按任意键打开浏览器... pause >nul start https://www.docker.com/products/docker-desktop/ echo. echo [2/6] 等待下载完成... echo 请完成Docker Desktop的下载 echo 下载完成后返回此窗口继续 echo. echo 按任意键继续... pause >nul echo [3/6] 安装Docker Desktop... echo 请按照以下步骤安装: echo 1. 双击下载的 Docker Desktop Installer.exe echo 2. 安装时取消勾选"Use WSL 2 instead of Hyper-V"(如果出现) echo 3. 点击"Advanced"选项 echo 4. 设置安装路径为:D:\GeologyAI\Docker\ echo 5. 设置数据目录为:D:\GeologyAI\DockerData\ echo 6. 完成安装 echo. echo 安装完成后返回此窗口继续 echo 按任意键继续... pause >nul echo [4/6] 配置Docker... echo 请完成Docker Desktop的初始配置: echo 1. 启动Docker Desktop echo 2. 接受服务条款 echo 3. 等待Docker启动完成 echo 4. 在设置中勾选"Use WSL 2 based engine" echo. echo 配置完成后返回此窗口继续 echo 按任意键继续... pause >nul echo [5/6] 验证Docker安装... docker --version >nul 2>&1 if %errorlevel% equ 0 ( echo ✅ Docker安装成功 ) else ( echo ❌ Docker安装验证失败 echo 请检查Docker是否安装成功 pause exit /b 1 ) echo [6/6] 安装完成! echo. echo ========================================== echo ✅ Docker Desktop安装完成! echo. echo 下一步:请运行 "05-设置Ubuntu环境.bat" echo 按任意键退出... pause >nul ``` 2. **运行Docker安装脚本** - 右键点击 `04-安装Docker.bat` - 选择"**以管理员身份运行**" - 按照提示完成Docker安装 ### Docker安装注意事项: - **安装路径**:必须选择 `D:\GeologyAI\Docker\` - **数据目录**:必须选择 `D:\GeologyAI\DockerData\` - **首次启动**:需要等待Docker初始化完成 --- ## 第四步:设置Ubuntu环境 ### 操作说明: 在Ubuntu中配置必要的环境和权限 ### 具体步骤: 1. **创建环境设置脚本** - 在桌面创建:`05-设置Ubuntu环境.bat` - 右键编辑,粘贴: ```batch @echo off chcp 65001 >nul title 地质AI系统 - 设置Ubuntu环境 echo ========================================== echo 地质AI工作流系统部署工具 echo 步骤5:设置Ubuntu环境 echo ========================================== echo. echo [1/4] 准备Ubuntu环境配置脚本... echo 将在Ubuntu中执行以下操作: echo 1. 设置文件夹权限 echo 2. 更新系统软件包 echo 3. 安装必要工具 echo. echo 按任意键继续... pause >nul :: 创建Ubuntu配置脚本 echo cd /mnt/d/GeologyAI > ubuntu_setup.sh echo. >> ubuntu_setup.sh echo echo "=== 开始设置地质AI系统环境 ===" >> ubuntu_setup.sh echo. >> ubuntu_setup.sh echo "# 设置文件夹权限" >> ubuntu_setup.sh echo "echo '设置文件夹权限...'" >> ubuntu_setup.sh echo "sudo chmod -R 777 /mnt/d/GeologyAI/" >> ubuntu_setup.sh echo. >> ubuntu_setup.sh echo "# 更新系统" >> ubuntu_setup.sh echo "echo '更新系统软件包...'" >> ubuntu_setup.sh echo "sudo apt update && sudo apt upgrade -y" >> ubuntu_setup.sh echo. >> ubuntu_setup.sh echo "# 安装必要工具" >> ubuntu_setup.sh echo "echo '安装必要工具...'" >> ubuntu_setup.sh echo "sudo apt install -y curl wget git vim" >> ubuntu_setup.sh echo. >> ubuntu_setup.sh echo "# 创建符号链接" >> ubuntu_setup.sh echo "echo '创建符号链接...'" >> ubuntu_setup.sh echo "ln -s /mnt/d/GeologyAI ~/GeologyAI" >> ubuntu_setup.sh echo. >> ubuntu_setup.sh echo "echo '✅ Ubuntu环境设置完成!'" >> ubuntu_setup.sh echo "echo '下一步:请运行 06-安装Ollama.bat'" >> ubuntu_setup.sh echo [2/4] 在Ubuntu中运行配置脚本... echo 将在Ubuntu窗口中执行配置命令 echo 可能需要输入密码(您在安装Ubuntu时设置的密码) echo. echo 按任意键打开Ubuntu并运行配置... pause >nul :: 复制脚本到Ubuntu并执行 wsl -d Ubuntu-22.04 -e bash -c "cd /mnt/d/GeologyAI && bash ubuntu_setup.sh" echo. echo [3/4] 验证环境设置... wsl -d Ubuntu-22.04 -e bash -c "ls -la /mnt/d/GeologyAI" if %errorlevel% equ 0 ( echo ✅ Ubuntu环境设置成功 ) else ( echo ❌ Ubuntu环境设置失败 pause exit /b 1 ) echo [4/4] 设置完成! echo. echo ========================================== echo ✅ Ubuntu环境设置完成! echo. echo 下一步:请运行 "06-安装Ollama.bat" echo 按任意键退出... pause >nul ``` 2. **运行环境设置脚本** - 右键点击 `05-设置Ubuntu环境.bat` - 选择"**以管理员身份运行**" - 按照提示完成Ubuntu环境配置 ### 注意事项: - 在Ubuntu中执行命令时,如果需要输入密码,输入您在安装Ubuntu时设置的密码 - 密码输入时不会显示字符,这是正常现象 --- ## 第五步:安装Ollama AI模型 ### 操作说明: 安装Ollama并下载地质行业专用的AI模型 ### 具体步骤: 1. **创建Ollama安装脚本** - 在桌面创建:`06-安装Ollama.bat` - 右键编辑,粘贴: ```batch @echo off chcp 65001 >nul title 地质AI系统 - 安装Ollama echo ========================================== echo 地质AI工作流系统部署工具 echo 步骤6:安装Ollama echo ========================================== echo. echo [1/5] 创建Ollama安装脚本... echo 将在Ubuntu中安装Ollama和AI模型 echo 注意:模型下载需要较长时间(30分钟到2小时) echo 请确保网络连接稳定 echo. echo 按任意键继续... pause >nul :: 创建Ollama安装脚本 echo #!/bin/bash > install_ollama.sh echo. >> install_ollama.sh echo echo "=== 开始安装Ollama和AI模型 ===" >> install_ollama.sh echo. >> install_ollama.sh echo "# 安装Ollama" >> install_ollama.sh echo "echo '安装Ollama...'" >> install_ollama.sh echo "curl -fsSL https://ollama.ai/install.sh | sh" >> install_ollama.sh echo. >> install_ollama.sh echo "# 设置模型存储路径" >> install_ollama.sh echo "echo '设置模型存储路径...'" >> install_ollama.sh echo "echo 'export OLLAMA_MODELS=\"/mnt/d/GeologyAI/Ollama\"' >> ~/.bashrc" >> install_ollama.sh echo "source ~/.bashrc" >> install_ollama.sh echo. >> install_ollama.sh echo "# 下载地质行业AI模型" >> install_ollama.sh echo "echo '下载AI模型(这需要较长时间)...'" >> install_ollama.sh echo "echo '模型1: deepseek-coder:6.7b (代码生成)'" >> install_ollama.sh echo "ollama pull deepseek-coder:6.7b" >> install_ollama.sh echo. >> install_ollama.sh echo "echo '模型2: llama2:7b (通用问答)'" >> install_ollama.sh echo "ollama pull llama2:7b" >> install_ollama.sh echo. >> install_ollama.sh echo "echo '模型3: deepseek-llm:7b (文本生成)'" >> install_ollama.sh echo "ollama pull deepseek-llm:7b" >> install_ollama.sh echo. >> install_ollama.sh echo "echo '✅ Ollama安装完成!'" >> install_ollama.sh echo "echo '已安装的模型:'" >> install_ollama.sh echo "ollama list" >> install_ollama.sh echo [2/5] 复制脚本到Ubuntu... copy install_ollama.sh D:\GeologyAI\ if exist D:\GeologyAI\install_ollama.sh ( echo ✅ 脚本复制成功 ) else ( echo ❌ 脚本复制失败 pause exit /b 1 ) echo [3/5] 在Ubuntu中运行安装脚本... echo 现在开始在Ubuntu中安装Ollama和AI模型 echo 这个过程需要较长时间,请耐心等待... echo 您可以在Ubuntu窗口中查看安装进度 echo. echo 按任意键开始安装... pause >nul wsl -d Ubuntu-22.04 -e bash -c "cd /mnt/d/GeologyAI && chmod +x install_ollama.sh && ./install_ollama.sh" echo. echo [4/5] 验证Ollama安装... wsl -d Ubuntu-22.04 -e bash -c "ollama list" if %errorlevel% equ 0 ( echo ✅ Ollama安装成功 ) else ( echo ❌ Ollama安装失败 pause exit /b 1 ) echo [5/5] 安装完成! echo. echo ========================================== echo ✅ Ollama安装完成! echo. echo 下一步:请运行 "07-部署RAGFlow.bat" echo 按任意键退出... pause >nul ``` 2. **运行Ollama安装脚本** - 右键点击 `06-安装Ollama.bat` - 选择"**以管理员身份运行**" - 等待安装完成(需要较长时间) ### 模型下载说明: - **deepseek-coder:6.7b**:用于代码生成和地质数据处理 - **llama2:7b**:用于通用问答和文档处理 - **deepseek-llm:7b**:用于文本生成和报告编写 --- ## 第六步:部署RAGFlow知识库系统 ### 操作说明: 部署RAGFlow知识库管理系统,用于管理地质文档和知识 ### 具体步骤: 1. **创建RAGFlow部署脚本** - 在桌面创建:`07-部署RAGFlow.bat` - 右键编辑,粘贴: ```batch @echo off chcp 65001 >nul title 地质AI系统 - 部署RAGFlow echo ========================================== echo 地质AI工作流系统部署工具 echo 步骤7:部署RAGFlow echo ========================================== echo. echo [1/5] 创建RAGFlow配置文件... echo 正在创建Docker Compose配置文件... echo. :: 创建RAGFlow配置脚本 echo #!/bin/bash > deploy_ragflow.sh echo. >> deploy_ragflow.sh echo echo "=== 开始部署RAGFlow知识库系统 ===" >> deploy_ragflow.sh echo. >> deploy_ragflow.sh echo "# 进入RAGFlow目录" >> deploy_ragflow.sh echo "cd /mnt/d/GeologyAI/RAGFlow" >> deploy_ragflow.sh echo. >> deploy_ragflow.sh echo "# 创建docker-compose配置文件" >> deploy_ragflow.sh echo "cat > docker-compose.yml << 'EOF'" >> deploy_ragflow.sh echo "version: '3.8'" >> deploy_ragflow.sh echo "services:" >> deploy_ragflow.sh echo " ragflow:" >> deploy_ragflow.sh echo " image: inchat/ragflow:latest" >> deploy_ragflow.sh echo " container_name: ragflow" >> deploy_ragflow.sh echo " ports:" >> deploy_ragflow.sh echo " - \"9380:9380\"" >> deploy_ragflow.sh echo " volumes:" >> deploy_ragflow.sh echo " - ./data:/app/data" >> deploy_ragflow.sh echo " - /mnt/d/GeologyAI/Templates:/templates" >> deploy_ragflow.sh echo " environment:" >> deploy_ragflow.sh echo " - RAGFLOW_DATA_DIR=/app/data" >> deploy_ragflow.sh echo " restart: unless-stopped" >> deploy_ragflow.sh echo "EOF" >> deploy_ragflow.sh echo. >> deploy_ragflow.sh echo "echo '✅ RAGFlow配置文件创建完成'" >> deploy_ragflow.sh echo. >> deploy_ragflow.sh echo "# 启动RAGFlow" >> deploy_ragflow.sh echo "echo '启动RAGFlow服务...'" >> deploy_ragflow.sh echo "docker-compose up -d" >> deploy_ragflow.sh echo. >> deploy_ragflow.sh echo "# 等待服务启动" >> deploy_ragflow.sh echo "echo '等待服务启动...'" >> deploy_ragflow.sh echo "sleep 20" >> deploy_ragflow.sh echo. >> deploy_ragflow.sh echo "# 检查服务状态" >> deploy_ragflow.sh echo "echo '检查RAGFlow服务状态...'" >> deploy_ragflow.sh echo "docker-compose ps" >> deploy_ragflow.sh echo. >> deploy_ragflow.sh echo "echo '✅ RAGFlow部署完成!'" >> deploy_ragflow.sh echo "echo '访问地址: http://localhost:9380'" >> deploy_ragflow.sh echo [2/5] 复制脚本到Ubuntu... copy deploy_ragflow.sh D:\GeologyAI\ if exist D:\GeologyAI\deploy_ragflow.sh ( echo ✅ 脚本复制成功 ) else ( echo ❌ 脚本复制失败 pause exit /b 1 ) echo [3/5] 在Ubuntu中运行部署脚本... echo 现在开始在Ubuntu中部署RAGFlow echo 需要下载Docker镜像,可能需要一些时间... echo. echo 按任意键开始部署... pause >nul wsl -d Ubuntu-22.04 -e bash -c "cd /mnt/d/GeologyAI && chmod +x deploy_ragflow.sh && ./deploy_ragflow.sh" echo. echo [4/5] 验证RAGFlow部署... echo 等待服务启动... timeout /t 30 /nobreak >nul wsl -d Ubuntu-22.04 -e bash -c "cd /mnt/d/GeologyAI/RAGFlow && docker-compose ps" if %errorlevel% equ 0 ( echo ✅ RAGFlow部署成功 ) else ( echo ❌ RAGFlow部署失败 pause exit /b 1 ) echo [5/5] 部署完成! echo. echo ========================================== echo ✅ RAGFlow部署完成! echo. echo 访问地址: http://localhost:9380 echo 用户名: admin echo 密码: admin echo. echo 下一步:请运行 "08-部署Dify.bat" echo 按任意键退出... pause >nul ``` 2. **运行RAGFlow部署脚本** - 右键点击 `07-部署RAGFlow.bat` - 选择"**以管理员身份运行**" - 等待部署完成 3. **验证RAGFlow** - 打开浏览器 - 访问:`http://localhost:9380` - 应该能看到RAGFlow登录页面 --- ## 第七步:部署Dify工作流系统 ### 操作说明: 部署Dify工作流平台,用于创建自动化报告生成流程 ### 具体步骤: 1. **创建Dify部署脚本** - 在桌面创建:`08-部署Dify.bat` - 右键编辑,粘贴: ```batch @echo off chcp 65001 >nul title 地质AI系统 - 部署Dify echo ========================================== echo 地质AI工作流系统部署工具 echo 步骤8:部署Dify echo ========================================== echo. echo [1/5] 创建Dify配置文件... echo 正在创建Docker Compose配置文件... echo. :: 创建Dify配置脚本 echo #!/bin/bash > deploy_dify.sh echo. >> deploy_dify.sh echo echo "=== 开始部署Dify工作流系统 ===" >> deploy_dify.sh echo. >> deploy_dify.sh echo "# 进入Dify目录" >> deploy_dify.sh echo "cd /mnt/d/GeologyAI/Dify" >> deploy_dify.sh echo. >> deploy_dify.sh echo "# 创建docker-compose配置文件" >> deploy_dify.sh echo "cat > docker-compose.yml << 'EOF'" >> deploy_dify.sh echo "version: '3.8'" >> deploy_dify.sh echo "services:" >> deploy_dify.sh echo " dify:" >> deploy_dify.sh echo " image: langgenius/dify:latest" >> deploy_dify.sh echo " container_name: dify" >> deploy_dify.sh echo " ports:" >> deploy_dify.sh echo " - \"5001:5001\"" >> deploy_dify.sh echo " volumes:" >> deploy_dify.sh echo " - ./data:/app/api/data" >> deploy_dify.sh echo " - /mnt/d/GeologyAI/Templates:/templates" >> deploy_dify.sh echo " environment:" >> deploy_dify.sh echo " - DB_TYPE=sqlite" >> deploy_dify.sh echo " - SQLITE_DATABASE=dify.db" >> deploy_dify.sh echo " restart: unless-stopped" >> deploy_dify.sh echo "EOF" >> deploy_dify.sh echo. >> deploy_dify.sh echo "echo '✅ Dify配置文件创建完成'" >> deploy_dify.sh echo. >> deploy_dify.sh echo "# 启动Dify" >> deploy_dify.sh echo "echo '启动Dify服务...'" >> deploy_dify.sh echo "docker-compose up -d" >> deploy_dify.sh echo. >> deploy_dify.sh echo "# 等待服务启动" >> deploy_dify.sh echo "echo '等待服务启动...'" >> deploy_dify.sh echo "sleep 20" >> deploy_dify.sh echo. >> deploy_dify.sh echo "# 检查服务状态" >> deploy_dify.sh echo "echo '检查Dify服务状态...'" >> deploy_dify.sh echo "docker-compose ps" >> deploy_dify.sh echo. >> deploy_dify.sh echo "echo '✅ Dify部署完成!'" >> deploy_dify.sh echo "echo '访问地址: http://localhost:5001'" >> deploy_dify.sh echo [2/5] 复制脚本到Ubuntu... copy deploy_dify.sh D:\GeologyAI\ if exist D:\GeologyAI\deploy_dify.sh ( echo ✅ 脚本复制成功 ) else ( echo ❌ 脚本复制失败 pause exit /b 1 ) echo [3/5] 在Ubuntu中运行部署脚本... echo 现在开始在Ubuntu中部署Dify echo 需要下载Docker镜像,可能需要一些时间... echo. echo 按任意键开始部署... pause >nul wsl -d Ubuntu-22.04 -e bash -c "cd /mnt/d/GeologyAI && chmod +x deploy_dify.sh && ./deploy_dify.sh" echo. echo [4/5] 验证Dify部署... echo 等待服务启动... timeout /t 30 /nobreak >nul wsl -d Ubuntu-22.04 -e bash -c "cd /mnt/d/GeologyAI/Dify && docker-compose ps" if %errorlevel% equ 0 ( echo ✅ Dify部署成功 ) else ( echo ❌ Dify部署失败 pause exit /b 1 ) echo [5/5] 部署完成! echo. echo ========================================== echo ✅ Dify部署完成! echo. echo 访问地址: http://localhost:5001 echo. echo 下一步:请运行 "09-创建管理脚本.bat" echo 按任意键退出... pause >nul ``` 2. **运行Dify部署脚本** - 右键点击 `08-部署Dify.bat` - 选择"**以管理员身份运行**" - 等待部署完成 3. **验证Dify** - 打开浏览器 - 访问:`http://localhost:5001` - 应该能看到Dify工作台页面 --- ## 第八步:创建系统管理脚本 ### 操作说明: 创建统一的管理脚本,方便启动和管理整个系统 ### 具体步骤: 1. **创建系统管理脚本** - 在桌面创建:`09-创建管理脚本.bat` - 右键编辑,粘贴: ```batch @echo off chcp 65001 >nul title 地质AI系统 - 创建管理脚本 echo ========================================== echo 地质AI工作流系统部署工具 echo 步骤9:创建管理脚本 echo ========================================== echo. echo [1/4] 创建系统管理脚本... echo 正在创建统一的管理脚本... echo. :: 创建系统管理脚本 echo #!/bin/bash > geology_ai_manager.sh echo. >> geology_ai_manager.sh echo "# 地质AI工作流系统管理脚本" >> geology_ai_manager.sh echo "# 自动启动和管理所有服务" >> geology_ai_manager.sh echo. >> geology_ai_manager.sh echo "echo '==========================================='" >> geology_ai_manager.sh echo "echo ' 地质AI工作流系统启动工具'" >> geology_ai_manager.sh echo "echo '==========================================='" >> geology_ai_manager.sh echo "echo" >> geology_ai_manager.sh echo. >> geology_ai_manager.sh echo "# 启动Ollama" >> geology_ai_manager.sh echo "echo '1. 启动Ollama AI模型...'" >> geology_ai_manager.sh echo "ollama serve &" >> geology_ai_manager.sh echo "sleep 10" >> geology_ai_manager.sh echo. >> geology_ai_manager.sh echo "# 启动RAGFlow" >> geology_ai_manager.sh echo "echo '2. 启动RAGFlow知识库...'" >> geology_ai_manager.sh echo "cd /mnt/d/GeologyAI/RAGFlow && docker-compose up -d" >> geology_ai_manager.sh echo "sleep 10" >> geology_ai_manager.sh echo. >> geology_ai_manager.sh echo "# 启动Dify" >> geology_ai_manager.sh echo "echo '3. 启动Dify工作流...'" >> geology_ai_manager.sh echo "cd /mnt/d/GeologyAI/Dify && docker-compose up -d" >> geology_ai_manager.sh echo "sleep 10" >> geology_ai_manager.sh echo. >> geology_ai_manager.sh echo "# 检查服务状态" >> geology_ai_manager.sh echo "echo '4. 检查服务状态...'" >> geology_ai_manager.sh echo "echo" >> geology_ai_manager.sh echo "echo 'Ollama 状态:'" >> geology_ai_manager.sh echo "if pgrep -f 'ollama serve' > /dev/null; then echo '✅ 运行中'; else echo '❌ 未运行'; fi" >> geology_ai_manager.sh echo "echo" >> geology_ai_manager.sh echo "echo 'RAGFlow 状态:'" >> geology_ai_manager.sh echo "cd /mnt/d/GeologyAI/RAGFlow && docker-compose ps | grep -q Up && echo '✅ 运行中' || echo '❌ 未运行'" >> geology_ai_manager.sh echo "echo '访问地址: http://localhost:9380'" >> geology_ai_manager.sh echo "echo" >> geology_ai_manager.sh echo "echo 'Dify 状态:'" >> geology_ai_manager.sh echo "cd /mnt/d/GeologyAI/Dify && docker-compose ps | grep -q Up && echo '✅ 运行中' || echo '❌ 未运行'" >> geology_ai_manager.sh echo "echo '访问地址: http://localhost:5001'" >> geology_ai_manager.sh echo "echo" >> geology_ai_manager.sh echo "echo '==========================================='" >> geology_ai_manager.sh echo "echo '✅ 系统启动完成!'" >> geology_ai_manager.sh echo "echo '==========================================='" >> geology_ai_manager.sh echo "echo" >> geology_ai_manager.sh echo "# 保持脚本运行" >> geology_ai_manager.sh echo "echo '按 Ctrl+C 停止所有服务并退出'" >> geology_ai_manager.sh echo "wait" >> geology_ai_manager.sh echo [2/4] 复制脚本到Ubuntu... copy geology_ai_manager.sh D:\GeologyAI\ if exist D:\GeologyAI\geology_ai_manager.sh ( echo ✅ 管理脚本创建成功 ) else ( echo ❌ 管理脚本创建失败 pause exit /b 1 ) echo [3/4] 设置脚本权限... wsl -d Ubuntu-22.04 -e bash -c "cd /mnt/d/GeologyAI && chmod +x geology_ai_manager.sh" if %errorlevel% equ 0 ( echo ✅ 脚本权限设置成功 ) else ( echo ❌ 脚本权限设置失败 pause exit /b 1 ) echo [4/4] 创建桌面快捷方式... echo 创建桌面快捷方式... powershell -Command " $WshShell = New-Object -comObject WScript.Shell; $Shortcut = $WshShell.CreateShortcut('%USERPROFILE%\Desktop\启动地质AI系统.lnk'); $Shortcut.TargetPath = 'wsl.exe'; $Shortcut.Arguments = '-d Ubuntu-22.04 -e bash /mnt/d/GeologyAI/geology_ai_manager.sh'; $Shortcut.WorkingDirectory = 'D:\GeologyAI'; $Shortcut.Description = '地质AI工作流系统启动工具'; $Shortcut.IconLocation = 'C:\Windows\System32\wsl.exe,0'; $Shortcut.Save() " if exist "%USERPROFILE%\Desktop\启动地质AI系统.lnk" ( echo ✅ 桌面快捷方式创建成功 ) else ( echo ❌ 桌面快捷方式创建失败 pause exit /b 1 ) echo. echo ========================================== echo ✅ 系统管理脚本创建完成! echo. echo 创建的快捷方式: echo 📄 启动地质AI系统.lnk - 一键启动所有服务 echo. echo 下一步:请运行 "10-验证系统.bat" echo 按任意键退出... pause >nul ``` 2. **运行管理脚本创建** - 右键点击 `09-创建管理脚本.bat` - 选择"**以管理员身份运行**" - 等待完成 --- ## 第九步:验证系统部署 ### 操作说明: 验证所有组件是否正确安装和运行 ### 具体步骤: 1. **创建验证脚本** - 在桌面创建:`10-验证系统.bat` - 右键编辑,粘贴: ```batch @echo off chcp 65001 >nul title 地质AI系统 - 验证部署 echo ========================================== echo 地质AI工作流系统部署工具 echo 步骤10:验证系统 echo ========================================== echo. echo [1/6] 验证文件夹结构... if exist "D:\GeologyAI" ( echo ✅ 根目录存在 ) else ( echo ❌ 根目录不存在 goto :error ) echo [2/6] 验证WSL和Ubuntu... wsl --list | findstr "Ubuntu" >nul if %errorlevel% equ 0 ( echo ✅ Ubuntu安装成功 ) else ( echo ❌ Ubuntu未安装 goto :error ) echo [3/6] 验证Docker... docker --version >nul 2>&1 if %errorlevel% equ 0 ( echo ✅ Docker安装成功 ) else ( echo ❌ Docker未安装 goto :error ) echo [4/6] 验证Ollama... wsl -d Ubuntu-22.04 -e bash -c "ollama list" >nul 2>&1 if %errorlevel% equ 0 ( echo ✅ Ollama安装成功 ) else ( echo ❌ Ollama未安装 goto :error ) echo [5/6] 验证RAGFlow... wsl -d Ubuntu-22.04 -e bash -c "cd /mnt/d/GeologyAI/RAGFlow && docker-compose ps" | findstr "Up" >nul if %errorlevel% equ 0 ( echo ✅ RAGFlow运行中 ) else ( echo ❌ RAGFlow未运行 goto :error ) echo [6/6] 验证Dify... wsl -d Ubuntu-22.04 -e bash -c "cd /mnt/d/GeologyAI/Dify && docker-compose ps" | findstr "Up" >nul if %errorlevel% equ 0 ( echo ✅ Dify运行中 ) else ( echo ❌ Dify未运行 goto :error ) echo. echo ========================================== echo ✅ 系统验证完成! echo 所有组件安装成功! echo. echo 🎉 部署完成!您现在可以: echo. echo 1. 双击桌面"启动地质AI系统.lnk"启动服务 echo 2. 访问以下地址使用系统: echo 📚 RAGFlow知识库: http://localhost:9380 echo ⚙️ Dify工作流: http://localhost:5001 echo. echo 地质工作流程: echo 1. 在RAGFlow中上传地质文档和规范 echo 2. 在Dify中配置报告生成工作流 echo 3. 输入勘查数据,自动生成专业报告 echo. echo 按任意键播放完成提示音并退出... pause >nul :: 播放完成提示音 echo  powershell -c "(New-Object Media.SoundPlayer 'C:\Windows\Media\tada.wav').PlaySync();" 2>nul goto :eof :error echo. echo ========================================== echo ❌ 系统验证失败! echo 请检查前面的步骤是否正确完成 echo 或重新运行失败的步骤 echo. echo 按任意键退出... pause >nul ``` 2. **运行验证脚本** - 右键点击 `10-验证系统.bat` - 选择"**以管理员身份运行**" - 查看验证结果 --- ## 🎯 使用指南 ### 启动系统: 1. 双击桌面"**启动地质AI系统.lnk**" 2. 等待所有服务启动完成(约1-2分钟) 3. 服务启动后,不要关闭Ubuntu窗口 ### 访问系统: - **RAGFlow知识库**:http://localhost:9380 - 用户名:admin - 密码:admin - **Dify工作流**:http://localhost:5001 ### 地质工作流程: 1. **准备知识库**(RAGFlow): - 创建新的知识库 - 上传地质规范、技术标准等PDF/DOC文件 - 系统会自动处理和索引文档 2. **配置工作流**(Dify): - 创建新的应用 - 选择"工作流"类型 - 配置地质报告生成流程 3. **生成报告**: - 在工作流中输入勘查数据 - 系统自动检索相关知识 - 生成专业的Word格式报告 ### 停止系统: 在启动系统的Ubuntu窗口中按 `Ctrl + C` --- ## 🔧 故障排除 ### 常见问题: 1. **端口冲突**: - 如果9380或5001端口被占用 - 修改对应docker-compose.yml文件中的端口号 2. **Docker启动失败**: - 检查Docker Desktop是否运行 - 重启Docker服务 3. **模型下载慢**: - 使用国内镜像:`OLLAMA_HOST=0.0.0.0 ollama pull 模型名` 4. **权限问题**: - 运行:`wsl -d Ubuntu-22.04 -e bash -c "sudo chmod -R 777 /mnt/d/GeologyAI/"` ### 数据备份: 重要数据位置: - `D:\GeologyAI\RAGFlow\data\` - 知识库数据 - `D:\GeologyAI\Dify\data\` - 工作流配置 - `D:\GeologyAI\Ollama\` - AI模型 - `D:\GeologyAI\Templates\` - 报告模板 定期备份整个 `D:\GeologyAI\` 文件夹 --- ## 📞 技术支持 如果遇到问题: 1. 检查 `D:\GeologyAI\日志文件\` 中的日志 2. 重新运行对应的部署步骤 3. 确保所有步骤按顺序完成 这个完整的部署方案包含了所有必要的步骤和详细的说明,按照顺序执行每个步骤即可成功部署地质AI工作流系统。请根据背景及要求:本人从事地质找矿行业、水工环地质勘查行业、岩土工程勘察行业的电脑小白,电脑系统为Win11,有英伟达显卡2080ti双显卡显卡共44gb,电脑内存96GB,在wsl和Ubuntu的基础上利用Ollama + DeepSeek + Docker + RAGFlow+Dify本地部署私人知识库加cmp工作流,自动提取报告模板自动生成word报告,Ubuntu24.04+Ollama + DeepSeek + Docker (Docker Desktop需要汉化)+ RAGFlow(最新版)+Dify都必须安装在D盘的单独文件夹内,且软件安装禁止安装在c盘,所有数据存储于D盘的特有文件夹内。以以上方案架构重新整理一份含具体操作步骤及说明的完整详细的部署方案。
09-30
#include "stdafx.h" #include "grouptybase.h" #include "sp_drawView.h" #include "HmLayer.h" #include "yc.h" #include "HuaMian.h" #include <Shlwapi.h> #include "TysView.h" #include "NewGroupPage.h" #include "dll_draw.h" #include "DlgGroupScale.h" #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif IMPLEMENT_SERIAL(CGroupTyBase,CTyBase, 0) float CGroupTyBase::c_xScale=1.0; float CGroupTyBase::c_yScale=1.0; BOOL CGroupTyBase::c_bText=true; BOOL CGroupTyBase::c_bBmp=false; CGroupTyBase::CGroupTyBase(int vId/*=0*/,CHMLayer* pLayer/*=NULL*/) :CTyBase(vId,pLayer) { m_bCreating=false; m_ArrChilds.RemoveAll(); m_LayerID=0; memset(&m_groupTypeInfo,0,sizeof(SGroupInfo)); memset(&m_groupRtuInfo,0,sizeof(S_GROUPRTU)); for (int i=0;i<MAX_GRP_RTU_NUM;i++) { m_groupRtuInfo.rtu[i].node_id=-1; m_groupRtuInfo.rtu[i].line_id=-1; m_groupRtuInfo.rtu[i].rtu_id=-1; m_groupRtuInfo.rtu[i].rtu_type=-1; } m_xScale=1; m_yScale=1; m_bText=c_bText; m_bBmp=c_bBmp; } DRAW_TY CGroupTyBase::GetTyType() { return tyGroup; } CGroupTyBase::CGroupTyBase(CTyBaseList* pList) :CTyBase(0,NULL) { m_LayerID=0; m_bCreating=false; m_ArrChilds.RemoveAll(); m_dwFlag=m_dwFlag|0x1; memset(&m_groupTypeInfo,0,sizeof(SGroupInfo)); memset(&m_groupRtuInfo,0,sizeof(S_GROUPRTU)); if (pList==NULL) return; BOOL bRoot; POSITION pos=pList->GetHeadPosition(); while (pos!=NULL) { CTyBase* pTy=pList->GetNext(pos); pTy->IsGroupTy(bRoot); if (bRoot==true) { assert(false); continue; } AddTy(pTy); } m_xScale=1; m_yScale=1; m_bText=c_bText; m_bBmp=c_bBmp; } CGroupTyBase::CGroupTyBase(LPCSTR filepath) :CTyBase(0,NULL) { m_bCreating=false; m_ArrChilds.RemoveAll(); m_LayerID=0; m_dwFlag=m_dwFlag| 0x1; memset(&m_groupTypeInfo,0,sizeof(SGroupInfo)); memset(&m_groupRtuInfo,0,sizeof(S_GROUPRTU)); m_xScale=1; m_yScale=1; m_bText=c_bText; m_bBmp=c_bBmp; if (filepath==NULL) return; if (PathFileExists(filepath)==false) return; CFileException fe; CFile vFile; char path_buffer[_MAX_PATH]; char drive[_MAX_DRIVE]; char dir[_MAX_DIR]; char fname[_MAX_FNAME]; char ext[_MAX_EXT]; _splitpath(filepath,drive,dir,fname,ext); if (!vFile.Open(filepath, CFile::modeRead|CFile::shareDenyWrite, &fe)) return; TRY { CWaitCursor wait; SaveGroupFile(&vFile,false); if (stricmp(m_groupTypeInfo.Name,fname)!=0) { fname[63]=0x0; strcpy(m_groupTypeInfo.Name,fname); } m_Id=0; int count=m_ArrChilds.GetCount(); for (int i=0;i<count;i++) { tagShowProp* pProp=m_ArrChilds.GetAt(i); assert(pProp!=NULL); if (pProp==NULL) continue; if (pProp->pChildTy==NULL) continue; pProp->pChildTy->m_Id=0; } vFile.Close(); } CATCH_ALL(e) { vFile.Close(); } END_CATCH_ALL } CGroupTyBase::~CGroupTyBase(void) { RemoveSelf(); int count=m_ArrChilds.GetCount(); for (int i=0;i<count;i++) { tagShowProp* pProp=m_ArrChilds.GetAt(i); assert(pProp!=NULL); if (pProp==NULL) continue; if (pProp->pChildTy==NULL) continue; delete pProp->pChildTy; delete pProp; } m_ArrChilds.RemoveAll(); } void CGroupTyBase::DisMissGroup(void) //组合图元拆卸 { if (m_pHMLayer!=NULL) m_pHMLayer->OnRemoveTy(this); m_dwFlag=m_dwFlag&0xfffffffe; int count=m_ArrChilds.GetCount(); for (int i=0;i<count;i++) { tagShowProp* pProp=m_ArrChilds.GetAt(i); assert(pProp!=NULL); if (pProp==NULL) continue; if (pProp->pChildTy==NULL) continue; pProp->pChildTy->DisMissGroup(); delete pProp; } m_ArrChilds.RemoveAll(); } //查找某个子图元的位置,通过子图元的指针 int CGroupTyBase::FindChildTy(CTyBase * pTy) { int ret=-1; int count=m_ArrChilds.GetCount(); for (int i=0;i<count;i++) { tagShowProp* pProp=m_ArrChilds.GetAt(i); assert(pProp!=NULL); if (pProp==NULL) continue; if (pTy==pProp->pChildTy) { ret=i; break; } } return ret; } //查找某个子图元,通过子图元的显示类型 CTyBase * CGroupTyBase::FindChildTyObj(int vShowPropType) { CTyBase * ret=NULL; int count=m_ArrChilds.GetCount(); for (int i=0;i<count;i++) { tagShowProp* pProp=m_ArrChilds.GetAt(i); assert(pProp!=NULL); if (pProp==NULL) continue; if (vShowPropType==pProp->showType) { ret=pProp->pChildTy; break; } } return ret; } //获取显示属性量 bool CGroupTyBase::GetPropCode(int vShowPropType,char* codeEname) { bool ret=false; memset(codeEname,0,sizeof(char)*17); CYC * pTy=(CYC*) FindChildTyObj(vShowPropType); if (pTy==NULL) return ret; ret=true; strcpy(codeEname,pTy->m_yc.ename); return ret; } //查找某个子图元的位置,通过子图元的显示类型 int CGroupTyBase::FindChildTy(int vShowPropType) { int ret=-1; int count=m_ArrChilds.GetCount(); for (int i=0;i<count;i++) { tagShowProp* pProp=m_ArrChilds.GetAt(i); assert(pProp!=NULL); if (pProp==NULL) continue; if (vShowPropType==pProp->showType) { ret=i; break; } } return ret; } void CGroupTyBase::RemoveChildTy(CTyBase * pTy,CDrawInfoBase * pView) { assert(pTy!=NULL); if (pTy==NULL) return; if (pView!=NULL) { pView->InvalidateTy(this); } RectStruct oldRt; RectStruct newRt; memset(&oldRt,0,sizeof(RectStruct)); memset(&newRt,0,sizeof(RectStruct)); GetRect(&oldRt.x0,&oldRt.y0,&oldRt.x1,&oldRt.y1); int pos=FindChildTy(pTy); if (pos>=0) { m_ArrChilds.RemoveAt(pos); pTy->m_pGroup=NULL; SetModifiedFlag(true); } GetRect(&newRt.x0,&newRt.y0,&newRt.x1,&newRt.y1); if (m_pHMLayer!=NULL) m_pHMLayer->OnPositionChangedTy(this,oldRt,newRt); if (pView!=NULL) { pView->InvalidateTy(this); } } /*向容器里增加一个子图元 //参数: int showType-子图元属性编码 <0-属性无效(组合对象用) 0-主显示属性 >0 */ void CGroupTyBase::AddTy(CTyBase *pTy,int showType,CDrawInfoBase * pView) { assert(pTy!=NULL); if (pTy==NULL) return; RectStruct oldRt; RectStruct newRt; memset(&oldRt,0,sizeof(RectStruct)); memset(&newRt,0,sizeof(RectStruct)); GetRect(&oldRt.x0,&oldRt.y0,&oldRt.x1,&oldRt.y1); pTy->m_pGroup=this; if (pView!=NULL) { pView->InvalidateTy(this); } if (showType<0) { int pos=FindChildTy(pTy); if (pos<0) { tagShowProp* pProp=new tagShowProp; memset(pProp,0,sizeof(pProp)); pProp->pChildTy=pTy; pProp->showType=showType; m_ArrChilds.Add(pProp); pTy->m_pGroup=this; SetModifiedFlag(true); } } else { int pos=FindChildTy(showType); if (pos<0) { tagShowProp* pProp=new tagShowProp; memset(pProp,0,sizeof(pProp)); pProp->pChildTy=pTy; pProp->showType=showType; if (showType==0) m_ArrChilds.InsertAt(0,pProp); else m_ArrChilds.Add(pProp); pTy->m_pGroup=this; SetModifiedFlag(true); } } GetRect(&newRt.x0,&newRt.y0,&newRt.x1,&newRt.y1); if (m_pHMLayer!=NULL) m_pHMLayer->OnPositionChangedTy(this,oldRt,newRt); if (pView!=NULL) { pView->InvalidateTy(this); } } //添加子图元进入指定的画面层 void CGroupTyBase::AddChildTyToLayer(CHMLayer* pLayer) { if (pLayer==NULL) return; CTyBase* pTy=NULL; int count=m_ArrChilds.GetCount(); for (int i=0;i<count;i++) { tagShowProp* pProp=m_ArrChilds[i]; assert(pProp!=NULL); if (pProp==NULL) continue; pTy=pProp->pChildTy; assert(pTy!=NULL); if (pTy==NULL) continue; if (pTy->m_pHMLayer==NULL) pLayer->Add(pTy); } } void CGroupTyBase::GetRect(float *minX, float *minY, float *maxX, float *maxY) { float minX1=0,minX2=0,minY1=0,minY2=0,maxX1=0,maxX2=0,maxY1=0,maxY2=0; if ((m_dwFlag&0x1)==0) return; //设备图元还没有装载完毕 bool bFirst=true; CTyBase* pTy=NULL; int count=m_ArrChilds.GetCount(); for (int i=0;i<count;i++) { tagShowProp* pProp=m_ArrChilds[i]; assert(pProp!=NULL); if (pProp==NULL) continue; pTy=pProp->pChildTy; //assert(pTy!=NULL); if (pTy==NULL) continue; if (bFirst) { pTy->GetRect(&minX1,&minY1,&maxX1,&maxY1); if ((minX1==maxX1)&&(maxY1==minY1)&&(minX1==0)&&(minY1==0)) continue; bFirst=false; } else { pTy->GetRect(&minX2,&minY2,&maxX2,&maxY2); if ((minX2==maxX2)&&(maxY2==minY2)&&(minX2==0)&&(minY2==0)) continue; if (minX2<minX1) minX1=minX2; if (minY2<minY1) minY1=minY2; if (maxX2>maxX1) maxX1=maxX2; if (maxY2>maxY1) maxY1=maxY2; } } if (bFirst==false) { *minX=minX1; *minY=minY1; *maxX=maxX1; *maxY=maxY1; } } //BOOL CGroupTyBase::PointInObj(float x, float y,float errRange) //{ // BOOL ret=false; // int count=m_ArrChilds.GetCount(); // if (count==0) return ret; // CTyBase* pTy=NULL; // // for (int i=0;i<count;i++) // { // pTy=m_ArrChilds[i]->pChildTy; // assert(pTy!=NULL); // if (pTy==NULL) continue; // ret=pTy->PointInObj(x,y,errRange); // if (ret==true) break; // // } // return ret; // //} BOOL CGroupTyBase::PointInObj(float x, float y,float errRange) { assert(errRange>=0); if (m_bDelete) return FALSE; BOOL ret=FALSE; RectStruct rt,rt2,rt3; GetRect(&rt.x0,&rt.y0,&rt.x1,&rt.y1); rt2=rt; rt2.InflateRect(errRange+5,errRange+5); ret=PointInRect(x,y,rt2); return ret; } void CGroupTyBase::Ty_Serialize(CArchive & ar) { int count=0; if(ar.IsStoring()) { ar.Write((char *)&m_groupTypeInfo,sizeof(SGroupInfo)); ar.Write((char*)&m_groupRtuInfo,sizeof(S_GROUPRTU)); ar.Write((char *)&m_xScale,sizeof(float)); ar.Write((char *)&m_yScale,sizeof(float)); ar.Write((char *)&m_bText,sizeof(BOOL)); ar.Write((char *)&m_bBmp,sizeof(BOOL)); int num=m_ArrChilds.GetCount(); for (int i=0;i<num;i++) { tagShowProp* pProp=m_ArrChilds[i]; assert(pProp!=NULL); assert(pProp!=NULL); assert(pProp->pChildTy!=NULL); if (pProp==NULL) continue; if (pProp->pChildTy==NULL) continue; if (pProp->pChildTy->m_bDelete==true) continue; count++; } ar<<count; for (int i=0;i<num;i++) { //CRuntime_Class //CObject* pObject = pClass->CreateObject(); tagShowProp* pProp=m_ArrChilds[i]; assert(pProp!=NULL); assert(pProp->pChildTy!=NULL); if (pProp==NULL) continue; if (pProp->pChildTy==NULL) continue; if (pProp->pChildTy->m_bDelete==true) continue; ar<<pProp->showType; ar<<pProp->pChildTy; } } else { ar.Read((char *)&m_groupTypeInfo,sizeof(SGroupInfo)); m_groupTypeInfo.Name[0]=0x0; ar.Read((char*)&m_groupRtuInfo,sizeof(S_GROUPRTU)); int i; for (i=0;i<m_groupRtuInfo.rtu_count;i++) { m_groupRtuInfo.rtu[i].node_id=-1; m_groupRtuInfo.rtu[i].rtu_id=-1; m_groupRtuInfo.rtu[i].name[0]=0x0; } ar.Read((char *)&m_xScale,sizeof(float)); ar.Read((char *)&m_yScale,sizeof(float)); ar.Read((char *)&m_bText,sizeof(BOOL)); ar.Read((char *)&m_bBmp,sizeof(BOOL)); ar>>count; for (i=0;i<count;i++) { tagShowProp* pProp=new tagShowProp; memset(pProp,0,sizeof(pProp)); ar>>pProp->showType; ar>>pProp->pChildTy; pProp->pChildTy = pProp->pChildTy->Clone(); pProp->pChildTy->m_pGroup=this; m_ArrChilds.Add(pProp); } } } BOOL CGroupTyBase::IsGroupTy(BOOL& vRoot) { vRoot=true; return true; } void CGroupTyBase::DrawBounds(CDC * pDC,CDrawInfoBase *pView) { float minX=0,minY=0,maxX=0,maxY=0; GetRect(&minX,&minY,&maxX,&maxY); if ((minX==maxX)&&(minY==maxY)&&(minX==0)&&(minY==0)) //无效 return; CPoint pt1,pt2; pt1=pView->UPtoLP(minX,minY); pt2=pView->UPtoLP(maxX,maxY); CRect rt; rt.SetRect(pt1,pt2); rt.NormalizeRect(); rt.InflateRect(5,5); LOGBRUSH logBrush2; logBrush2.lbStyle =BS_HATCHED; //BS_SOLID|BS_HATCHED; logBrush2.lbColor = RGB(200,200,255); logBrush2.lbHatch=HS_DIAGCROSS; CPen pen; pen.CreatePen(PS_SOLID|PS_GEOMETRIC|PS_ENDCAP_ROUND, 4, &logBrush2); CPen * pOldPen=pDC->SelectObject(&pen); int holdDrawMode=pDC->SetROP2(R2_COPYPEN); CBrush brush,*pOldBrush; LOGBRUSH logbrush; logbrush.lbStyle=BS_NULL; brush.CreateBrushIndirect(&logbrush); pOldBrush=pDC->SelectObject(&brush); pDC->Rectangle(&rt); pDC->SelectObject(pOldBrush); pDC->SetROP2(holdDrawMode); pDC->SelectObject(pOldPen); } void CGroupTyBase::DrawTracker(CDC *pDC, CDrawInfoBase *pView, TrackerState state) { //CTyBase::DrawTracker(pDC,pView,state); ASSERT_VALID(this); assert(pView!=NULL); switch (state) { case normal: case active: break; case selected: { DrawBounds(pDC,pView); int nHandleCount = GetHandleCount(); for (int nHandle = 1; nHandle <= nHandleCount; nHandle += 1) { CRect rt=GetHandleLogRect(nHandle,pView); pDC->PatBlt(rt.left,rt.top, rt.Width(),rt.Height(), DSTINVERT); } } break; } } //int CGroupTyBase::GetHandleCount() //{ // return 0; //} //获取子图元列表 void CGroupTyBase::GetChildTyList(CTyBaseList& vList) { vList.RemoveAll(); int count=m_ArrChilds.GetCount(); for (int i=0;i<count;i++) { tagShowProp* pProp=m_ArrChilds[i]; assert(pProp!=NULL); assert(pProp->pChildTy!=NULL); if (pProp->pChildTy==NULL) continue; vList.AddTail(pProp->pChildTy); } } void CGroupTyBase::Ty_Move(float xLen, float yLen,CDrawInfoBase * pView) { if (pView!=NULL) pView->InvalidateTy(this); CTyBase* pTy=NULL; int count=m_ArrChilds.GetCount(); for (int i=0;i<count;i++) { tagShowProp* pProp=m_ArrChilds[i]; assert(pProp!=NULL); assert(pProp->pChildTy!=NULL); if (pProp->pChildTy==NULL) continue; pProp->pChildTy->Move(xLen,yLen,pView); } if (pView!=NULL) pView->InvalidateTy(this); } //释放所有被选择的子图元 void CGroupTyBase::DeSelectChildTy(CTysView* pView) { assert(pView!=NULL); if (pView==NULL) return; CTyBase* pTy=NULL; int count=m_ArrChilds.GetCount(); for (int i=0;i<count;i++) { tagShowProp* pProp=m_ArrChilds[i]; assert(pProp!=NULL); pTy=pProp->pChildTy; assert(pTy!=NULL); if (pTy==NULL) continue; pView->Deselect(pTy); } } void CGroupTyBase::OnChildMoveReCallEvent(CTyBase* pChildTy,float xLen, float yLen,CDrawInfoBase * pView) { } //从某画面层里删除自己 void CGroupTyBase::RemoveSelf() { if ((m_dwFlag&0x1)==0) //设备图元还没有装载完毕 { if (m_pHMLayer!=NULL) m_pHMLayer->Remove(this); return; } //先在切割表中删除自己 if (m_pHMLayer!=NULL) m_pHMLayer->OnRemoveTy(this); CTyBase* pTy=NULL; int count=m_ArrChilds.GetCount(); for (int i=0;i<count;i++) { tagShowProp* pProp=m_ArrChilds[i]; assert(pProp!=NULL); pTy=pProp->pChildTy; assert(pTy!=NULL); if (pTy==NULL) continue; if (pTy->m_pHMLayer==NULL) continue; pTy->m_pGroup=NULL;//防止迭代重入 pTy->m_pHMLayer->Remove(pTy); } if (m_pHMLayer!=NULL) m_pHMLayer->Remove(this); } ///通过菜单删除自己 void CGroupTyBase::SetDelete(CDrawInfoBase * pView) { if (m_bDelete==true) return; //对删除嵌套解扣 //先根据当前面积,在切割表中删除自己 if (m_pHMLayer!=NULL) m_pHMLayer->OnRemoveTy(this); if (pView!=NULL) pView->InvalidateTy(this); CTyBaseList vList; CTyBase* pTy=NULL; int count=m_ArrChilds.GetCount(); for (int i=0;i<count;i++) { tagShowProp* pProp=m_ArrChilds[i]; assert(pProp!=NULL); pTy=pProp->pChildTy; assert(pTy!=NULL); if (pTy==NULL) continue; vList.AddTail(pTy); //pTy->SetDelete(bDelete,true,pView); } POSITION pos=vList.GetHeadPosition(); while (pos!=NULL) { pTy=vList.GetNext(pos); assert(pTy!=NULL); if (pTy==NULL) continue; pTy->SetDelete(pView); } vList.RemoveAll(); m_bDelete=true; if (pView!=NULL) pView->InvalidateTy(this); } //通过菜单删除自己,触发的删除事件 void CGroupTyBase::OnDeleteEvent(BOOL bDelete,CDrawInfoBase * pView) { } //存盘 void CGroupTyBase::SaveGroupFile(CFile *file, BOOL Yn) { if (file==NULL) { assert(false); return; } CTyBase* pTy=NULL; CTyBaseList vList; WORD vMVer,vEVer; int count=0; DRAW_TY tystyle; if (Yn==true) { vMVer=CHuaMian::m_wMVersion; vEVer=CHuaMian::m_wEVersion; file->Write((char*)&vMVer,sizeof(WORD)); file->Write((char*)&vEVer,sizeof(WORD)); file->Write((char *)&m_groupTypeInfo,sizeof(SGroupInfo)); file->Write((char *)&m_groupRtuInfo,sizeof(S_GROUPRTU)); GetChildTyList(vList); count=vList.GetCount(); file->Write((char*)&count,sizeof(int)); POSITION pos=vList.GetHeadPosition(); while (pos!=NULL) { pTy=vList.GetNext(pos); if (!pTy->m_bDelete) { tystyle=pTy->GetTyType(); assert(tystyle!=tyNone); file->Write((char *)&tystyle,sizeof(tystyle)); pTy->Save(file,vMVer,vEVer,Yn); } } } else { file->Read((char*)&vMVer,sizeof(WORD)); file->Read((char*)&vEVer,sizeof(WORD)); //比较画面文件版本号 if ((vMVer>CHuaMian::m_wMVersion)||((vMVer==CHuaMian::m_wMVersion) &&((vEVer>CHuaMian::m_wEVersion)))) { //pException=new CPicFileException(); //pException->m_errno=CPicFileException::HIGHVERSION; //throw(pException); assert(false); return; } file->Read((char *)&m_groupTypeInfo,sizeof(SGroupInfo)); file->Read((char *)&m_groupRtuInfo,sizeof(S_GROUPRTU)); file->Read((char *)&count,sizeof(int)); for (int i=0;i<count;i++) { file->Read((char *)&tystyle,sizeof(tystyle)); pTy=CTyBase::CreateTy(tystyle); if (pTy==NULL) return; pTy->Save(file,vMVer,vEVer,Yn); AddTy(pTy); //CGroupTyBase* pGrp=(CGroupTyBase*) pTy; //CHMLayer * pLayer=NULL; //pLayer=FindLayer(pGrp->m_LayerID); //assert(pLayer!=NULL); //if (pLayer==NULL) continue; //pGrp->AssemblyChildTy(pLayer); //pLayer->Add(pTy,true); } } } //void CGroupTyBase::Ty_Save_Version(CFile *file, BOOL Yn,WORD vMVer,WORD vEVer) void CGroupTyBase::Ty_Save(CFile* file,WORD mVer,WORD eVer,BOOL Yn) { assert(file!=NULL); assert(m_bDelete==false); if (file==NULL) return; int count=0; //int posNumber; CTyBase* pTy=NULL; if (Yn) { int iLayerNo=m_pHMLayer->GetLayerID(); file->Write((char *)&iLayerNo,sizeof(int)); file->Write((char *)&m_groupTypeInfo,sizeof(SGroupInfo)); file->Write((char *)&m_groupRtuInfo,sizeof(S_GROUPRTU)); file->Write((char *)&m_xScale,sizeof(float)); file->Write((char *)&m_yScale,sizeof(float)); file->Write((char *)&m_bText,sizeof(BOOL)); file->Write((char *)&m_bBmp,sizeof(BOOL)); char buf[65]; memset(buf,0,sizeof(char)); file->Write(buf,sizeof(char)*65); //num=m_TyList.GetCount(); int num=m_ArrChilds.GetCount(); for (int i=0;i<num;i++) { tagShowProp* pProp=m_ArrChilds[i]; assert(pProp!=NULL); assert(pProp!=NULL); assert(pProp->pChildTy!=NULL); if (pProp==NULL) continue; if (pProp->pChildTy==NULL) continue; if (pProp->pChildTy->m_bDelete==true) continue; count++; } file->Write((char *)&count,sizeof(count)); for (int i=0;i<num;i++) { //CRuntime_Class //CObject* pObject = pClass->CreateObject(); tagShowProp* pProp=m_ArrChilds[i]; assert(pProp!=NULL); assert(pProp->pChildTy!=NULL); if (pProp==NULL) continue; pTy=pProp->pChildTy; if (pTy==NULL) continue; if (pTy->m_bDelete==true) continue; file->Write((char *)&(pProp->showType),sizeof(int)); file->Write((char *)&(pTy->m_Id),sizeof(int)); } } else { file->Read((char *)&(m_LayerID),sizeof(int)); file->Read((char *)&m_groupTypeInfo,sizeof(SGroupInfo)); file->Read((char *)&m_groupRtuInfo,sizeof(S_GROUPRTU)); file->Read((char *)&m_xScale,sizeof(float)); file->Read((char *)&m_yScale,sizeof(float)); file->Read((char *)&m_bText,sizeof(BOOL)); file->Read((char *)&m_bBmp,sizeof(BOOL)); char buf[65]; memset(buf,0,sizeof(char)); file->Read(buf,sizeof(char)*65); file->Read((char *)&count,sizeof(count)); int tyID; for (int i=0;i<count;i++) { tagShowProp* pProp= new tagShowProp; file->Read((char *)&(pProp->showType),sizeof(int)); file->Read((char *)&tyID,sizeof(int)); pProp->pChildTy=(CTyBase*)(char*)tyID; m_ArrChilds.Add(pProp); } } } //图层装载完毕事件 void CGroupTyBase::OnAfterLoadLayerEvent(void) { CTyBase::OnAfterLoadLayerEvent(); assert(m_pHMLayer!=NULL); if (m_pHMLayer==NULL) return; int count=m_ArrChilds.GetCount(); int tyID; CTyBase* pTy; for (int i=0;i<count;i++) { tagShowProp* pProp=m_ArrChilds.GetAt(i); assert(pProp!=NULL); tyID=(int)(char*)(pProp->pChildTy); pTy=m_pHMLayer->FindTyBase(tyID); assert(pTy!=NULL); if (pTy==NULL) { m_ArrChilds[i]->pChildTy=NULL; continue; } m_ArrChilds[i]->pChildTy=pTy; pTy->m_pGroup=this; } } //拼装组合图元 void CGroupTyBase::AssemblyChildTy(CHMLayer* pLayer) { if (pLayer==NULL) return; if ((m_dwFlag&0x1)==0) return; m_dwFlag=m_dwFlag|0x1; int count=m_ArrChilds.GetCount(); int tyID; CTyBase* pTy; for (int i=0;i<count;i++) { tagShowProp* pProp=m_ArrChilds.GetAt(i); assert(pProp!=NULL); tyID=(int)(char*)(pProp->pChildTy); CHMLayerList *layers = &(pLayer->m_pHuaMian->m_HMLayerList); POSITION pos=layers->GetHeadPosition(); while (pos!=NULL) { pLayer=layers->GetNext(pos); if (pLayer!=NULL) { pTy=pLayer->FindTyBase(tyID); if(pTy != NULL) break; } } //assert(pTy!=NULL); if (pTy==NULL) { m_ArrChilds[i]->pChildTy=NULL; continue; } m_ArrChilds[i]->pChildTy=pTy; pTy->m_pGroup=this; } } //图元加入层前 void CGroupTyBase::OnAddLayerBeforeEvent(tagAddLayerEvent* pInfo) { if (pInfo==NULL) return; if (pInfo->pLayer==NULL) return; int count=m_ArrChilds.GetCount(); int tyID; CTyBase* pTy; for (int i=0;i<count;i++) { tagShowProp* pProp=m_ArrChilds.GetAt(i); assert(pProp!=NULL); //tyID=(int)(char*)(pProp->pChildTy); //pTy=m_pHMLayer->FindTyBase(tyID); pTy=pProp->pChildTy; assert(pTy!=NULL); if (pTy==NULL) continue; if (pTy->m_pHMLayer==pInfo->pLayer) continue; pTy->m_pGroup=this; pInfo->pLayer->Add(pTy,pInfo->blNumberChanged); } } //图元加入层后 void CGroupTyBase::OnAddLayerAfterEvent(tagAddLayerEvent* pInfo) { } //返回组图元的最大外接矩形(文字除外) void CGroupTyBase::GetGroupRect(float *minX,float *minY,float *maxX,float *maxY) { float minX1=0,minX2=0,minY1=0,minY2=0,maxX1=0,maxX2=0,maxY1=0,maxY2=0; if ((m_dwFlag&0x1)==0) return; //设备图元还没有装载完毕 bool bFirst=true; CTyBase* pTy=NULL; int count=m_ArrChilds.GetCount(); for (int i=0;i<count;i++) { tagShowProp* pProp=m_ArrChilds[i]; assert(pProp!=NULL); if (pProp==NULL) continue; pTy=pProp->pChildTy; assert(pTy!=NULL); if (pTy==NULL) continue; if (pTy->IsTextTy()==true) continue; if (bFirst) { pTy->GetRect(&minX1,&minY1,&maxX1,&maxY1); if ((minX1==maxX1)&&(maxY1==minY1)&&(minX1==0)&&(minY1==0)) continue; bFirst=false; } else { pTy->GetRect(&minX2,&minY2,&maxX2,&maxY2); if ((minX2==maxX2)&&(maxY2==minY2)&&(minX2==0)&&(minY2==0)) continue; if (minX2<minX1) minX1=minX2; if (minY2<minY1) minY1=minY2; if (maxX2>maxX1) maxX1=maxX2; if (maxY2>maxY1) maxY1=maxY2; } } if (bFirst==false) { *minX=minX1; *minY=minY1; *maxX=maxX1; *maxY=maxY1; } } void CGroupTyBase::DrawGroup(CDC *pDC, CDrawInfoBase *pView) { int count=m_ArrChilds.GetCount(); CTyBase* pTy; for (int i=0;i<count;i++) { tagShowProp* pProp=m_ArrChilds.GetAt(i); assert(pProp!=NULL); pTy=pProp->pChildTy; assert(pTy!=NULL); if (pTy==NULL) continue; if (pTy->IsTextTy()==true) continue; pTy->DrawDC(pDC,pView); } } //自动转换组合图元的点参数 void CGroupTyBase::ParamReplaceGroup(void) { CStringList ruleList; CString str; str.Format("3,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d",m_groupRtuInfo.rtu_count, m_groupRtuInfo.rtu[0].node_id,m_groupRtuInfo.rtu[0].line_id,m_groupRtuInfo.rtu[0].rtu_id, m_groupRtuInfo.rtu[1].node_id,m_groupRtuInfo.rtu[1].line_id,m_groupRtuInfo.rtu[1].rtu_id, m_groupRtuInfo.rtu[2].node_id,m_groupRtuInfo.rtu[2].line_id,m_groupRtuInfo.rtu[2].rtu_id, m_groupRtuInfo.rtu[3].node_id,m_groupRtuInfo.rtu[3].line_id,m_groupRtuInfo.rtu[3].rtu_id); ruleList.AddTail(str); int count=m_ArrChilds.GetCount(); CTyBase* pTy; for (int i=0;i<count;i++) { tagShowProp* pProp=m_ArrChilds.GetAt(i); assert(pProp!=NULL); pTy=pProp->pChildTy; assert(pTy!=NULL); if (pTy==NULL) continue; pTy->ParamReplace(ruleList); } SetModifiedFlag(true); } void CGroupTyBase::OnEditProperties(CDrawInfoBase * pView) { CDlgGroupScale dlg; CPropertySheet Property; Property.AddPage(&dlg); Property.SetTitle("组合图元属性.."); //Property.m_psh.dwFlags|=PSH_NOAPPLYNOW; //dlg.m_psp.dwFlags&=~PSP_HASHELP; dlg.SetContent(m_xScale,m_yScale,m_bText,m_bBmp); //dlg.SetGroupInfo(&m_groupTypeInfo); if(Property.DoModal()==IDOK) { float xScale,yScale; BOOL bText,bBmp; dlg.GetContent(xScale,yScale,bText,bBmp); SetModifiedFlag(true); SetGroupScale(xScale,yScale,bText,bBmp,pView); c_xScale=m_xScale; c_yScale=m_yScale; c_bText=m_bText; c_bBmp=m_bBmp; } } void CGroupTyBase::OnEditProperties_2(CDrawInfoBase * pView) { CNewGroupPage dlg; CPropertySheet Property; Property.AddPage(&dlg); Property.SetTitle("组合图元模板属性.."); Property.m_psh.dwFlags|=PSH_NOAPPLYNOW; dlg.m_psp.dwFlags&=~PSP_HASHELP; dlg.SetGroupInfo(&m_groupTypeInfo); if(Property.DoModal()==IDOK) { dlg.GetGroupInfo(&m_groupTypeInfo); m_groupRtuInfo.rtu_count=m_groupTypeInfo.nRtuCount; for (int i=0;i<MAX_GRP_RTU_NUM;i++) { strcpy(m_groupRtuInfo.rtu[i].name,m_groupTypeInfo.RtuInfo[i].Name); m_groupRtuInfo.rtu[i].rtu_type=m_groupTypeInfo.RtuInfo[i].nModType; } SetModifiedFlag(true); } } //创建组合模板的一个实例 BOOL CGroupTyBase::OnCreateSample(CDrawInfoBase * pView) { BOOL ret=false; if (g_DLL.m_pFunc_ShowFindRtuDlg==NULL) return ret; S_GROUPRTU rec; memset(&rec,0,sizeof(S_GROUPRTU)); memcpy(&rec,&m_groupRtuInfo,sizeof(S_GROUPRTU)); ret=true; if ((*g_DLL.m_pFunc_ShowFindRtuDlg)(&rec)==true) { for (int i=0;i<rec.rtu_count;i++) { if (rec.rtu[i].rtu_id==-1) { ret=false; continue; } } memcpy(&m_groupRtuInfo,&rec,sizeof(S_GROUPRTU)); ParamReplaceGroup(); } else { ret = false; } // ret=true; return ret; } //获取组合图元的单元配置参数 BOOL CGroupTyBase::GetGroupTyRtuParam(S_GROUPRTU& vParam) { memcpy(&vParam,&m_groupRtuInfo,sizeof(S_GROUPRTU)); return true; } int CGroupTyBase::GetHandleCount() { return 8; } PointStruct CGroupTyBase::GetHandle(int nHandle) { ASSERT_VALID(this); PointStruct pt; float x0,y0,x1,y1; GetRect(&x0,&y0,&x1,&y1); switch (nHandle) { default: ASSERT(FALSE); case 1: pt.x = x0; pt.y = y0; break; case 2: pt.x = (x1+x0)/2; pt.y = y0; break; case 3: pt.x = x1; pt.y = y0; break; case 4: pt.x = x1; pt.y = (y0+y1)/2; break; case 5: pt.x = x1; pt.y = y1; break; case 6: pt.x = (x1+x0)/2; pt.y = y1; break; case 7: pt.x = x0; pt.y = y1; break; case 8: pt.x = x0; pt.y = (y0+y1)/2; break; } return pt; } HCURSOR CGroupTyBase::GetHandleCursor(int nHandle) { ASSERT_VALID(this); LPCTSTR id; switch (nHandle) { default: ASSERT(FALSE); case 1: case 5: id=IDC_SIZENWSE; break; case 2: case 6: id=IDC_SIZENS; break; case 3: case 7: id=IDC_SIZENESW; break; case 4: case 8: id=IDC_SIZEWE; break; } return AfxGetApp()->LoadStandardCursor(id); } void CGroupTyBase::SetGroupScale(float xScale, float yScale,BOOL bText,BOOL bBmp,CDrawInfoBase *pView) { if ((xScale==m_xScale)&&(yScale==m_yScale)&&(m_bText==bText)&&(m_bBmp==bBmp)) { return; } float x0,y0,x1,y1; GetRect(&x0,&y0,&x1,&y1); PointStruct point; memset(&point,0,sizeof(PointStruct)); point.x=x0+(x1-x0)/m_xScale; point.y=y0+(y1-y0)/m_yScale; Ty_MoveHandleTo(5,point,pView,0); m_bText=bText; m_bBmp=bBmp; GetRect(&x0,&y0,&x1,&y1); point.x=x0+(x1-x0)*xScale; point.y=y0+(y1-y0)*yScale; Ty_MoveHandleTo(5,point,pView,0); //m_xScale=xScale; //m_yScale=yScale; } void CGroupTyBase::Ty_MoveHandleTo(int nHandle, PointStruct point, CDrawInfoBase *pView,UINT nFlags) { //assert(pView!=NULL); if (pView!=NULL) pView->InvalidateTy(this); CPixelTranslate vTranslate; tagTranslateInfo vInfo; memset(&vInfo,0,sizeof(tagTranslateInfo)); GetRect(&vInfo.vSrcX0,&vInfo.vSrcY0,&vInfo.vSrcX1,&vInfo.vSrcY1); vInfo.vDstX=point.x; vInfo.vDstY=point.y; vInfo.nFlags=nFlags; vInfo.vHandle=nHandle; vInfo.pView=pView; vInfo.bText=m_bText; float xScale=-1,yScale=-1; vTranslate.GetXYScale(xScale,yScale,vInfo); // if ((xScale>4)||(xScale<0.01)) // assert(false); if (xScale>0) { xScale=m_xScale*xScale; if ((xScale>20)||(xScale<0.1)) return; m_xScale=xScale; } if (yScale>0) { yScale=m_yScale*yScale; if ((yScale>20)||(yScale<0.1)) return; m_yScale=yScale; } RectStruct rt1,rt2; // Ty_MoveHandleTo(nHandle,point,pView,nFlags); CTyBase* pTy=NULL; CHMLayer *pLayer = NULL; int count=m_ArrChilds.GetCount(); for (int i=0;i<count;i++) { tagShowProp* pProp=m_ArrChilds[i]; assert(pProp!=NULL); pTy=pProp->pChildTy; assert(pTy!=NULL); if (pTy==NULL) continue; pTy->GetRect(&rt1.x0,&rt1.y0,&rt1.x1,&rt1.y1); pTy->OnEvent_GroupMoveHandleTo(&vTranslate,vInfo); pLayer = pTy->m_pHMLayer; if (pLayer!=NULL) { pTy->GetRect(&rt2.x0,&rt2.y0,&rt2.x1,&rt2.y1); pLayer->OnPositionChangedTy(pTy,rt1,rt2); } } if (pView!=NULL) pView->InvalidateTy(this); }
07-17
#include "Control.h" extern int16 static_speed; int16 encoder_data_dir[4] = {0}; int16 encoder_data_max[4] = {0}; uint8 pit_flag0 = 0; // 在encoder_control_speed函数中添加: extern int8 xianshi; extern int error; #define GYRO_FILTER_ALPHA 0.8 static float gyro_filtered = 0.0f; int start_flag=0; int16 goal_speed_l=0; int16 goal_speed_r=0; int flag_zhuangtai=0; //0直行,1左转,2右转,3斜左,4斜右,5十字,6丢路,7堵转,8环岛 //后面可以改成结构体 static void dutyUpdate(void); // 结构体里有外部接口,可以声明静态不被其他文件发现,防止函数重名 static void getActualSpeed(void); /*--------------------------------------------------------------*/ /* 结构体定义 */ /*==============================================================*/ pidfunc PID = { // 对增量式PID和位置式PID进行结构体封装,使用例:PID.INC(&lmor, target); .INC = inc_pid, .POS = pos_pid }; // 左电机转速 pidpara lmor_spd = { .alpha = 0.12, .Kp =0.5, .Ki = 0.01, .Kd = 0, .thrsod = 700, .action = dutyUpdate, .getAct = getActualSpeed }; // 右电机转速 7-8 pidpara rmor_spd = { .alpha = 0.12, .Kp =0.5, .Ki = 0.01, .Kd = 0, .thrsod = 700, .action = dutyUpdate, .getAct = getActualSpeed }; // 转角控制 pidpara_po turn_spd = { .alpha = 0.2, .Kp = 2.55, .Ki = 0, .Kd = 20, .Kp2 = 0, .GKD = 0, .thrsod =1500, .action = dutyUpdate, .getAct = getActualSpeed }; void control_init(void) //控制信号初始化准备,默认 { gpio_init(DIR_R1, GPO, GPIO_LOW, GPO_PUSH_PULL); // GPIO 初始化为输出 默认上拉输出高 pwm_init(PWM_R1, 17000, 0); // PWM 通道初始化频率 17KHz 占空比初始为 0 gpio_init(DIR_L1, GPO, GPIO_LOW, GPO_PUSH_PULL); // GPIO 初始化为输出 默认上拉输出高 pwm_init(PWM_L1, 17000, 0); // PWM 通道初始化频率 17KHz 占空比初始为 0 gpio_init(DIR_R2, GPO, GPIO_HIGH, GPO_PUSH_PULL); gpio_init(DIR_L2, GPO, GPIO_LOW, GPO_PUSH_PULL); // GPIO 初始化为输出 默认上拉输出高 } //=====================================车轮速度基础控制模块 //motor1 左车轮转速控制 //motor2 右车轮转速控制 void speed_control(int16 motor1, int16 motor2) { motor1=motor1*1; motor2=motor2*1; if(motor1 > MAX_DUTY) motor1 = MAX_DUTY; else if(motor1 < MIN_DUTY) motor1 = MIN_DUTY; if(motor1>0) { gpio_set_level(DIR_L1, GPIO_HIGH); // DIR输出高电平 pwm_set_duty(PWM_L1, motor1 * (PWM_DUTY_MAX / 1000)); // 计算占空比 gpio_set_level(DIR_L2, GPIO_LOW); // DIR输出高电平 } else { gpio_set_level(DIR_L1, GPIO_HIGH); // DIR输出低电平 pwm_set_duty(PWM_L1,(-motor1) * (PWM_DUTY_MAX / 1000)); // 计算占空比 gpio_set_level(DIR_L2, GPIO_HIGH); } if(motor2 > MAX_DUTY) motor2 = MAX_DUTY; else if(motor2 < MIN_DUTY) motor2 = MIN_DUTY; if(motor2>0) { gpio_set_level(DIR_R1, GPIO_HIGH); // DIR输出高电平 pwm_set_duty(PWM_R1, motor2 * (PWM_DUTY_MAX / 1000)); // 计算占空比 gpio_set_level(DIR_R2, GPIO_HIGH); // DIR输出高电 } else { gpio_set_level(DIR_R1, GPIO_HIGH); // DIR输出低电平 pwm_set_duty(PWM_R1, (-motor2) * (PWM_DUTY_MAX / 1000)); // 计算占空比 gpio_set_level(DIR_R2, GPIO_LOW); // DIR输出低电平 } //ips114_show_int(180, 85, motor1,5); // ips114_show_int(180, 102, motor2,5); } //===============================================基础动作以及调整 //前进 //speed 前进速度 void control_go(int16 speed) { if(speed>MAX_SPEED) speed=MAX_SPEED; speed_control(speed,speed); static_speed=speed; } //左偏 //speed 前进速度 void control_shiftleft(int16 degree,int16 speed) { if(speed==-1) speed=static_speed; if(degree>MAX_DEGREE) degree=MAX_DEGREE; speed_control(speed-degree,speed+degree); }//右偏 //speed 前进速度 void control_shiftright(int16 degree,int16 speed) { if(speed==-1) speed=static_speed; if(degree>MAX_DEGREE) degree=MAX_DEGREE; speed_control(speed+degree,speed-degree); } //后退 //speed 后退速度 void control_back(int16 speed) { if(speed>MAX_SPEED) speed=MAX_SPEED; speed_control(-speed,-speed); static_speed=-speed; } //===========================================编码器初始化 void encoder_init(void) { encoder_dir_init(ENCODER_DIR1, ENCODER_DIR_PULSE1, ENCODER_DIR_DIR1); // 初始化编码器模块与引脚 带方向增量编码器模式 encoder_dir_init(ENCODER_DIR2, ENCODER_DIR_PULSE2, ENCODER_DIR_DIR2); // 初始化编码器模块与引脚 带方向增量编码器模式 pit_ms_init(PIT0, 20); // 初始化 PIT0 为周期中断 20ms 周 } //===========================================编码器测试 uint8 encoder_get(int i) { return encoder_data_dir[i]; } /*----------------------*/ /* 增量PID模块 */ /*======================*/ void inc_pid(struct pidpara *para, const short tar){ // 参数列表-> para:调定参数 | tar:目标值 | act:实际值 | value:控制量 | thrsod:阈值 // 变量定义 float yn; // 保存和计算误差 para->e3 = para->e2; para->e2 = para->e1; para->e1 = tar - para->act; yn = para->I; // PID公式 para->I = para->Ki*para->e1; // 一阶低通滤波(积分项 para->I = para->alpha*para->I + (1-para->alpha)*yn; para->rs += para->Kp*(para->e1-para->e2) + para->I + para->Kd*(para->e1 - 2*para->e2 + para->e3); // 阈值限定 if(abs(para->rs) > para->thrsod){ if(para->rs >= 0) para->rs = para->thrsod; else para->rs = -para->thrsod; } } /*----------------------*/ /* 位置PID模块 */ /*======================*/ void pos_pid(struct pidpara_po *para, const short tar){ // 参数列表-> para:调定参数 | tar:目标值 | act:实际值 | max:最大控制值 | min:最小控制值 // 保存和计算误差 para->e2 = para->e1; para->e1 = tar - para->act; para->e1 = para ->alpha*para->e1+(1-para->alpha)*para->e2; // PID公式 para->rs = (para->Kp)*para->e1 + (para->Kp2)*para->e1*abs(para->e1)+para->Kd*(para->e1 - para->e2)+para->GKD*para->imu; // 阈值限定 if(abs(para->rs) > para->thrsod){ if(para->rs >= 0) para->rs = para->thrsod; else para->rs = -para->thrsod; } } int getCalculateResult(const struct pidpara *para){ // 返回计算结果 return para->rs; } static void dutyUpdate(void){ // 用以更新占空比 return; } static void getActualSpeed(void){ // 用以获取实际速度 return; } // 归一化处理函数 float normalize_image_error(int raw_error) { } //=========================================编码器闭环速度 //==========================思路1,绝对控制附加增益,思路2,相对控制; void encoder_control_speed(int16 motor1,int16 motor2) { static int16 slow_count_l=0; static int16 slow_count_r=0; static int last_motor=0; int16 sl_mol,sl_mor; int16 tar_lf; int16 tar_rg; static int16 error_mol=0,error_mor=0; int16 error_lf_mix=0; int16 error_rg_mix=0; static int16 start_count=0; // 根据历史数据动态调整 if(last_motor!=motor1) { last_motor=motor1; lmor_spd.I=0; lmor_spd.rs=0; rmor_spd.I=0; rmor_spd.rs=0; } tar_lf=motor1*2.5; //编码器增益为100→400 tar_rg=motor2*2.5; if(pit_flag0&&start_flag) { pit_flag0=0; lmor_spd.act= encoder_data_dir[0]; rmor_spd.act= encoder_data_dir[1]; turn_spd.act = -error; // 缩放至合适控制范围 turn_spd.imu=GYRO_FILTER_ALPHA*imu660ra_gyro_transition(imu660ra_gyro_z)*2+ (1 - GYRO_FILTER_ALPHA) * gyro_filtered; gyro_filtered = turn_spd.imu; // 更新滤波值 pos_pid(&turn_spd,0); //角度位置式pid闭环 //ips114_show_int(0, 15, turn_spd.rs,5); tar_lf=tar_lf+turn_spd.rs; tar_rg=tar_rg-turn_spd.rs; inc_pid(&lmor_spd,tar_lf); inc_pid(&rmor_spd,tar_rg); //速度增量式pid闭环 error_mol=lmor_spd.rs; error_mor=rmor_spd.rs; } if(start_flag) { if(flag_zhuangtai==3) { if(slow_count_l>goal_speed_l) { sl_mol=slow_count_l; slow_count_l=slow_count_l-2; } else { sl_mol=goal_speed_l; } if(slow_count_r>goal_speed_r) { sl_mor=slow_count_r; slow_count_r=slow_count_r-2; } else { sl_mor=goal_speed_r; } speed_control(motor1,motor2); } else{ error_lf_mix=error_mol/2.5; error_rg_mix=error_mor/2.5; if(xianshi) { ips114_show_int(180, 85,error_mol,5); ips114_show_int(180, 102,error_mor,5); } if((motor1+error_lf_mix)>190) {error_lf_mix=190-motor1; lmor_spd.rs=error_lf_mix*2.5; } if((motor2+error_rg_mix)>190) { error_rg_mix=190-motor2; rmor_spd.rs=error_rg_mix*2.5; } speed_control(motor1+error_lf_mix,motor2+error_rg_mix); slow_count_r=motor2+error_rg_mix; slow_count_l=motor1+error_lf_mix; } } else { if(start_flag==0) { if(start_count<motor1-15) { speed_control(start_count,start_count); start_count=start_count+2; } else {speed_control(motor1-15,motor2-15); start_flag=1; } } else { speed_control(motor1+error_lf_mix,motor2+error_rg_mix); } } } /********************************************************************************************************************* * CYT2BL3 Opensourec Library 即( CYT2BL3 开源库)是一个基于官方 SDK 接口的第三方开源库 * Copyright (c) 2022 SEEKFREE 逐飞科技 * * 本文件是 CYT2BL3 开源库的一部分 * * CYT2BL3 开源库 是免费软件 * 您可以根据自由软件基金会发布的 GPL(GNU General Public License,即 GNU通用公共许可证)的条款 * 即 GPL 的第3版(即 GPL3.0)或(您选择的)任何后来的版本,重新发布和/或修改它 * * 本开源库的发布是希望它能发挥作用,但并未对其作任何的保证 * 甚至没有隐含的适销性或适合特定用途的保证 * 更多细节请参见 GPL * * 您应该在收到本开源库的同时收到一份 GPL 的副本 * 如果没有,请参阅<https://www.gnu.org/licenses/> * * 额外注明: * 本开源库使用 GPL3.0 开源许可证协议 以上许可申明为译文版本 * 许可申明英文版在 libraries/doc 文件夹下的 GPL3_permission_statement.txt 文件中 * 许可证副本在 libraries 文件夹下 即该文件夹下的 LICENSE 文件 * 欢迎各位使用并传播本程序 但修改内容时必须保留逐飞科技的版权声明(即本声明) * * 文件名称 main_cm4 * 公司名称 成都逐飞科技有限公司 * 版本信息 查看 libraries/doc 文件夹内 version 文件 版本说明 * 开发环境 IAR 9.40.1 * 适用平台 CYT2BL3 * 店铺链接 https://seekfree.taobao.com/ * * 修改记录 * 日期 作者 备注 * 2024-11-19 pudding first version ********************************************************************************************************************/ #include "zf_common_headfile.h" #include <ctype.h> // 打开新的工程或者工程移动了位置务必执行以下操作 // 第一步 关闭上面所有打开的文件 // 第二步 project->clean 等待下方进度条走完 // **************************** 代码区域 **************************** //============================显示屏区域================================ //============================显示屏区域================================ #define UART_RECEVIER_UART_INDEX (UART_2) // 使用 UART2 #define UART_RECEVIER_BAUDRATE (115200) // 波特率 #define UART_RECEVIER_TX_PIN (UART2_RX_P07_0) // TX 引脚(占位) #define UART_RECEVIER_RX_PIN (UART2_TX_P07_1) // RX 引脚(实际连接) #define MAX_PACKET_SIZE 64 // 全局变量用于解析数据包 uint8 rx_buffer[MAX_PACKET_SIZE]; // 存储接收到的原始数据 uint8 rx_index = 0; // 当前接收索引 uint8 packet_start = 0; // 是否找到起始符 $ uint8 packet_end = 0; // 是否找到结束符 * uint8 uart2_get_data[64]; // UART2 接收缓冲区 uint8 fifo2_get_data[64]; // FIFO 读取缓冲区 uint8 get_data_uart2 = 0; // 接收临时变量 uint32 uart2_fifo_count = 0; // FIFO 中的数据个数 fifo_struct uart2_data_fifo; // UART2 的 FIFO 结构体 /* ============== 新增 SCB4 配置 ============== */ #define UART_SCB4_INDEX (UART_1) // 使用 SCB4 作为 UART4 #define UART_SCB4_BAUDRATE (115200) // 波特率 #define UART_SCB4_RX_PIN (UART1_RX_P06_0) // RX 引脚 #define UART_SCB4_TX_PIN (UART1_TX_P06_1) // TX 引脚 // SCB4 接收相关全局变量 uint8 uart4_get_data[64]; // UART4 接收缓冲区 uint8 fifo4_get_data[64]; // FIFO 读取缓冲区 uint8 get_data_uart4 = 0; // 接收临时变量 uint32 uart4_fifo_count = 0; // FIFO 中的数据个数 fifo_struct uart4_data_fifo; // UART4 的 FIFO 结构体 // SCB4 数据包解析变量 uint8 rx_buffer_scb4[MAX_PACKET_SIZE]; // 存储接收到的原始数据 uint8 packet_start_scb4 = 0; // 是否找到起始符 $ uint8 packet_end_scb4 = 0; // 是否找到结束符 * uint8 rx_index_scb4 = 0; // 当前接收索引 #define IR_SENSOR_COUNT 8 // 红外传感器数量 uint8_t ir_sensor_values[IR_SENSOR_COUNT]; // 存储八路红外数据 uint8 sum_ir; //变量初始化 extern int8 xianshi; //控制显示变量 extern int16 encoder_data_dir[4]; //编码器数值 extern int16 encoder_data_max[4]; //编码器最大值 extern uint8 pit_flag0; //编码器数值更新标志 extern int8 start_f; //开始标志 extern int16 brzeeT; //蜂鸣器计时 extern void (*flag_mode[])(void); char buffer[32]; // 用于存储格式化字符串 extern int error; //记录误差值 extern int8 mode_point; //模式指针 extern int16 goal_speed_l; //左转预期值 extern int16 goal_speed_r; //右转预期值 int8 stop_f=1; extern int8 receive_flag; extern int start_flag; extern int16 slow_count; //uint32_t frame_count = 0; // 当前帧计数 //uint16_t fps_value = 0; // 存储当前 FPS 值,便于显示 int main(void) { clock_init(SYSTEM_CLOCK_160M); // 时钟配置及系统初始化<务必保留> debug_init(); // 调试串口初始化 system_delay_ms(100); ips114_init(); //屏幕显示初始化 ips114_show_string(0, 16, "init success."); control_init(); //电机控制初始化 encoder_init(); //编码器初始化 // pit_ms_init(PIT_CH10, 10); // 此处编写用户代码 例如外设初始化代码等 gpio_init(P23_7, GPO, GPIO_LOW, GPO_PUSH_PULL); // 初始化 LED1 输出 gpio_set_level(P23_7, 0); //蜂鸣器初始化 // 初始化 UART2 的 FIFO fifo_init(&uart2_data_fifo, FIFO_DATA_8BIT, uart2_get_data, 64); // 初始化 UART2 uart_init(UART_RECEVIER_UART_INDEX, UART_RECEVIER_BAUDRATE, UART_RECEVIER_TX_PIN, UART_RECEVIER_RX_PIN); // 启用 UART2 接收中断 uart_rx_interrupt(UART_RECEVIER_UART_INDEX, 1); // 初始化 UART1 的 FIFO fifo_init(&uart4_data_fifo, FIFO_DATA_8BIT, uart4_get_data, 64); // 初始化 UART1 uart_init(UART_SCB4_INDEX, UART_SCB4_BAUDRATE, UART_SCB4_TX_PIN, UART_SCB4_RX_PIN); uart_rx_interrupt(UART_SCB4_INDEX, 1); IMU_Init(); //陀螺仪初始化 key_init(10); //10ms扫描一次 ips114_show_string(0, 36, "init success."); uart_write_string(UART_SCB4_INDEX, "$0,0,1#"); // 此处编写用户代码 例如外设初始化代码等 // ========== 添加:初始化 FPS 时间基准 ========== // frame_count = 0; // fps_value = 0; for(;;) { // frame_count++; // 主循环每运行一次,帧数 +1 flag_mode[mode_point](); //ips114_show_int(10, 116, IMU_360_Value.Z_360,5); // ips114_show_int(10, 76, imu660ra_gyro_transition(imu660ra_gyro_z)- Gyro_Offset.Zdata ,5); uart2_fifo_count = fifo_used(&uart2_data_fifo); // 检查 FIFO 中是否有数据 if (uart2_fifo_count > 0) { fifo_read_buffer(&uart2_data_fifo, fifo2_get_data, &uart2_fifo_count, FIFO_READ_AND_CLEAN); for (uint32_t i = 0; i < uart2_fifo_count; i++) { uint8_t ch = fifo2_get_data[i]; if (!packet_start) { if (ch == '$') { rx_index = 0; packet_start = 1; } } else { if (ch == '*') { packet_end = 1; rx_buffer[rx_index] = '\0'; // 字符串结束符 break; } else if (rx_index < MAX_PACKET_SIZE - 1) { rx_buffer[rx_index++] = ch; } else { // 缓冲区溢出,重置 packet_start = 0; rx_index = 0; } } } if (packet_start && packet_end) { // 成功提取出内容 int dy; if (sscanf((char*)rx_buffer, "%d", &dy) == 1) { // 成功解析 dx 和 dy // 更新全局变量或用于控制 // 示例:假设你有全局变量 left_de 和 right_de error = (int)dy; receive_flag=1; ips114_show_int(180, 15, error,4); if(error==1000&&flag_zhuangtai==0) { error=0; // speed_control(210,-210); // system_delay_ms(5); gpio_set_level(P23_7, 1); brzeeT=1; IMU_360_Value.Z_360=0; flag_zhuangtai=1; } else if(error==1500&&flag_zhuangtai==0) { error=0; // speed_control(210,-210); // system_delay_ms(5); // gpio_set_level(P23_7, 1); // brzeeT=1; IMU_360_Value.Z_360=0; flag_zhuangtai=2; } else if(error==2000) { error=0; flag_zhuangtai=3; goal_speed_l=20; goal_speed_l=20; // gpio_set_level(P23_7, 1); // brzeeT=2; } } // 重置状态 packet_start = 0; packet_end = 0; rx_index = 0; } } uart4_fifo_count = fifo_used(&uart4_data_fifo); if(uart4_fifo_count > 0) { // 从FIFO读取数据到缓冲区 fifo_read_buffer(&uart4_data_fifo, fifo4_get_data, &uart4_fifo_count, FIFO_READ_AND_CLEAN); for(uint32_t i = 0; i < uart4_fifo_count; i++) { uint8_t ch = fifo4_get_data[i]; if(!packet_start_scb4) { if(ch == '$') { rx_index_scb4 = 0; packet_start_scb4 = 1; } } else { if(ch == '#') { packet_end_scb4 = 1; rx_buffer_scb4[rx_index_scb4] = '\0'; // 添加字符串结束符 break; } else if(rx_index_scb4 < MAX_PACKET_SIZE - 1) { rx_buffer_scb4[rx_index_scb4++] = ch; } else { // 缓冲区溢出,重置 packet_start_scb4 = 0; rx_index_scb4 = 0; } } } if(packet_start_scb4 && packet_end_scb4) { char *ptr = (char*)rx_buffer_scb4; int sensor_idx = 0; // 验证头部 if(ptr[0] == 'D' && ptr[1] == ','&&flag_zhuangtai==3) { sum_ir=0; ptr += 2; // 跳过 "D," // 逐个解析传感器数据 while(*ptr != '\0' && sensor_idx < IR_SENSOR_COUNT) { // 定位冒号位置 (格式: "xN:V") if(ptr[0] == 'x' && isdigit(ptr[1]) && ptr[2] == ':') { // 直接提取值字符 char val_char = ptr[3]; // 转换并存储 ir_sensor_values[sensor_idx] = (val_char == '1') ? 1 : 0; sum_ir+= ir_sensor_values[sensor_idx] ; sensor_idx++; // 移动到下一个数据项 ptr += 4; // 跳过 "xN:V" if(*ptr == ',') ptr++; // 跳过逗号 } else { break; // 格式错误退出 } } if(sum_ir<=7&&sum_ir>=2) { if(mode_point==1) { flag_zhuangtai=0; speed_control(-180,-180); mode_point=2; } else if(mode_point==3) { flag_zhuangtai=0; speed_control(-180,-180); mode_point=4; } } } // 显示所有传感器值(调试用) // for(int i = 0; i < IR_SENSOR_COUNT; i++) { // ips114_show_int(100, 2 + i*10, ir_sensor_values[i], 1); // } packet_start_scb4 = 0; packet_end_scb4 = 0; rx_index_scb4 = 0; } } if(xianshi) { ips114_show_int(180, 5, flag_zhuangtai,2); // ips114_show_int(185, 116, right_de,2); // ips114_show_int(10, 100, fps_value, 3); // 显示 FPS,最多三位数 // ips114_show_string(10, 80, "FPS:"); ips114_show_int(180, 45, encoder_data_dir[0],3); ips114_show_int(180, 65, encoder_data_dir[1],3); // 输出测试信息 } // ips114_show_int(180, 45, encoder_data_max[0],5); // ips114_show_int(180, 65, encoder_data_max[1],5); // 此处编写需要循环执行的代码 } } void wait_go_1(void) //0 等发车 { if(start_f==1) { start_f=0; stop_f=0; mode_point=1; uart_write_string(UART_RECEVIER_UART_INDEX, "$1*"); } else { speed_control(0,0); } } void go_1(void) //1 任务1发车 { if(flag_zhuangtai==1) { speed_control(-45,95); } else if(flag_zhuangtai==2) { speed_control(95,-46); } else if(flag_zhuangtai==3) encoder_control_speed(30,30); else encoder_control_speed(120,120); } void wait_back_1(void) //2 到病房_任务1 { if( encoder_data_dir[0]==0&& encoder_data_dir[1]==0&&stop_f==0) { gpio_set_level(P23_7, 1); stop_f=1; brzeeT=20; } else if(start_f==1) { start_f=0; // start_flag=0; stop_f=0; mode_point=3; flag_zhuangtai=4; uart_write_string(UART_RECEVIER_UART_INDEX, "$30*"); } if(stop_f==0) { int l_s,r_s; if(encoder_data_dir[0]>0) l_s=-encoder_data_dir[0]*0.4; else l_s=0; if(encoder_data_dir[1]>0) r_s=-encoder_data_dir[1]*0.4; else r_s=0; speed_control(l_s,r_s); } else speed_control(0,0); } void back_1(void) //3 任务1返回 { if(flag_zhuangtai==4) { speed_control(115,-115); } else if(flag_zhuangtai==1) { speed_control(-45,95); } else if(flag_zhuangtai==2) { speed_control(95,-45); } else if(flag_zhuangtai==3) speed_control(30,30); else encoder_control_speed(120,120); } void finish_1(void) //4 任务1结束 { if( encoder_data_dir[0]==0&& encoder_data_dir[1]==0&&stop_f==0) { gpio_set_level(P23_7, 1); stop_f=1; brzeeT=20; } else if(start_f==1) { start_f=0; start_flag=0; stop_f=0; mode_point=5; // uart_write_string(UART_RECEVIER_UART_INDEX, "$30*"); } if(stop_f==0) { int l_s,r_s; if(encoder_data_dir[0]>0) l_s=-encoder_data_dir[0]*0.4; else l_s=0; if(encoder_data_dir[1]>0) r_s=-encoder_data_dir[1]*0.4; else r_s=0; speed_control(l_s,r_s); } else speed_control(0,0); } void wait_go_2(void) //5 任务2等发车 { speed_control(90 ,90); } void go_2(void) //6 任务2发车 { speed_control(100,115); // system_delay_ms(50); flag_zhuangtai=0; } void wait_back_2(void) //7 任务2到病房 { speed_control(0,0); system_delay_ms(10000); } void back_2(void) //8 任务2返回 { } void finish_2(void) //9 任务2结束 { encoder_control_speed(80,80); } void wait_go_3(void) //10 任务3等发车 { encoder_control_speed(80,80); } void go_3(void) //11 任务3发车 { speed_control(40,130); } void wait_back_3(void) //12 任务3到病房 { speed_control(40,130); } void back_3(void) //13 任务3返回 { speed_control(40,130); } void finish_3(void) //13 任务3 结束 { speed_control(40,130); } void (*flag_mode[])(void) = { wait_go_1, go_1, wait_back_1, back_1, finish_1, wait_go_2, go_2, wait_back_2, back_2, finish_2, wait_go_3, go_3, wait_back_3, back_3, finish_3 }; void uart_rx_interrupt_handler (void) { // get_data = uart_read_byte(UART_INDEX); // 接收数据 while 等待式 不建议在中断使用 if(uart_query_byte(UART_RECEVIER_UART_INDEX, &get_data_uart2)) // 接收数据 查询式 有数据会返回 TRUE 没有数据会返回 FALSE { fifo_write_buffer(&uart2_data_fifo, &get_data_uart2, 1); // 将数据写入 fifo 中 } } void uart4_rx_interrupt_handler (void) { // get_data = uart_read_byte(UART_INDEX); // 接收数据 while 等待式 不建议在中断使用 if(uart_query_byte(UART_SCB4_INDEX, &get_data_uart4)) { fifo_write_buffer(&uart4_data_fifo, &get_data_uart4, 1); } } // **************************** 代码区域 **************************** /********************************************************************************************************************* * CYT2BL3 Opensourec Library 即( CYT2BL3 开源库)是一个基于官方 SDK 接口的第三方开源库 * Copyright (c) 2022 SEEKFREE 逐飞科技 * * 本文件是 CYT2BL3 开源库的一部分 * * CYT2BL3 开源库 是免费软件 * 您可以根据自由软件基金会发布的 GPL(GNU General Public License,即 GNU通用公共许可证)的条款 * 即 GPL 的第3版(即 GPL3.0)或(您选择的)任何后来的版本,重新发布和/或修改它 * * 本开源库的发布是希望它能发挥作用,但并未对其作任何的保证 * 甚至没有隐含的适销性或适合特定用途的保证 * 更多细节请参见 GPL * * 您应该在收到本开源库的同时收到一份 GPL 的副本 * 如果没有,请参阅<https://www.gnu.org/licenses/> * * 额外注明: * 本开源库使用 GPL3.0 开源许可证协议 以上许可申明为译文版本 * 许可申明英文版在 libraries/doc 文件夹下的 GPL3_permission_statement.txt 文件中 * 许可证副本在 libraries 文件夹下 即该文件夹下的 LICENSE 文件 * 欢迎各位使用并传播本程序 但修改内容时必须保留逐飞科技的版权声明(即本声明) * * 文件名称 cm4_isr * 公司名称 成都逐飞科技有限公司 * 版本信息 查看 libraries/doc 文件夹内 version 文件 版本说明 * 开发环境 IAR 9.40.1 * 适用平台 CYT2BL3 * 店铺链接 https://seekfree.taobao.com/ * * 修改记录 * 日期 作者 备注 * 2024-1-9 pudding first version * 2024-5-14 pudding 新增12个pit周期中断 增加部分注释说明 ********************************************************************************************************************/ #include "zf_common_headfile.h" extern int16 encoder_data_dir[4]; extern int16 encoder_data_max[4]; extern uint8 pit_flag0; //编码器更新标志 extern int start_flag; int8 start_f=0; //开始 uint16 turn_timeout = 0; //转向时间限制 int16 brzeeT=0; //蜂鸣器时间 int8 xianshi=1; //显示屏显示函数 int error=0; //误差值 int8 mode_point=0; //模式指针 extern char buffer[32]; int16 slow_count=0; int8 receive_flag=0; int8 turn_count=0; //extern uint32_t frame_count; // 当前帧计数 //uint32_t time_count = 0; // 上次更新时间(ms) //extern uint16_t fps_value; // 存储当前 FPS 值,便于显示 // 在文件开头添加宏定义 #define DT 0.005f // 实际中断时间间隔(秒) #define TARGET_ANGLE 54.0f // 目标转角 #define LEST_TARGLE 47.0f //最小判断转角 #define TURN_TARGET_ANGLE 140.0f // 目标转角 #define TURN_LEST_TARGLE 100.0f //最小判断转角 // **************************** PIT中断函数 **************************** void pit0_ch0_isr() // 定时器通道 0 周期中断服务函数 { pit_isr_flag_clear(PIT_CH0); tsl1401_collect_pit_handler(); } // 20ms void pit0_ch1_isr() // 定时器通道 1 周期中断服务函数 { pit_isr_flag_clear(PIT_CH1); pit_flag0=1; // if(pit_flag0) // pit_flag0 = 0; encoder_data_dir[0] = encoder_get_count(ENCODER_DIR1); encoder_clear_count(ENCODER_DIR1); encoder_data_dir[1] = -(encoder_get_count(ENCODER_DIR2)); encoder_clear_count(ENCODER_DIR2); //蜂鸣器响应 if(brzeeT>1) brzeeT--; else if(brzeeT==1) { brzeeT=0; gpio_set_level(P23_7, 0); } if(slow_count>1) slow_count--; else if(slow_count==1) { slow_count=0; uart_write_string(UART_RECEVIER_UART_INDEX, "$20*"); } /*===============turn_count计数 *20ms================= 1.状态9 入环巡线 退出 转到0状态 并且turn_8=1 2.状态10 出环巡线 退出 转到0状态 并且turn_8=0; 3.状态5 过十字 退出 转到0状态 =============================================*/ /*===============左转右转间隔*20ms================= =============================================*/ // ips114_show_float (170,45,IMU_360_Value.Z_360, 3,2 ); } /*==================================转弯和按键检测=================================== 这里思路: 10ms 按键检测略去 直角转弯: 1.陀螺仪 累加到30° 2.定时退出 定时到5 3.退出设置 状态0 转弯抑制 左转右转间隔设置 30°转弯: 1.陀螺仪 累加到30° 2.定时退出 定时到5 3.退出设置 设置定时 进入靠右巡线 zhuangtai9 ===============================转弯和按键检测=====================================*/ void pit0_ch2_isr() // 定时器通道 2 周期中断服务函数 { pit_isr_flag_clear(PIT_CH2); //按键检测部分 key_scanner(); if(key_get_state(KEY_1)==KEY_SHORT_PRESS||key_get_state(KEY_1)==KEY_LONG_PRESS) { start_f=1; } if(key_get_state(KEY_2)==KEY_SHORT_PRESS||key_get_state(KEY_2)==KEY_LONG_PRESS) { flag_zhuangtai=1; IMU_360_Value.Z_360 = 0; } if(key_get_state(KEY_3)==KEY_SHORT_PRESS||key_get_state(KEY_3)==KEY_LONG_PRESS) // speed_kong=1-speed_kong; xianshi=1-xianshi; if(key_get_state(KEY_4)==KEY_SHORT_PRESS||key_get_state(KEY_4)==KEY_LONG_PRESS) ; if(key_get_state(KEY_NUMBER)==KEY_SHORT_PRESS||key_get_state(KEY_NUMBER)==KEY_LONG_PRESS) { if(mode_point==0) start_f=1; } else { if(mode_point==2) start_f=1; } // flag_zhuangtai=1; // if(time_count<100) // time_count++; // else if(time_count==100) // { // time_count=0; // fps_value=frame_count; // frame_count=0; // } } void pit0_ch10_isr() // 定时器通道 10 周期中断服务函数 { pit_isr_flag_clear(PIT_CH10); // imu660ra_get_acc(); // 获取 imu660ra 的加速度测量数值 imu660ra_get_gyro(); // 获取 imu660ra 的角速度测量数值 //转向 // 转向控制逻辑重构 static float integrated_angle = 0.0f; float angular_velocity; const float FILTER_GAIN = 0.98f; // 互补滤波器系数 switch(flag_zhuangtai) { case 1: // 左转直角 // 计算角速度(度/秒) angular_velocity = imu660ra_gyro_transition(imu660ra_gyro_z) - Gyro_Offset.Zdata; // 使用互补滤波积分 integrated_angle = FILTER_GAIN * (integrated_angle + angular_velocity * DT) + (1 - FILTER_GAIN) * integrated_angle; IMU_360_Value.Z_360 = integrated_angle; // 角度达到90°或超时退出 if(IMU_360_Value.Z_360 >= TARGET_ANGLE||(error>-130&&error<140&&error!=0&&IMU_360_Value.Z_360 >= LEST_TARGLE&&receive_flag==1)){// || turn_timeout >= turn_time_Max) { turn_count++; ips114_show_int(10, 46, turn_count,3); ips114_show_int(10, 26, IMU_360_Value.Z_360,5); flag_zhuangtai = 0; // speed_control(190,-190); gpio_set_level(P23_7, 1); brzeeT = 3; turn_timeout = 0; // uart_write_string(UART_RECEVIER_UART_INDEX, "$20*"); if(mode_point==1) slow_count=20; else if(mode_point==3) slow_count=30; IMU_360_Value.Z_360 = 0; } turn_timeout++; break; case 2: // 右转直角 angular_velocity = imu660ra_gyro_transition(imu660ra_gyro_z) - Gyro_Offset.Zdata; // 使用相同的互补滤波积分(注意负号) integrated_angle = FILTER_GAIN * (integrated_angle + angular_velocity * DT) + (1 - FILTER_GAIN) * integrated_angle; IMU_360_Value.Z_360 = integrated_angle; // 达到-90°或超时退出 if(IMU_360_Value.Z_360 <= -TARGET_ANGLE||(error>-140&&error<120&&error!=0&&IMU_360_Value.Z_360 <= -LEST_TARGLE&&receive_flag==1)){// || turn_timeout >= turn_time_Max) { ips114_show_int(10, 116, IMU_360_Value.Z_360,5); IMU_360_Value.Z_360 = 0; flag_zhuangtai = 0; turn_timeout = 0; gpio_set_level(P23_7, 1); brzeeT = 3; speed_control(-100,120); if(mode_point==1) slow_count=30; else if(mode_point==3) slow_count=30; } turn_timeout++; break; case 4: // 右向回转 angular_velocity = imu660ra_gyro_transition(imu660ra_gyro_z) + Gyro_Offset.Zdata; // 使用相同的互补滤波积分(注意负号) integrated_angle = FILTER_GAIN * (integrated_angle + angular_velocity * DT) + (1 - FILTER_GAIN) * integrated_angle; IMU_360_Value.Z_360 = integrated_angle; // 达到-90°或超时退出 if(IMU_360_Value.Z_360 <= -TURN_TARGET_ANGLE||(error>-140&&error<150&&error!=0&&IMU_360_Value.Z_360 <= -TURN_LEST_TARGLE&&receive_flag==1)){// || turn_timeout >= turn_time_Max) { IMU_360_Value.Z_360 = 0; flag_zhuangtai = 0; turn_timeout = 0; uart_write_string(UART_RECEVIER_UART_INDEX, "$0*"); } turn_timeout++; break; default: // 非转向状态时重置 integrated_angle = 0.0f; turn_timeout = 0; break; } receive_flag=0; } void pit0_ch11_isr() // 定时器通道 11 周期中断服务函数 { pit_isr_flag_clear(PIT_CH11); } void pit0_ch12_isr() // 定时器通道 12 周期中断服务函数 { pit_isr_flag_clear(PIT_CH12); } void pit0_ch13_isr() // 定时器通道 13 周期中断服务函数 { pit_isr_flag_clear(PIT_CH13); } void pit0_ch14_isr() // 定时器通道 14 周期中断服务函数 { pit_isr_flag_clear(PIT_CH14); } void pit0_ch15_isr() // 定时器通道 15 周期中断服务函数 { pit_isr_flag_clear(PIT_CH15); } void pit0_ch16_isr() // 定时器通道 16 周期中断服务函数 { pit_isr_flag_clear(PIT_CH16); } void pit0_ch17_isr() // 定时器通道 17 周期中断服务函数 { pit_isr_flag_clear(PIT_CH17); } void pit0_ch18_isr() // 定时器通道 18 周期中断服务函数 { pit_isr_flag_clear(PIT_CH18); } void pit0_ch19_isr() // 定时器通道 19 周期中断服务函数 { pit_isr_flag_clear(PIT_CH19); } void pit0_ch20_isr() // 定时器通道 20 周期中断服务函数 { pit_isr_flag_clear(PIT_CH20); } void pit0_ch21_isr() // 定时器通道 21 周期中断服务函数 { pit_isr_flag_clear(PIT_CH21); } // **************************** PIT中断函数 **************************** void uart_rx_interrupt_handler (void); void uart4_rx_interrupt_handler (void); // **************************** 串口中断函数 **************************** // 串口0默认作为调试串口 void uart0_isr (void) { if(uart_isr_mask(UART_0)) // 串口0接收中断 { #if DEBUG_UART_USE_INTERRUPT // 如果开启 debug 串口中断 debug_interrupr_handler(); // 调用 debug 串口接收处理函数 数据会被 debug 环形缓冲区读取 #endif // 如果修改了 DEBUG_UART_INDEX 那这段代码需要放到对应的串口中断去 } else // 串口0发送中断 { } } void uart1_isr (void) { if(uart_isr_mask(UART_1)) // 串口1接收中断 { uart4_rx_interrupt_handler(); } else // 串口1发送中断 { } } void uart2_isr (void) { if(uart_isr_mask(UART_2)) // 串口2接收中断 { uart_rx_interrupt_handler(); } else // 串口2发送中断 { } } void uart3_isr (void) { if(uart_isr_mask(UART_3)) // 串口3接收中断 { } else // 串口3发送中断 { } } void uart4_isr (void) { if(uart_isr_mask(UART_4)) // 串口4接收中断 { } else // 串口4发送中断 { } } // **************************** 外部中断函数 **************************** void gpio_0_exti_isr() // 外部 GPIO_0 中断服务函数 { } void gpio_1_exti_isr() // 外部 GPIO_1 中断服务函数 { if(exti_flag_get(P01_0)) // 示例P1_0端口外部中断判断 { } if(exti_flag_get(P01_1)) { } } void gpio_2_exti_isr() // 外部 GPIO_2 中断服务函数 { if(exti_flag_get(P02_0)) { } if(exti_flag_get(P02_4)) { } } void gpio_3_exti_isr() // 外部 GPIO_3 中断服务函数 { } void gpio_4_exti_isr() // 外部 GPIO_4 中断服务函数 { } void gpio_5_exti_isr() // 外部 GPIO_5 中断服务函数 { } void gpio_6_exti_isr() // 外部 GPIO_6 中断服务函数 { } void gpio_7_exti_isr() // 外部 GPIO_7 中断服务函数 { } void gpio_8_exti_isr() // 外部 GPIO_8 中断服务函数 { } void gpio_9_exti_isr() // 外部 GPIO_9 中断服务函数 { } void gpio_10_exti_isr() // 外部 GPIO_10 中断服务函数 { } void gpio_11_exti_isr() // 外部 GPIO_11 中断服务函数 { } void gpio_12_exti_isr() // 外部 GPIO_12 中断服务函数 { } void gpio_13_exti_isr() // 外部 GPIO_13 中断服务函数 { } void gpio_14_exti_isr() // 外部 GPIO_14 中断服务函数 { } void gpio_15_exti_isr() // 外部 GPIO_15 中断服务函数 { } void gpio_16_exti_isr() // 外部 GPIO_16 中断服务函数 { } void gpio_17_exti_isr() // 外部 GPIO_17 中断服务函数 { } void gpio_18_exti_isr() // 外部 GPIO_18 中断服务函数 { } void gpio_19_exti_isr() // 外部 GPIO_19 中断服务函数 { } void gpio_20_exti_isr() // 外部 GPIO_20 中断服务函数 { } void gpio_21_exti_isr() // 外部 GPIO_21 中断服务函数 { } void gpio_22_exti_isr() // 外部 GPIO_22 中断服务函数 { } void gpio_23_exti_isr() // 外部 GPIO_23 中断服务函数 { } // **************************** 外部中断函数 **************************** 我经过分析,并不存在再次进入的误触情况,但是我还是发现有已经退出转完状态,但是接着有有一段明显的转完导致我最终位置有点偏,请帮我分析控制逻辑中哪里出了问题,多给一些建议
最新发布
10-09
import redis import requests import time import json from datetime import datetime, timedelta import os import math import threading from concurrent.futures import ThreadPoolExecutor import pytz from queue import Queue from fastapi import FastAPI, HTTPException from pydantic import BaseModel from typing import Dict, List # FastAPI应用 app = FastAPI(title="京东评论爬虫API", description="多线程爬取京东评论数据并提供查询接口") # 数据存储 crawled_data: Dict[str, List[dict]] = {} data_lock = threading.Lock() # 配置部分 BASE_URL = "https://pjsj.jddj.com/jd/sku-comment/query-page" ACCOUNTS = [ {"name": "钟红军", "cookie_file": "cookie.json", "current_page": 1}, # {"name": "account2", "cookie_file": "cookie2.json", "current_page": 1} ] THREAD_POOL_SIZE = len(ACCOUNTS) task_queue = Queue() REDIS_HOST = 'localhost' REDIS_PORT = 6379 REDIS_DB = 0 PASSWORD = '123456' redis_client = redis.StrictRedis(host=REDIS_HOST, port=REDIS_PORT, db=REDIS_DB, password=PASSWORD) # 数据模型 class CommentItem(BaseModel): id: str content: str create_time: str score: int class CrawlResponse(BaseModel): status: str message: str data_count: int # 辅助函数 def load_cookies_from_json(cookie_file): """从json文件加载cookies""" if not os.path.exists(cookie_file): print(f"警告: cookie文件 {cookie_file} 不存在") return None try: with open(cookie_file, 'r', encoding='utf-8') as f: return json.load(f) except Exception as e: print(f"读取cookie文件 {cookie_file} 失败: {e}") return None # def save_crawled_data(account_name: str, data: dict): # """保存爬取数据""" # with data_lock: # if account_name not in crawled_data: # crawled_data[account_name] = [] # crawled_data[account_name].extend(data['data']['resultList']) # save_to_redis(crawled_data) def make_request(account): """发送请求""" with data_lock: page = account['current_page'] now_time = time.strftime('%Y-%m-%d', time.localtime()) params = { "pageNo": str(page), "pageSize": "100", # "storeId": "15506231", # 店铺ID "startTime": now_time + " 00:00:00", "endTime": now_time + " 23:59:59" } cookies = load_cookies_from_json(account['cookie_file']) headers = { "authority": "pjsj.jddj.com", "accept": "application/json, text/javascript, */*; q=0.01", "accept-language": "zh-CN,zh;q=0.9", # "cookie": "3AB9D23F7A4B3C9B=IR5JY5HVIONIPRVZ2XT6IADLJNT7YVYDN7KSOUASGPRJ7NAJBFGHWLVPMEZ2I7HO7ZXYPRPK2XOFRADO3VURDNIBOE; __jda=157302241.1748326760578484526793.1748326760.1748326760.1748326760.1; __jdv=157302241%7Cdirect%7C-%7Cnone%7C-%7C1748326760578; __jdc=157302241; mba_muid=1748326760578484526793; thor=D6CAE49174A1C2B1BFC448D24F0B356D54E1C3A1A62EF708482E83C31DB30F7A0D6E35AF8C74BE68709840C619A79DC59520F022F1C537DAA53D977DF761A73AF6D0083C726CFB395271DAF4D7C482A5302D1A77A17CC9F1F92A7E8185D119635AEEE05CAEC366757DA9A1C06725F830BA2A0C7714B045132D6DD372E3E517D3AEE9FACFD309A6117551CCEB6637A265; light_key=AASBKE7rOxgWQziEhC_QY6ya7oMtArydscb7k_M0HOxtksgRmje1Wh6GnZii5TXmpvFkJWd90SeBVGnpH3MQd0yRl-dW4Q; pin=Z%E4%BA%BA%E6%B0%91%E5%85%AC%E7%A4%BE%E8%80%81%E9%95%BF%E6%B2%99%E6%B9%98%E8%8F%9C; unick=rws31804m68239; lsp-store1.jd.local=3LXOEL6XD5JIX2ARP727WV7XV3ZJJBFMFQM4QPQK4H3WA2NN3LHO25Y5VAEJWZNLF36EPE6YY4JPPMMIB2L4FZ2RA4DC3OQPSKMMG66XKJFZ2ZYYEXN5AIFEQPR53P6LNPKVJFYG2NELNYAVTSBL4E4AOEJO6XA7ZMRDGFJN5BWH6LYPLWP5TYSTLFGS22D2QHJR7UY5QARLLLYGPVZE3ZSOVVVGWJGOHBIA4FKICSWUIXP23IOYXPXML3VQVF37FSJNEJT2P2VSI55JHJZ3KDXSDDW6OVYC77QPQ7MZ4KG54G65X6VYENKNHCEIMBE7ZVIFPMJ57IIVHYH5SFY7PNDXLTNWSBZRMWYMPBUMMXN7PZJO6475BIUZOPGMLVVRQIT4G54OHGJRQ3KKZCJZSNV57774F5ON4BJLKTBOH3OOMGVYLKSHTIARPJSBRTFPC7PUEGQWZW3YUSHGPF7V2T4TIAWASZJKTM7NJMA; user_email=Z%E4%BA%BA%E6%B0%91%E5%85%AC%E7%A4%BE%E8%80%81%E9%95%BF%E6%B2%99%E6%B9%98%E8%8F%9C; __jdb=157302241.3.1748326760578484526793|1.1748326760; 3AB9D23F7A4B3CSS=jdd03IR5JY5HVIONIPRVZ2XT6IADLJNT7YVYDN7KSOUASGPRJ7NAJBFGHWLVPMEZ2I7HO7ZXYPRPK2XOFRADO3VURDNIBOEAAAAMXCBR6FEAAAAAADIUPN47E6AWWHQX; josl-privilege1.jddj.com=3LXOEL6XD5JIX2ARP727WV7XV3ZJJBFMFQM4QPQK4H3WA2NN3LHO25Y5VAEJWZNLF36EPE6YY4JPPMMIB2L4FZ2RA4DC3OQPSKMMG66XKJFZ2ZYYEXN5AIFEQPR53P6LNPKVJFYG2NELNYAVTSBL4E4AOEJO6XA7ZMRDGFJN5BWH6LYPLWP5TYSTLFGS22D2QHJR7UY5QARLLLYGPVZE3ZSOVVVGWJGOHBIA4FPL4IDBM5RFMZT3TMHHZDAW273UDNJ6QCVCBDWVWMXLIQZE34ONYTW6OVYC77QPQ7MZ4KG54G65X6VYENKNHCEIMBE7ZVIFPMJ57IIVHYH5SFY7PNDXLTNWSBZRMWYMPBUMMXN7PZJO6475BIUZOPGMLVVRQIT4G54OHGJRQ3KKZCJZSNV57774F5ON4BJLKTBOH3OOMGVYLKSHTIARPJSBRTFPC7PUEGQWZW3YVENLP3724YREZAYCRBOXRPBOSII; josl-privilege1.jd.local=3LXOEL6XD5JIX2ARP727WV7XV3ZJJBFMFQM4QPQK4H3WA2NN3LHO25Y5VAEJWZNLF36EPE6YY4JPPMMIB2L4FZ2RA4DC3OQPSKMMG66XKJFZ2ZYYEXN5AIFEQPR53P6LNPKVJFYG2NELNYAVTSBL4E4AOEJO6XA7ZMRDGFJN5BWH6LYPLWP5TYSTLFGS22D2QHJR7UY5QARLLLYGPVZE3ZSOVVVGWJGOHBIA4FPL4IDBM5RFMZT3TMHHZDAW273UDNJ6QCVCBDWVWMXLIQZE34ONYTW6OVYC77QPQ7MZ4KG54G65X6VYENKNHCEIMBE7ZVIFPMJ57IIVHYH5SFY7PNDXLTNWSBZRMWYMPBUMMXN7PZJO6475BIUZOPGMLVVRQIT4G54OHGJRQ3KKZCJZSNV57774F5ON4BJLKTBOH3OOMGVYLKSHTIARPJSBRTFPC7PUEGQWZW3YVENLP3724YREZAYCRBOXRPBOSII; mba_sid=17483267605791887488231.1; flash=3_H47SrMyh5_73S8ThAeBvyL_lWo0CFt7RdspWOBxRRgQRi1yN5nLjFba5-pkiQMOvtspoou3_yPDtW-t98169gqz6ZbTb6eU7Z9sYqp1zwI3zpENNrIPiyWxu_yKIkieYvjZvqYSn9FQcGPVL5j8OR9Lr4n8HWnZ5RUvFbdaQcsAzkV**; __jd_ref_cls=takeoutHome_Menu; shop.o2o.jd.com1=3LXOEL6XD5JIX2ARP727WV7XV3ZJJBFMFQM4QPQK4H3WA2NN3LHO25Y5VAEJWZNLF36EPE6YY4JPPMMIB2L4FZ2RA4DC3OQPSKMMG66XKJFZ2ZYYEXN5AIFEQPR53P6LNPKVJFYG2NELNYAVTSBL4E4AOEJO6XA7ZMRDGFJN5BWH6LYPLWP5TYSTLFGS22D2QHJR7UY5QARLLLYGPVZE3ZSOVVVGWJGOHBIA4FKICSWUIXP23IOYXPXML3VQVF37FSJNEJT2P2VSI55JHJZ3KDXSDDW6OVYC77QPQ7MZ4KG54G65X6V6JNKWU65W4AHPTE6S5COCIPJISHSUR6NLDORGUPSNJKM2ZNQMFOU2SFQ6F6WUNO5GXDJSVUELLBJT; lsp-store1.jddj.com=3LXOEL6XD5JIX2ARP727WV7XV3ZJJBFMFQM4QPQK4H3WA2NN3LHO25Y5VAEJWZNLF36EPE6YY4JPPMMIB2L4FZ2RA4DC3OQPSKMMG66XKJFZ2ZYYEXN5AIFEQPR53P6LNPKVJFYG2NELNYAVTSBL4E4AOEJO6XA7ZMRDGFJN5BWH6LYPLWP5TYSTLFGS22D2QHJR7UY5QARLLLYGPVZE3ZSOVVVGWJGOHBIA4FKICSWUIXP23IOYXPXML3VQVF37FSJNEJT2P2VSI55JHJZ3KDXSDDW6OVYC77QPQ7MZ4KG54G65X6V6JNKWU65W4AHPTE6S5COCIPJISHSUR6NLDORGUPSNJKM2ZNQMFOU2SFQ6F6WUNO5GXDJSVUELLBJT; user_key=2474644; vender_id=1512295; vender_name=\\u4EBA\\u6C11\\u516C\\u793E\\u00B7\\u8001\\u957F\\u6C99\\u6E58\\u83DC", "referer": "https://pjsj.jddj.com/resource/web/html/jdComment.html", "sec-ch-ua": "\"Chromium\";v=\"106\", \"Microsoft Edge\";v=\"106\", \"Not;A=Brand\";v=\"99\"", "sec-ch-ua-mobile": "?0", "sec-ch-ua-platform": "\"Windows\"", "sec-fetch-dest": "empty", "sec-fetch-mode": "cors", "sec-fetch-site": "same-origin", "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/106.0.0.0 Safari/537.36 Edg/106.0.1370.47", "x-requested-with": "XMLHttpRequest" } try: print(f"账号 {account['name']} 正在请求第 {page} 页...") response = requests.get( BASE_URL, params=params, headers=headers, cookies=cookies, timeout=10 ) response.raise_for_status() data = response.json() # save_crawled_data(account['name'], data) # print(data) return account, data except Exception as e: print(f"账号 {account['name']} 请求失败: {e}") return account, None def process_data(account, data): """处理数据""" value = data['data']['totalCount'] print(f"账号 {account['name']} 当前有: {value}条数据") page = math.ceil(value / 100) page = page if page >= 0 else 0 print(f"账号 {account['name']} 需要翻: {page}页") if value > 100: with data_lock: account['current_page'] += 1 if account['current_page'] <= page: print(f"账号 {account['name']} 获取第{account['current_page']}页的数据") return False # 需要重新请求 return True # 处理完成 def save_to_redis(data): """将数据保存到redis""" redis_key = f"crawler_data:{data['guid']}" try: redis_client.set(redis_key, json.dumps(data)) print(f"数据已保存到redis: {redis_key}") except Exception as e: print(f"保存到redis失败: {e}") def data_analysis(data): """数据分析""" data_list = data['data']['resultList'] if not data_list: print('暂时没有评论数据') return data_list def worker(): """工作线程函数""" while True: account = task_queue.get() try: account, data = make_request(account) if data is not None: data_list = data_analysis(data) # 单次数据存储redis for datas in data_list: save_to_redis(datas) if data is not None and not process_data(account, data): task_queue.put(account) # 需要重新请求 except Exception as e: print(f"账号 {account['name']} 处理异常: {e}") finally: task_queue.task_done() def is_in_special_period(): """判断是否在特殊时段""" tz = pytz.timezone('Asia/Shanghai') hour = datetime.now(tz).hour return (11 <= hour < 14) or (17 <= hour < 20) def calculate_next_run(): """计算下次运行时间""" now = datetime.now() if is_in_special_period(): next_run = (now + timedelta(minutes=30)).replace(second=0, microsecond=0) if now.minute >= 30: next_run = next_run.replace(minute=0) + timedelta(hours=1) else: next_run = (now + timedelta(hours=1)).replace(minute=0, second=0, microsecond=0) return next_run def wait_until_next_run(next_run): """等待到下次运行时间""" wait_seconds = (next_run - datetime.now()).total_seconds() if wait_seconds > 0: print(f"等待 {wait_seconds:.1f} 秒直到下次运行...") time.sleep(wait_seconds) def start_scheduler(): """启动调度器""" with ThreadPoolExecutor(max_workers=THREAD_POOL_SIZE) as executor: for _ in range(THREAD_POOL_SIZE): executor.submit(worker) while True: next_run = calculate_next_run() print(f"\n开始新一轮请求,时间: {datetime.now()}") for account in ACCOUNTS: task_queue.put(account.copy()) task_queue.join() wait_until_next_run(next_run) # API端点 @app.get("/comments/{account_name}", response_model=List[CommentItem]) async def get_comments(account_name: str, limit: int = 10): """获取指定账号的评论数据""" with data_lock: if account_name not in crawled_data: raise HTTPException(status_code=404, detail="Account not found") return crawled_data[account_name][:limit] @app.get("/start_crawl", response_model=CrawlResponse) async def start_crawl(): """手动触发爬取任务""" for account in ACCOUNTS: task_queue.put(account.copy()) return { "status": "success", "message": "Crawl tasks added to queue", "data_count": sum(len(v) for v in crawled_data.values()) } @app.get("/stats") async def get_stats(): """获取爬取统计信息""" with data_lock: return { "accounts": [a['name'] for a in ACCOUNTS], "data_counts": {k: len(v) for k, v in crawled_data.items()}, "last_updated": datetime.now().isoformat() } # 启动爬虫线程 @app.on_event("startup") async def startup_event(): """应用启动时初始化""" # 检查账号配置 if not ACCOUNTS: raise RuntimeError("未配置任何账号!") for account in ACCOUNTS: if not os.path.exists(account['cookie_file']): print(f"警告: 账号 {account['name']} 的Cookie文件 {account['cookie_file']} 不存在") print(f"启动多线程爬虫,线程数: {THREAD_POOL_SIZE}") threading.Thread(target=start_scheduler, daemon=True).start() if __name__ == "__main__": import uvicorn uvicorn.run(app, host="0.0.0.0", port=8000) 以上代码,不改变代码逻辑和采集频率的前提下,对代码结构进行优化,进行模块化设计,同时具备良好的阅读性、扩展性
05-30
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值