[{"data":1,"prerenderedAt":2288},["ShallowReactive",2],{"posts":3},[4,642,1887,1927,2040,2068,2155,2212],{"id":5,"title":6,"body":7,"date":634,"description":635,"extension":636,"meta":637,"navigation":56,"path":638,"seo":639,"stem":640,"__hash__":641},"blogs\u002Fblogs\u002FFastAPI 实战总结 & 坑点指南.md","FastAPI 实战总结 & 坑点指南",{"type":8,"value":9,"toc":627},"minimark",[10,15,28,110,133,159,163,170,261,279,289,293,375,379,393,433,490,499,511,564,593,597,613,616,623],[11,12,14],"h3",{"id":13},"一apirouter-的正确姿势","一、APIRouter 的正确姿势",[16,17,18,19,23,24,27],"p",{},"项目大了别把所有路由堆在 ",[20,21,22],"code",{},"main.py","，用 ",[20,25,26],{},"APIRouter"," 分模块：",[29,30,35],"pre",{"className":31,"code":32,"language":33,"meta":34,"style":34},"language-python shiki shiki-themes github-light github-dark","# routers\u002Fuser.py\nfrom fastapi import APIRouter\n\nrouter = APIRouter(prefix=\"\u002Fusers\", tags=[\"users\"])  # prefix 统一前缀\n\n@router.get(\"\u002F{user_id}\")   # 实际路径 \u002Fusers\u002F{user_id}\ndef get_user(user_id: int):\n    return {\"id\": user_id}\n\n# main.py\nfrom routers import user\napp.include_router(user.router)\n","python","",[20,36,37,45,51,58,64,69,75,81,87,92,98,104],{"__ignoreMap":34},[38,39,42],"span",{"class":40,"line":41},"line",1,[38,43,44],{},"# routers\u002Fuser.py\n",[38,46,48],{"class":40,"line":47},2,[38,49,50],{},"from fastapi import APIRouter\n",[38,52,54],{"class":40,"line":53},3,[38,55,57],{"emptyLinePlaceholder":56},true,"\n",[38,59,61],{"class":40,"line":60},4,[38,62,63],{},"router = APIRouter(prefix=\"\u002Fusers\", tags=[\"users\"])  # prefix 统一前缀\n",[38,65,67],{"class":40,"line":66},5,[38,68,57],{"emptyLinePlaceholder":56},[38,70,72],{"class":40,"line":71},6,[38,73,74],{},"@router.get(\"\u002F{user_id}\")   # 实际路径 \u002Fusers\u002F{user_id}\n",[38,76,78],{"class":40,"line":77},7,[38,79,80],{},"def get_user(user_id: int):\n",[38,82,84],{"class":40,"line":83},8,[38,85,86],{},"    return {\"id\": user_id}\n",[38,88,90],{"class":40,"line":89},9,[38,91,57],{"emptyLinePlaceholder":56},[38,93,95],{"class":40,"line":94},10,[38,96,97],{},"# main.py\n",[38,99,101],{"class":40,"line":100},11,[38,102,103],{},"from routers import user\n",[38,105,107],{"class":40,"line":106},12,[38,108,109],{},"app.include_router(user.router)\n",[16,111,112,116,117,120,121,124,125,128,129,132],{},[113,114,115],"strong",{},"坑点 1","：",[20,118,119],{},"prefix=\"\u002Fusers\""," 后，路由里写 ",[20,122,123],{},"\"\u002F{user_id}\""," 而不是 ",[20,126,127],{},"\"\u002Fusers\u002F{user_id}\"","，否则路径变成 ",[20,130,131],{},"\u002Fusers\u002Fusers\u002Fxxx"," 喵！",[16,134,135,138,139,142,143,146,147,150,151,154,155,158],{},[113,136,137],{},"坑点 2","：路由注册顺序很重要！",[20,140,141],{},"\u002Fusers\u002Fme"," 要写在 ",[20,144,145],{},"\u002Fusers\u002F{user_id}"," ",[113,148,149],{},"前面","，否则 ",[20,152,153],{},"me"," 会被当成 ",[20,156,157],{},"user_id"," 匹配走（还会报类型转换错误）。",[11,160,162],{"id":161},"二参数到底从哪来最容易混","二、参数到底从哪来（最容易混）",[16,164,165,166,169],{},"FastAPI 按",[113,167,168],{},"声明方式","自动判断参数来源：",[29,171,173],{"className":31,"code":172,"language":33,"meta":34,"style":34},"from fastapi import Query, Path, Body\nfrom pydantic import BaseModel\n\nclass Item(BaseModel):\n    name: str\n    price: float\n\n@app.get(\"\u002Fitems\u002F{item_id}\")\ndef read_item(\n    item_id: int = Path(...),        # 路径参数 \u002Fitems\u002F3\n    q: str | None = Query(None),     # 查询参数 ?q=abc\n):\n    ...\n\n@app.post(\"\u002Fitems\")\ndef create_item(item: Item):          # Pydantic 模型 → 自动从 body 解析\n    ...\n",[20,174,175,180,185,189,194,199,204,208,213,218,223,228,233,239,244,250,256],{"__ignoreMap":34},[38,176,177],{"class":40,"line":41},[38,178,179],{},"from fastapi import Query, Path, Body\n",[38,181,182],{"class":40,"line":47},[38,183,184],{},"from pydantic import BaseModel\n",[38,186,187],{"class":40,"line":53},[38,188,57],{"emptyLinePlaceholder":56},[38,190,191],{"class":40,"line":60},[38,192,193],{},"class Item(BaseModel):\n",[38,195,196],{"class":40,"line":66},[38,197,198],{},"    name: str\n",[38,200,201],{"class":40,"line":71},[38,202,203],{},"    price: float\n",[38,205,206],{"class":40,"line":77},[38,207,57],{"emptyLinePlaceholder":56},[38,209,210],{"class":40,"line":83},[38,211,212],{},"@app.get(\"\u002Fitems\u002F{item_id}\")\n",[38,214,215],{"class":40,"line":89},[38,216,217],{},"def read_item(\n",[38,219,220],{"class":40,"line":94},[38,221,222],{},"    item_id: int = Path(...),        # 路径参数 \u002Fitems\u002F3\n",[38,224,225],{"class":40,"line":100},[38,226,227],{},"    q: str | None = Query(None),     # 查询参数 ?q=abc\n",[38,229,230],{"class":40,"line":106},[38,231,232],{},"):\n",[38,234,236],{"class":40,"line":235},13,[38,237,238],{},"    ...\n",[38,240,242],{"class":40,"line":241},14,[38,243,57],{"emptyLinePlaceholder":56},[38,245,247],{"class":40,"line":246},15,[38,248,249],{},"@app.post(\"\u002Fitems\")\n",[38,251,253],{"class":40,"line":252},16,[38,254,255],{},"def create_item(item: Item):          # Pydantic 模型 → 自动从 body 解析\n",[38,257,259],{"class":40,"line":258},17,[38,260,238],{},[16,262,263,266,267,270,271,274,275,278],{},[113,264,265],{},"坑点 3","：POST 里想同时收 body + query 参数，直接混着声明就行，但",[113,268,269],{},"简单类型默认是 query，模型类型默认是 body","。如果 POST 里写个 ",[20,272,273],{},"name: str"," 想从 body 收，要用 ",[20,276,277],{},"Body(...)"," 显式声明，否则前端传 body 你收不到喵！",[16,280,281,284,285,288],{},[113,282,283],{},"坑点 4","：多个 body 参数要包一层模型，或者用 ",[20,286,287],{},"Body(embed=True)","，不然 FastAPI 会把它们拆散。",[11,290,292],{"id":291},"三请求方法选择rest-习惯","三、请求方法选择（REST 习惯）",[294,295,296,312],"table",{},[297,298,299],"thead",{},[300,301,302,306,309],"tr",{},[303,304,305],"th",{},"方法",[303,307,308],{},"场景",[303,310,311],{},"前端 fetch",[313,314,315,327,341,352,362],"tbody",{},[300,316,317,321,324],{},[318,319,320],"td",{},"GET",[318,322,323],{},"查询、获取",[318,325,326],{},"默认就是 GET",[300,328,329,332,335],{},[318,330,331],{},"POST",[318,333,334],{},"创建、提交、登录",[318,336,337,340],{},[20,338,339],{},"method: 'POST'"," + body",[300,342,343,346,349],{},[318,344,345],{},"PUT",[318,347,348],{},"整体更新",[318,350,351],{},"同上",[300,353,354,357,360],{},[318,355,356],{},"PATCH",[318,358,359],{},"部分更新",[318,361,351],{},[300,363,364,367,370],{},[318,365,366],{},"DELETE",[318,368,369],{},"删除",[318,371,372],{},[20,373,374],{},"method: 'DELETE'",[11,376,378],{"id":377},"四高频坑点清单","四、高频坑点清单",[380,381,382],"ol",{},[383,384,385,388,389,392],"li",{},[113,386,387],{},"CORS 跨域","：前端 fetch 报 ",[20,390,391],{},"CORS error"," 是新手第一坑，后端必须加：",[29,394,396],{"className":31,"code":395,"language":33,"meta":34,"style":34},"from fastapi.middleware.cors import CORSMiddleware\napp.add_middleware(\n    CORSMiddleware,\n    allow_origins=[\"http:\u002F\u002Flocalhost:5173\"],  # 前端地址，别用 * 配 credentials\n    allow_methods=[\"*\"],\n    allow_headers=[\"*\"],\n)\n",[20,397,398,403,408,413,418,423,428],{"__ignoreMap":34},[38,399,400],{"class":40,"line":41},[38,401,402],{},"from fastapi.middleware.cors import CORSMiddleware\n",[38,404,405],{"class":40,"line":47},[38,406,407],{},"app.add_middleware(\n",[38,409,410],{"class":40,"line":53},[38,411,412],{},"    CORSMiddleware,\n",[38,414,415],{"class":40,"line":60},[38,416,417],{},"    allow_origins=[\"http:\u002F\u002Flocalhost:5173\"],  # 前端地址，别用 * 配 credentials\n",[38,419,420],{"class":40,"line":66},[38,421,422],{},"    allow_methods=[\"*\"],\n",[38,424,425],{"class":40,"line":71},[38,426,427],{},"    allow_headers=[\"*\"],\n",[38,429,430],{"class":40,"line":77},[38,431,432],{},")\n",[380,434,435,444,450,480],{"start":47},[383,436,437,116,440,443],{},[113,438,439],{},"前端 POST 忘了加 header",[20,441,442],{},"headers: {'Content-Type': 'application\u002Fjson'}"," 不加的话，FastAPI 解析 body 会 422。",[383,445,446,449],{},[113,447,448],{},"422 错误","：FastAPI 参数校验失败默认返回 422（不是 400），看到 422 就去查字段类型\u002F必填项。",[383,451,452,455,456,459,460,463,464,467,468,471,472,475,476,479],{},[113,453,454],{},"async 混用","：路由用 ",[20,457,458],{},"async def"," 时，里面别调用",[113,461,462],{},"同步阻塞","的库（如 ",[20,465,466],{},"requests","、",[20,469,470],{},"time.sleep","），会卡死整个事件循环。要么用 ",[20,473,474],{},"httpx","，要么改成普通 ",[20,477,478],{},"def","（FastAPI 会放线程池跑）。",[383,481,482,485,486,489],{},[113,483,484],{},"返回 datetime\u002FDecimal 报错","：用 Pydantic 的 ",[20,487,488],{},"response_model"," 声明返回模型，FastAPI 会自动序列化：",[29,491,493],{"className":31,"code":492,"language":33,"meta":34,"style":34},"@app.get(\"\u002Fitems\", response_model=list[ItemOut])\n",[20,494,495],{"__ignoreMap":34},[38,496,497],{"class":40,"line":41},[38,498,492],{},[380,500,501],{"start":71},[383,502,503,506,507,510],{},[113,504,505],{},"依赖注入 Depends","：数据库会话、鉴权统一用 ",[20,508,509],{},"Depends","，别在每个路由里手写：",[29,512,514],{"className":31,"code":513,"language":33,"meta":34,"style":34},"def get_db():\n    db = SessionLocal()\n    try:\n        yield db\n    finally:\n        db.close()\n\n@app.get(\"\u002Fusers\")\ndef list_users(db: Session = Depends(get_db)):\n    ...\n",[20,515,516,521,526,531,536,541,546,550,555,560],{"__ignoreMap":34},[38,517,518],{"class":40,"line":41},[38,519,520],{},"def get_db():\n",[38,522,523],{"class":40,"line":47},[38,524,525],{},"    db = SessionLocal()\n",[38,527,528],{"class":40,"line":53},[38,529,530],{},"    try:\n",[38,532,533],{"class":40,"line":60},[38,534,535],{},"        yield db\n",[38,537,538],{"class":40,"line":66},[38,539,540],{},"    finally:\n",[38,542,543],{"class":40,"line":71},[38,544,545],{},"        db.close()\n",[38,547,548],{"class":40,"line":77},[38,549,57],{"emptyLinePlaceholder":56},[38,551,552],{"class":40,"line":83},[38,553,554],{},"@app.get(\"\u002Fusers\")\n",[38,556,557],{"class":40,"line":89},[38,558,559],{},"def list_users(db: Session = Depends(get_db)):\n",[38,561,562],{"class":40,"line":94},[38,563,238],{},[380,565,566,580],{"start":77},[383,567,568,571,572,575,576,579],{},[113,569,570],{},"文件上传","：用 ",[20,573,574],{},"UploadFile = File(...)","，且前端要用 ",[20,577,578],{},"FormData","，不能发 JSON。",[383,581,582,116,585,588,589,592],{},[113,583,584],{},"路径末尾斜杠",[20,586,587],{},"\u002Fusers"," 和 ",[20,590,591],{},"\u002Fusers\u002F"," 是两个路由，FastAPI 默认会 307 重定向，前端 fetch 时重定向可能丢 POST body，建议统一不加尾斜杠。",[11,594,596],{"id":595},"五调试神器","五、调试神器",[598,599,600,607],"ul",{},[383,601,602,603,606],{},"自带文档：",[20,604,605],{},"http:\u002F\u002Flocalhost:8000\u002Fdocs","（Swagger UI），可以直接在页面里测接口，比前端 fetch 调试快得多喵！",[383,608,609,610],{},"备选：",[20,611,612],{},"\u002Fredoc",[614,615],"hr",{},[16,617,618,619,622],{},"总结一句话：",[113,620,621],{},"参数来源看声明类型、422 查字段、CORS 先配好、路由顺序注意、async 里别阻塞","喵~ 有具体代码问题也可以贴给我看看！🐾",[624,625,626],"style",{},"html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":34,"searchDepth":47,"depth":47,"links":628},[629,630,631,632,633],{"id":13,"depth":47,"text":14},{"id":161,"depth":47,"text":162},{"id":291,"depth":47,"text":292},{"id":377,"depth":47,"text":378},{"id":595,"depth":47,"text":596},"2026-09-30","项目大了别把所有路由堆在 main.py，用 APIRouter 分模块：","md",{},"\u002Fblogs\u002Ffastapi-实战总结-and-坑点指南",{"title":6,"description":34},"blogs\u002FFastAPI 实战总结 & 坑点指南","1_a9XExhJmbIA_DWqr5A7gxG5jwuMJuIsmPc71mROmU",{"id":643,"title":644,"body":645,"date":634,"description":1881,"extension":636,"meta":1882,"navigation":56,"path":1883,"seo":1884,"stem":1885,"__hash__":1886},"blogs\u002Fblogs\u002F关于ORBBEC Astra 调试了半天的这件事\u002F关于ORBBEC Astra 调试了半天的这件事.md","关于我用wsl调试了 ORBBEC Astra 半天的这件事",{"type":8,"value":646,"toc":1862},[647,650,661,667,673,679,686,689,693,698,706,709,712,715,717,721,726,729,734,745,748,754,758,761,766,866,871,966,971,996,1006,1031,1034,1036,1040,1047,1050,1059,1061,1065,1074,1080,1094,1098,1105,1115,1121,1135,1149,1163,1167,1170,1175,1210,1217,1222,1285,1300,1305,1345,1348,1350,1354,1371,1375,1378,1594,1600,1724,1726,1730,1740,1794,1808,1835,1838,1841,1848,1851,1854,1859],[16,648,649],{},"1.踩的第一个坑，也不算坑吧，就是先直接安装orbbec sdk, github上我看limited maintannce, 还不信，压根什么都不行。所以说，需要先根据相机的型号选择正确的sdk。",[16,651,652,653,658],{},"2.第二个就是得安装官方的sensordriver的驱动，然后需要安装usbpid，右键计算机图标，点击\"管理\"里面，找到新插入的摄像机，然后识别不出来的，就应该在这里面，右键点击更新驱动，然后就应该能显示了，显示不了的再重启一下\n",[654,655],"img",{"alt":656,"src":657},"alt text","\u002Fimages\u002Fblogs\u002F%E5%85%B3%E4%BA%8EORBBEC%20Astra%20%E8%B0%83%E8%AF%95%E4%BA%86%E5%8D%8A%E5%A4%A9%E7%9A%84%E8%BF%99%E4%BB%B6%E4%BA%8B\u002Fimage-5.png",[654,659],{"alt":656,"src":660},"\u002Fimages\u002Fblogs\u002F%E5%85%B3%E4%BA%8EORBBEC%20Astra%20%E8%B0%83%E8%AF%95%E4%BA%86%E5%8D%8A%E5%A4%A9%E7%9A%84%E8%BF%99%E4%BB%B6%E4%BA%8B\u002Fimage-4.png",[16,662,663,666],{},[654,664],{"alt":656,"src":665},"\u002Fimages\u002Fblogs\u002F%E5%85%B3%E4%BA%8EORBBEC%20Astra%20%E8%B0%83%E8%AF%95%E4%BA%86%E5%8D%8A%E5%A4%A9%E7%9A%84%E8%BF%99%E4%BB%B6%E4%BA%8B\u002Fimage-3.png","\n3.就是装好wsl后，建议配置一下python的虚拟环境，装一些依赖，nano里面可以添加配置，这样每次一启动就配置好环境了，具体可以问AI。\n然后这些配置基本上都是我和AI一起解决的，然后也顺便让AI来总结一下：",[16,668,669,670],{},"“叠”:\n",[654,671],{"alt":656,"src":672},"\u002Fimages\u002Fblogs\u002F%E5%85%B3%E4%BA%8EORBBEC%20Astra%20%E8%B0%83%E8%AF%95%E4%BA%86%E5%8D%8A%E5%A4%A9%E7%9A%84%E8%BF%99%E4%BB%B6%E4%BA%8B\u002Fimage-1.png",[16,674,675,678],{},[654,676],{"alt":656,"src":677},"\u002Fimages\u002Fblogs\u002F%E5%85%B3%E4%BA%8EORBBEC%20Astra%20%E8%B0%83%E8%AF%95%E4%BA%86%E5%8D%8A%E5%A4%A9%E7%9A%84%E8%BF%99%E4%BB%B6%E4%BA%8B\u002Fimage-2.png","\n然后如果运行完ros2 launch openni2_camera camera_only.launch.py，开启另外一个终端窗口的话，运行ros2 topic list 应该会显示上面这张图片的样子",[16,680,681,682],{},"对了，每次启动后需要检查一下usbipd list,看看有没有连上，如果是shared的话，需要用usbipd attach --wsl --busid ",[683,684,685],"your-busid",{},"\n然后进入Ubuntu后，运行lsusb应该能看见设备。",[16,687,688],{},"我和ai共同解决了以下问题：\n库依赖 (libpng12)\n设备权限 (udev 规则) 手动将下载的udev规则放入wsl的虚拟环境中，然后重启\n库和驱动的安装路径问题 (OPENNI2_INCLUDE_PATH, OPENNI2_REDIST_PATH, OPENNI2_DRIVER_PATH)\n环境变量 (OPENNI2_DRIVERS_PATH) export\n库版本冲突 (ABI不兼容) 反复rm 和 cp\n从源码编译来解决冲突 co build",[11,690,692],{"id":691},"接下来让ai来发挥","接下来让AI来发挥:",[694,695,697],"h2",{"id":696},"从零到英雄在wsl-2上为ros-2配置orbbec摄像头的终极避坑指南","“从零到英雄”：在WSL 2上为ROS 2配置Orbbec摄像头的终极避坑指南",[699,700,701],"blockquote",{},[16,702,703],{},[113,704,705],{},"副标题：一个关于我如何从安装Ubuntu开始，误入歧途，并最终驯服这匹“野马”的完整实录",[16,707,708],{},"大家好，我是Frank。如果你正在读这篇文章，那么你很可能也踏上了这条充满挑战但回报丰厚的道路：在Windows上通过WSL 2，让一个Orbbec深度摄像头在ROS 2中欢快地歌唱。",[16,710,711],{},"我原以为这会是一段轻松的旅程，但事实证明，它是一场融合了Linux系统管理、驱动调试和ROS编译的“全能铁人三项”。",[16,713,714],{},"这篇文章，就是我这段旅程的完整记录。我将从零开始，包括安装Ubuntu和ROS 2，记录我最初的错误尝试，并最终展示那条唯一通往成功的、铺满了代码和血泪的道路。希望这份手把手的教程，能让你在配置的道路上，少走一些我走过的弯路。",[614,716],{},[11,718,720],{"id":719},"第零章创世纪-从零搭建开发环境","第零章：创世纪 —— 从零搭建开发环境",[722,723,725],"h4",{"id":724},"_01-安装wsl-2和ubuntu","0.1 安装WSL 2和Ubuntu",[16,727,728],{},"如果你连WSL都还没有，别担心，现在安装它非常简单。",[16,730,731],{},[113,732,733],{},"1. 在Windows的PowerShell（以管理员身份运行）中，一键安装：",[29,735,739],{"className":736,"code":737,"language":738,"meta":34,"style":34},"language-powershell shiki shiki-themes github-light github-dark","wsl --install\n","powershell",[20,740,741],{"__ignoreMap":34},[38,742,743],{"class":40,"line":41},[38,744,737],{},[16,746,747],{},"这条命令会自动帮你开启所需的功能，下载并安装最新版的Ubuntu。安装完成后，按提示重启电脑。",[16,749,750,753],{},[113,751,752],{},"2. 初始化Ubuntu：","\n重启后，Ubuntu会自动启动，并要求你设置一个用户名和密码。请牢记它们。",[722,755,757],{"id":756},"_02-安装ros-2-jazzy-jubilee","0.2 安装ROS 2 Jazzy Jubilee",[16,759,760],{},"现在，我们进入了WSL的Ubuntu终端，开始安装ROS 2。",[16,762,763],{},[113,764,765],{},"1. 设置UTF-8编码和软件源：",[29,767,771],{"className":768,"code":769,"language":770,"meta":34,"style":34},"language-bash shiki shiki-themes github-light github-dark","sudo apt update && sudo apt install locales\nsudo locale-gen en_US en_US.UTF-8\nsudo update-locale LC_ALL=en_US.UTF-8 LANG=en_US.UTF-8\nexport LANG=en_US.UTF-8\n\nsudo apt install software-properties-common\nsudo add-apt-repository universe\n","bash",[20,772,773,800,813,826,841,845,856],{"__ignoreMap":34},[38,774,775,779,783,786,790,792,794,797],{"class":40,"line":41},[38,776,778],{"class":777},"sScJk","sudo",[38,780,782],{"class":781},"sZZnC"," apt",[38,784,785],{"class":781}," update",[38,787,789],{"class":788},"sVt8B"," && ",[38,791,778],{"class":777},[38,793,782],{"class":781},[38,795,796],{"class":781}," install",[38,798,799],{"class":781}," locales\n",[38,801,802,804,807,810],{"class":40,"line":47},[38,803,778],{"class":777},[38,805,806],{"class":781}," locale-gen",[38,808,809],{"class":781}," en_US",[38,811,812],{"class":781}," en_US.UTF-8\n",[38,814,815,817,820,823],{"class":40,"line":53},[38,816,778],{"class":777},[38,818,819],{"class":781}," update-locale",[38,821,822],{"class":781}," LC_ALL=en_US.UTF-8",[38,824,825],{"class":781}," LANG=en_US.UTF-8\n",[38,827,828,832,835,838],{"class":40,"line":60},[38,829,831],{"class":830},"szBVR","export",[38,833,834],{"class":788}," LANG",[38,836,837],{"class":830},"=",[38,839,840],{"class":788},"en_US.UTF-8\n",[38,842,843],{"class":40,"line":66},[38,844,57],{"emptyLinePlaceholder":56},[38,846,847,849,851,853],{"class":40,"line":71},[38,848,778],{"class":777},[38,850,782],{"class":781},[38,852,796],{"class":781},[38,854,855],{"class":781}," software-properties-common\n",[38,857,858,860,863],{"class":40,"line":77},[38,859,778],{"class":777},[38,861,862],{"class":781}," add-apt-repository",[38,864,865],{"class":781}," universe\n",[16,867,868],{},[113,869,870],{},"2. 添加ROS 2的密钥和仓库地址：",[29,872,874],{"className":768,"code":873,"language":770,"meta":34,"style":34},"sudo apt update && sudo apt install curl -y\nsudo curl -sSL https:\u002F\u002Fraw.githubusercontent.com\u002Fros\u002Frosdistro\u002Fmaster\u002Fros.key -o \u002Fusr\u002Fshare\u002Fkeyrings\u002Fros-archive-keyring.gpg\necho \"deb [arch=$(dpkg --print-architecture) signed-by=\u002Fusr\u002Fshare\u002Fkeyrings\u002Fros-archive-keyring.gpg] http:\u002F\u002Fpackages.ros.org\u002Fros2\u002Fubuntu $(. \u002Fetc\u002Fos-release && echo $UBUNTU_CODENAME) main\" | sudo tee \u002Fetc\u002Fapt\u002Fsources.list.d\u002Fros2.list > \u002Fdev\u002Fnull\n",[20,875,876,899,917],{"__ignoreMap":34},[38,877,878,880,882,884,886,888,890,892,895],{"class":40,"line":41},[38,879,778],{"class":777},[38,881,782],{"class":781},[38,883,785],{"class":781},[38,885,789],{"class":788},[38,887,778],{"class":777},[38,889,782],{"class":781},[38,891,796],{"class":781},[38,893,894],{"class":781}," curl",[38,896,898],{"class":897},"sj4cs"," -y\n",[38,900,901,903,905,908,911,914],{"class":40,"line":47},[38,902,778],{"class":777},[38,904,894],{"class":781},[38,906,907],{"class":897}," -sSL",[38,909,910],{"class":781}," https:\u002F\u002Fraw.githubusercontent.com\u002Fros\u002Frosdistro\u002Fmaster\u002Fros.key",[38,912,913],{"class":897}," -o",[38,915,916],{"class":781}," \u002Fusr\u002Fshare\u002Fkeyrings\u002Fros-archive-keyring.gpg\n",[38,918,919,922,925,928,931,934,937,940,942,945,948,951,954,957,960,963],{"class":40,"line":53},[38,920,921],{"class":897},"echo",[38,923,924],{"class":781}," \"deb [arch=$(",[38,926,927],{"class":777},"dpkg",[38,929,930],{"class":897}," --print-architecture",[38,932,933],{"class":781},") signed-by=\u002Fusr\u002Fshare\u002Fkeyrings\u002Fros-archive-keyring.gpg] http:\u002F\u002Fpackages.ros.org\u002Fros2\u002Fubuntu $(",[38,935,936],{"class":897},".",[38,938,939],{"class":781}," \u002Fetc\u002Fos-release && ",[38,941,921],{"class":897},[38,943,944],{"class":788}," $UBUNTU_CODENAME",[38,946,947],{"class":781},") main\"",[38,949,950],{"class":830}," |",[38,952,953],{"class":777}," sudo",[38,955,956],{"class":781}," tee",[38,958,959],{"class":781}," \u002Fetc\u002Fapt\u002Fsources.list.d\u002Fros2.list",[38,961,962],{"class":830}," >",[38,964,965],{"class":781}," \u002Fdev\u002Fnull\n",[16,967,968],{},[113,969,970],{},"3. 安装ROS 2桌面完整版：",[29,972,974],{"className":768,"code":973,"language":770,"meta":34,"style":34},"sudo apt update\nsudo apt install ros-jazzy-desktop\n",[20,975,976,985],{"__ignoreMap":34},[38,977,978,980,982],{"class":40,"line":41},[38,979,778],{"class":777},[38,981,782],{"class":781},[38,983,984],{"class":781}," update\n",[38,986,987,989,991,993],{"class":40,"line":47},[38,988,778],{"class":777},[38,990,782],{"class":781},[38,992,796],{"class":781},[38,994,995],{"class":781}," ros-jazzy-desktop\n",[16,997,998,1001,1002,1005],{},[113,999,1000],{},"4. 设置环境：","\n将ROS的环境设置命令添加到你的",[20,1003,1004],{},".bashrc","文件中，这样每次打开新终端都会自动加载。",[29,1007,1009],{"className":768,"code":1008,"language":770,"meta":34,"style":34},"echo \"source \u002Fopt\u002Fros\u002Fjazzy\u002Fsetup.bash\" >> ~\u002F.bashrc\nsource ~\u002F.bashrc\n",[20,1010,1011,1024],{"__ignoreMap":34},[38,1012,1013,1015,1018,1021],{"class":40,"line":41},[38,1014,921],{"class":897},[38,1016,1017],{"class":781}," \"source \u002Fopt\u002Fros\u002Fjazzy\u002Fsetup.bash\"",[38,1019,1020],{"class":830}," >>",[38,1022,1023],{"class":781}," ~\u002F.bashrc\n",[38,1025,1026,1029],{"class":40,"line":47},[38,1027,1028],{"class":897},"source",[38,1030,1023],{"class":781},[16,1032,1033],{},"至此，一个崭新的、功能完备的ROS 2开发环境搭建完毕。",[614,1035],{},[11,1037,1039],{"id":1038},"第一章误入歧途-那条看似正确的捷径","第一章：误入歧途 —— 那条看似正确的“捷径”",[16,1041,1042,1043,1046],{},"当我开始着手驱动Orbbec摄像头时，我做的第一件事，就是去GitHub上搜索。很快，我找到了一个看似完美的仓库：",[20,1044,1045],{},"orbbec\u002Forbbecsdk_ros2","。名字里带“官方”、“SDK”、“ROS2”，这简直就是天选之子！",[16,1048,1049],{},"我满怀希望地按照它的README操作，结果却是一连串的编译错误、依赖缺失、版本不匹配。我很快意识到，这个仓库可能已经年久失修，或者它只适配某些特定的、我没有的硬件或ROS版本。",[16,1051,1052],{},[113,1053,1054,1055,1058],{},"教训一：不要轻易相信名字里带“官方”的非主线仓库。它们可能是被遗弃的“孤儿”，而社区维护的通用包（比如",[20,1056,1057],{},"openni2_camera","）通常更可靠。",[614,1060],{},[11,1062,1064],{"id":1063},"第二章回归正道-官方驱动与ros的联姻","第二章：回归正道 —— 官方驱动与ROS的“联姻”",[16,1066,1067,1068],{},"在放弃了那条“捷径”后，我决定走最原始、最正统的道路：",[113,1069,1070,1071,1073],{},"使用ROS社区维护的、通用的",[20,1072,1057],{},"包，并让它与从Orbbec官方下载的最新版Linux SDK协同工作。",[16,1075,1076,1079],{},[113,1077,1078],{},"关键资源："," 我们需要的所有SDK文件，都可以在这个官方GitHub仓库里找到。请下载适用于你系统（如Linux x64）的压缩包。",[598,1081,1082],{},[383,1083,1084,1087,1088],{},[113,1085,1086],{},"仓库地址",": ",[1089,1090,1091],"a",{"href":1091,"rel":1092},"https:\u002F\u002Fgithub.com\u002Forbbec\u002FOpenNI_SDK\u002Ftree\u002Fv2.3.0.86-beat6",[1093],"nofollow",[722,1095,1097],{"id":1096},"_21-windows篇黄金标准测试先确保硬件没问题","2.1 【Windows篇】“黄金标准测试”：先确保硬件没问题！",[16,1099,1100,1101,1104],{},"在深入折腾Linux之前，一个最聪明的做法是：",[113,1102,1103],{},"先在Windows下确认你的摄像头是好的。"," 这能帮你排除硬件故障，让你在后续的Linux配置中充满信心。",[16,1106,1107,1110,1111,1114],{},[113,1108,1109],{},"1. 安装Windows驱动 (SensorDriver):","\n从上面给出的GitHub仓库下载并安装Windows版本的SDK。它里面会包含一个叫做 ",[20,1112,1113],{},"Orbbec_Sensor_Driver"," 的驱动程序。正常情况下，安装它就足够了。",[16,1116,1117,1120],{},[113,1118,1119],{},"2. 手动指定驱动 (如果自动安装失败):","\n有时候，Windows并不会自动把新安装的驱动和你的设备关联起来。这时需要你“按着它的头”去认。",[598,1122,1123,1126,1129,1132],{},[383,1124,1125],{},"右键点击“此电脑” -> “管理” -> “设备管理器”。",[383,1127,1128],{},"找到你的Orbbec摄像头。它可能显示为“未知设备”，通常带一个黄色的感叹号。",[383,1130,1131],{},"右键点击它 -> “更新驱动程序” -> “浏览我的电脑以查找驱动程序” -> “让我从计算机上的可用驱动程序列表中选取”。",[383,1133,1134],{},"在列表里，找到并选中 \"Orbbec\" 相关的驱动，强制安装。",[16,1136,1137,1140,1141,1144,1145,1148],{},[113,1138,1139],{},"3. 运行Windows版Viewer进行验证:","\n在Windows SDK的",[20,1142,1143],{},"tools\u002F","目录下，找到 ",[20,1146,1147],{},"NiViewer.exe","。双击运行它。",[598,1150,1151,1157],{},[383,1152,1153,1156],{},[113,1154,1155],{},"如果能成功看到彩色和深度图像","，恭喜你！你的摄像头硬件100%是好的。接下来在Linux里的任何问题，都是软件配置问题。",[383,1158,1159,1162],{},[113,1160,1161],{},"如果连这里都失败","，那很可能是USB端口\u002F线缆问题，或者是硬件本身需要联系售后了。",[722,1164,1166],{"id":1165},"_22-linux篇让wsl看到你的摄像头-usbipd-udev","2.2 【Linux篇】让WSL“看到”你的摄像头 (USBIPD & udev)",[16,1168,1169],{},"确认硬件OK后，我们回到WSL，开始我们的“攻坚战”。",[16,1171,1172],{},[113,1173,1174],{},"1. USBIPD配置:",[29,1176,1178],{"className":736,"code":1177,"language":738,"meta":34,"style":34},"# 在Windows PowerShell(管理员)中...\nwinget install --interactive --exact dorssel.usbipd-win\n# 注意：确保设备没有被附加到WSL，如果之前附加了，先detach\nusbipd list\nusbipd bind --busid \u003C你的BUSID>\nusbipd attach --wsl --busid \u003C你的BUSID>\n",[20,1179,1180,1185,1190,1195,1200,1205],{"__ignoreMap":34},[38,1181,1182],{"class":40,"line":41},[38,1183,1184],{},"# 在Windows PowerShell(管理员)中...\n",[38,1186,1187],{"class":40,"line":47},[38,1188,1189],{},"winget install --interactive --exact dorssel.usbipd-win\n",[38,1191,1192],{"class":40,"line":53},[38,1193,1194],{},"# 注意：确保设备没有被附加到WSL，如果之前附加了，先detach\n",[38,1196,1197],{"class":40,"line":60},[38,1198,1199],{},"usbipd list\n",[38,1201,1202],{"class":40,"line":66},[38,1203,1204],{},"usbipd bind --busid \u003C你的BUSID>\n",[38,1206,1207],{"class":40,"line":71},[38,1208,1209],{},"usbipd attach --wsl --busid \u003C你的BUSID>\n",[16,1211,1212,1213,1216],{},"在WSL终端用",[20,1214,1215],{},"lsusb","确认成功。",[16,1218,1219],{},[113,1220,1221],{},"2. udev规则配置:",[29,1223,1225],{"className":768,"code":1224,"language":770,"meta":34,"style":34},"# 在WSL终端中...\n# 从你下载的zip解压后的目录里找到rules文件\nsudo cp \u003C你的SDK路径>\u002Frules\u002Forbbec-usb.rules \u002Fetc\u002Fudev\u002Frules.d\u002F55-orbbec.rules\nsudo udevadm control --reload-rules\nsudo udevadm trigger\n",[20,1226,1227,1233,1238,1263,1276],{"__ignoreMap":34},[38,1228,1229],{"class":40,"line":41},[38,1230,1232],{"class":1231},"sJ8bj","# 在WSL终端中...\n",[38,1234,1235],{"class":40,"line":47},[38,1236,1237],{"class":1231},"# 从你下载的zip解压后的目录里找到rules文件\n",[38,1239,1240,1242,1245,1248,1251,1254,1257,1260],{"class":40,"line":53},[38,1241,778],{"class":777},[38,1243,1244],{"class":781}," cp",[38,1246,1247],{"class":830}," \u003C",[38,1249,1250],{"class":781},"你的SDK路",[38,1252,1253],{"class":788},"径",[38,1255,1256],{"class":830},">",[38,1258,1259],{"class":781},"\u002Frules\u002Forbbec-usb.rules",[38,1261,1262],{"class":781}," \u002Fetc\u002Fudev\u002Frules.d\u002F55-orbbec.rules\n",[38,1264,1265,1267,1270,1273],{"class":40,"line":60},[38,1266,778],{"class":777},[38,1268,1269],{"class":781}," udevadm",[38,1271,1272],{"class":781}," control",[38,1274,1275],{"class":897}," --reload-rules\n",[38,1277,1278,1280,1282],{"class":40,"line":66},[38,1279,778],{"class":777},[38,1281,1269],{"class":781},[38,1283,1284],{"class":781}," trigger\n",[16,1286,1287,1288,1291,1292,1295,1296,1299],{},"拔插设备或重新",[20,1289,1290],{},"attach","后，用",[20,1293,1294],{},"ls -l \u002Fdev\u002Fbus\u002Fusb\u002F...","确认权限，看到",[20,1297,1298],{},"crw-rw-rw-","就代表成功了。",[16,1301,1302],{},[113,1303,1304],{},"3. Linux底层验证 (可选但推荐):",[29,1306,1308],{"className":768,"code":1307,"language":770,"meta":34,"style":34},"# 进入你解压的SDK目录\ncd \u003C你的SDK路径>\u002Fsamples\u002Fbin\u002F\n\n# 运行示例程序\n.\u002FSimpleViewer\n",[20,1309,1310,1315,1331,1335,1340],{"__ignoreMap":34},[38,1311,1312],{"class":40,"line":41},[38,1313,1314],{"class":1231},"# 进入你解压的SDK目录\n",[38,1316,1317,1320,1322,1324,1326,1328],{"class":40,"line":47},[38,1318,1319],{"class":897},"cd",[38,1321,1247],{"class":830},[38,1323,1250],{"class":781},[38,1325,1253],{"class":788},[38,1327,1256],{"class":830},[38,1329,1330],{"class":781},"\u002Fsamples\u002Fbin\u002F\n",[38,1332,1333],{"class":40,"line":53},[38,1334,57],{"emptyLinePlaceholder":56},[38,1336,1337],{"class":40,"line":60},[38,1338,1339],{"class":1231},"# 运行示例程序\n",[38,1341,1342],{"class":40,"line":66},[38,1343,1344],{"class":777},".\u002FSimpleViewer\n",[16,1346,1347],{},"如果能弹出窗口并显示图像，说明你的Linux底层驱动和权限配置已经完美了！",[614,1349],{},[11,1351,1353],{"id":1352},"第三章核心战役-从源码编译彻底解决兼容性问题","第三章：核心战役 —— 从源码编译，彻底解决兼容性问题",[16,1355,1356,1357,1360,1361,1364,1365],{},"直接用",[20,1358,1359],{},"apt","安装的",[20,1362,1363],{},"ros-jazzy-openni2-camera","会因为ABI不兼容而崩溃。",[113,1366,1367,1368,1370],{},"唯一的、绝对正确的出路是：用你下载的SDK，从源码编译",[20,1369,1057],{},"。",[722,1372,1374],{"id":1373},"_31-打造一个完美的系统级的openni地基","3.1 打造一个完美的、系统级的OpenNI“地基”",[16,1376,1377],{},"这是我们经过无数次失败后，总结出的这个“奇葩”SDK的正确安装方式。",[29,1379,1381],{"className":768,"code":1380,"language":770,"meta":34,"style":34},"# 清理旧环境，保持系统纯净\nsudo rm -f \u002Fusr\u002Flocal\u002Flib\u002FlibOpenNI2.so*\nsudo rm -rf \u002Fusr\u002Flib\u002FOpenNI2 \u002Fetc\u002Fopenni2\n\n# 1. 安装主库文件到标准位置\nsudo cp -d \u003C你的SDK路径>\u002Fsdk\u002Flibs\u002FlibOpenNI2.so \u002Fusr\u002Flocal\u002Flib\u002F\n\n# 2. 安装驱动插件\nsudo mkdir -p \u002Fusr\u002Flib\u002FOpenNI2\u002FDrivers\nsudo cp \u003C你的SDK路径>\u002Fsdk\u002Flibs\u002FOpenNI2\u002FDrivers\u002F* \u002Fusr\u002Flib\u002FOpenNI2\u002FDrivers\u002F\n\n# 3. 手动创建缺失的关键符号链接\ncd \u002Fusr\u002Flib\u002FOpenNI2\u002FDrivers\u002F\nsudo ln -s liborbbec.so liborbbec.so.0\nsudo ln -s libOniFile.so libOniFile.so.0\n\n# 4. 创建配置文件，连接主库与驱动\nsudo mkdir -p \u002Fetc\u002Fopenni2\nsudo bash -c 'echo -e \"[Drivers]\\nRepository=\u002Fusr\u002Flib\u002FOpenNI2\u002FDrivers\" > \u002Fetc\u002Fopenni2\u002FOpenNI.ini'\n\n# 5. 刷新系统库缓存，让一切生效\nsudo ldconfig\n",[20,1382,1383,1388,1404,1419,1423,1428,1451,1455,1460,1473,1496,1500,1505,1511,1527,1541,1545,1550,1561,1575,1580,1586],{"__ignoreMap":34},[38,1384,1385],{"class":40,"line":41},[38,1386,1387],{"class":1231},"# 清理旧环境，保持系统纯净\n",[38,1389,1390,1392,1395,1398,1401],{"class":40,"line":47},[38,1391,778],{"class":777},[38,1393,1394],{"class":781}," rm",[38,1396,1397],{"class":897}," -f",[38,1399,1400],{"class":781}," \u002Fusr\u002Flocal\u002Flib\u002FlibOpenNI2.so",[38,1402,1403],{"class":897},"*\n",[38,1405,1406,1408,1410,1413,1416],{"class":40,"line":53},[38,1407,778],{"class":777},[38,1409,1394],{"class":781},[38,1411,1412],{"class":897}," -rf",[38,1414,1415],{"class":781}," \u002Fusr\u002Flib\u002FOpenNI2",[38,1417,1418],{"class":781}," \u002Fetc\u002Fopenni2\n",[38,1420,1421],{"class":40,"line":60},[38,1422,57],{"emptyLinePlaceholder":56},[38,1424,1425],{"class":40,"line":66},[38,1426,1427],{"class":1231},"# 1. 安装主库文件到标准位置\n",[38,1429,1430,1432,1434,1437,1439,1441,1443,1445,1448],{"class":40,"line":71},[38,1431,778],{"class":777},[38,1433,1244],{"class":781},[38,1435,1436],{"class":897}," -d",[38,1438,1247],{"class":830},[38,1440,1250],{"class":781},[38,1442,1253],{"class":788},[38,1444,1256],{"class":830},[38,1446,1447],{"class":781},"\u002Fsdk\u002Flibs\u002FlibOpenNI2.so",[38,1449,1450],{"class":781}," \u002Fusr\u002Flocal\u002Flib\u002F\n",[38,1452,1453],{"class":40,"line":77},[38,1454,57],{"emptyLinePlaceholder":56},[38,1456,1457],{"class":40,"line":83},[38,1458,1459],{"class":1231},"# 2. 安装驱动插件\n",[38,1461,1462,1464,1467,1470],{"class":40,"line":89},[38,1463,778],{"class":777},[38,1465,1466],{"class":781}," mkdir",[38,1468,1469],{"class":897}," -p",[38,1471,1472],{"class":781}," \u002Fusr\u002Flib\u002FOpenNI2\u002FDrivers\n",[38,1474,1475,1477,1479,1481,1483,1485,1487,1490,1493],{"class":40,"line":94},[38,1476,778],{"class":777},[38,1478,1244],{"class":781},[38,1480,1247],{"class":830},[38,1482,1250],{"class":781},[38,1484,1253],{"class":788},[38,1486,1256],{"class":830},[38,1488,1489],{"class":781},"\u002Fsdk\u002Flibs\u002FOpenNI2\u002FDrivers\u002F",[38,1491,1492],{"class":897},"*",[38,1494,1495],{"class":781}," \u002Fusr\u002Flib\u002FOpenNI2\u002FDrivers\u002F\n",[38,1497,1498],{"class":40,"line":100},[38,1499,57],{"emptyLinePlaceholder":56},[38,1501,1502],{"class":40,"line":106},[38,1503,1504],{"class":1231},"# 3. 手动创建缺失的关键符号链接\n",[38,1506,1507,1509],{"class":40,"line":235},[38,1508,1319],{"class":897},[38,1510,1495],{"class":781},[38,1512,1513,1515,1518,1521,1524],{"class":40,"line":241},[38,1514,778],{"class":777},[38,1516,1517],{"class":781}," ln",[38,1519,1520],{"class":897}," -s",[38,1522,1523],{"class":781}," liborbbec.so",[38,1525,1526],{"class":781}," liborbbec.so.0\n",[38,1528,1529,1531,1533,1535,1538],{"class":40,"line":246},[38,1530,778],{"class":777},[38,1532,1517],{"class":781},[38,1534,1520],{"class":897},[38,1536,1537],{"class":781}," libOniFile.so",[38,1539,1540],{"class":781}," libOniFile.so.0\n",[38,1542,1543],{"class":40,"line":252},[38,1544,57],{"emptyLinePlaceholder":56},[38,1546,1547],{"class":40,"line":258},[38,1548,1549],{"class":1231},"# 4. 创建配置文件，连接主库与驱动\n",[38,1551,1553,1555,1557,1559],{"class":40,"line":1552},18,[38,1554,778],{"class":777},[38,1556,1466],{"class":781},[38,1558,1469],{"class":897},[38,1560,1418],{"class":781},[38,1562,1564,1566,1569,1572],{"class":40,"line":1563},19,[38,1565,778],{"class":777},[38,1567,1568],{"class":781}," bash",[38,1570,1571],{"class":897}," -c",[38,1573,1574],{"class":781}," 'echo -e \"[Drivers]\\nRepository=\u002Fusr\u002Flib\u002FOpenNI2\u002FDrivers\" > \u002Fetc\u002Fopenni2\u002FOpenNI.ini'\n",[38,1576,1578],{"class":40,"line":1577},20,[38,1579,57],{"emptyLinePlaceholder":56},[38,1581,1583],{"class":40,"line":1582},21,[38,1584,1585],{"class":1231},"# 5. 刷新系统库缓存，让一切生效\n",[38,1587,1589,1591],{"class":40,"line":1588},22,[38,1590,778],{"class":777},[38,1592,1593],{"class":781}," ldconfig\n",[722,1595,1597,1598],{"id":1596},"_32-编译为你量身定做的openni2_camera","3.2 编译为你量身定做的",[20,1599,1057],{},[29,1601,1603],{"className":768,"code":1602,"language":770,"meta":34,"style":34},"# 1. 准备ROS 2工作空间并下载源码\nmkdir -p ~\u002Fros2_ws\u002Fsrc\ncd ~\u002Fros2_ws\u002Fsrc\ngit clone https:\u002F\u002Fgithub.com\u002Fros-drivers\u002Fopenni2_camera.git -b ros2\n\n# 2. 安装依赖\ncd ~\u002Fros2_ws\nsudo apt update\nrosdep install --from-paths src --ignore-src -r -y\n\n# 3. 编译\nrm -rf build\u002F install\u002F log\u002F # 确保干净的编译\ncolcon build\n",[20,1604,1605,1610,1620,1626,1643,1647,1652,1659,1667,1688,1692,1697,1716],{"__ignoreMap":34},[38,1606,1607],{"class":40,"line":41},[38,1608,1609],{"class":1231},"# 1. 准备ROS 2工作空间并下载源码\n",[38,1611,1612,1615,1617],{"class":40,"line":47},[38,1613,1614],{"class":777},"mkdir",[38,1616,1469],{"class":897},[38,1618,1619],{"class":781}," ~\u002Fros2_ws\u002Fsrc\n",[38,1621,1622,1624],{"class":40,"line":53},[38,1623,1319],{"class":897},[38,1625,1619],{"class":781},[38,1627,1628,1631,1634,1637,1640],{"class":40,"line":60},[38,1629,1630],{"class":777},"git",[38,1632,1633],{"class":781}," clone",[38,1635,1636],{"class":781}," https:\u002F\u002Fgithub.com\u002Fros-drivers\u002Fopenni2_camera.git",[38,1638,1639],{"class":897}," -b",[38,1641,1642],{"class":781}," ros2\n",[38,1644,1645],{"class":40,"line":66},[38,1646,57],{"emptyLinePlaceholder":56},[38,1648,1649],{"class":40,"line":71},[38,1650,1651],{"class":1231},"# 2. 安装依赖\n",[38,1653,1654,1656],{"class":40,"line":77},[38,1655,1319],{"class":897},[38,1657,1658],{"class":781}," ~\u002Fros2_ws\n",[38,1660,1661,1663,1665],{"class":40,"line":83},[38,1662,778],{"class":777},[38,1664,782],{"class":781},[38,1666,984],{"class":781},[38,1668,1669,1672,1674,1677,1680,1683,1686],{"class":40,"line":89},[38,1670,1671],{"class":777},"rosdep",[38,1673,796],{"class":781},[38,1675,1676],{"class":897}," --from-paths",[38,1678,1679],{"class":781}," src",[38,1681,1682],{"class":897}," --ignore-src",[38,1684,1685],{"class":897}," -r",[38,1687,898],{"class":897},[38,1689,1690],{"class":40,"line":94},[38,1691,57],{"emptyLinePlaceholder":56},[38,1693,1694],{"class":40,"line":100},[38,1695,1696],{"class":1231},"# 3. 编译\n",[38,1698,1699,1702,1704,1707,1710,1713],{"class":40,"line":106},[38,1700,1701],{"class":777},"rm",[38,1703,1412],{"class":897},[38,1705,1706],{"class":781}," build\u002F",[38,1708,1709],{"class":781}," install\u002F",[38,1711,1712],{"class":781}," log\u002F",[38,1714,1715],{"class":1231}," # 确保干净的编译\n",[38,1717,1718,1721],{"class":40,"line":235},[38,1719,1720],{"class":777},"colcon",[38,1722,1723],{"class":781}," build\n",[614,1725],{},[11,1727,1729],{"id":1728},"第四章收获的喜悦-启动与使用","第四章：收获的喜悦 —— 启动与使用",[16,1731,1732,1733,1739],{},"现在，你可以享受你的劳动成果了。打开一个新终端，",[113,1734,1735,1736,1738],{},"不再需要任何",[20,1737,831],{},"环境变量","！",[29,1741,1743],{"className":768,"code":1742,"language":770,"meta":34,"style":34},"# 激活你编译好的工作空间\nsource ~\u002Fros2_ws\u002Finstall\u002Fsetup.bash\n\n# 启动摄像头，发布深度图和点云\nros2 launch openni2_camera camera_with_cloud.launch.py\n\n# (可选) 启动并开启IMU\n# ros2 launch openni2_camera camera_with_cloud.launch.py enable_imu:=true\n",[20,1744,1745,1750,1757,1761,1766,1780,1784,1789],{"__ignoreMap":34},[38,1746,1747],{"class":40,"line":41},[38,1748,1749],{"class":1231},"# 激活你编译好的工作空间\n",[38,1751,1752,1754],{"class":40,"line":47},[38,1753,1028],{"class":897},[38,1755,1756],{"class":781}," ~\u002Fros2_ws\u002Finstall\u002Fsetup.bash\n",[38,1758,1759],{"class":40,"line":53},[38,1760,57],{"emptyLinePlaceholder":56},[38,1762,1763],{"class":40,"line":60},[38,1764,1765],{"class":1231},"# 启动摄像头，发布深度图和点云\n",[38,1767,1768,1771,1774,1777],{"class":40,"line":66},[38,1769,1770],{"class":777},"ros2",[38,1772,1773],{"class":781}," launch",[38,1775,1776],{"class":781}," openni2_camera",[38,1778,1779],{"class":781}," camera_with_cloud.launch.py\n",[38,1781,1782],{"class":40,"line":71},[38,1783,57],{"emptyLinePlaceholder":56},[38,1785,1786],{"class":40,"line":77},[38,1787,1788],{"class":1231},"# (可选) 启动并开启IMU\n",[38,1790,1791],{"class":40,"line":83},[38,1792,1793],{"class":1231},"# ros2 launch openni2_camera camera_with_cloud.launch.py enable_imu:=true\n",[16,1795,1796,1797,1800,1801,1800,1804,1807],{},"在另一个终端，你可以用",[20,1798,1799],{},"ros2 topic list","，",[20,1802,1803],{},"rqt_image_view",[20,1805,1806],{},"rviz2","等工具来查看数据。",[16,1809,1810,1813,1814,1816,1817,1819,1820,1823,1824,1827,1828,1831,1832,1370],{},[113,1811,1812],{},"注意："," 如果在",[20,1815,1803],{},"或",[20,1818,1806],{},"中看不到图像，请检查显示插件的",[113,1821,1822],{},"QoS设置","，将",[113,1825,1826],{},"Reliability Policy","从",[20,1829,1830],{},"Reliable","改为",[20,1833,1834],{},"Best Effort",[11,1836,1837],{"id":1837},"结语",[16,1839,1840],{},"从安装一个纯净的Ubuntu，到误入歧途，再到最终通过系统级的配置和源码编译解决问题，这段经历虽然曲折，但让我对Linux驱动、ROS编译系统和问题排查有了前所未有的深刻理解。",[16,1842,1843,1844,1847],{},"最重要的经验是：",[113,1845,1846],{},"先在最简单的环境（原生Windows）下验证硬件，再进入复杂的环境（WSL + ROS）进行软件配置。"," 这能帮你节省大量的调试时间。",[16,1849,1850],{},"希望这份包含了Windows和Linux两大战场的详尽指南，能为你点亮前行的道路。",[16,1852,1853],{},"祝编码愉快！",[598,1855,1856],{},[383,1857,1858],{},"Frank",[624,1860,1861],{},"html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}",{"title":34,"searchDepth":47,"depth":47,"links":1863},[1864,1865,1869,1870,1874,1879,1880],{"id":691,"depth":47,"text":692},{"id":719,"depth":47,"text":720,"children":1866},[1867,1868],{"id":724,"depth":53,"text":725},{"id":756,"depth":53,"text":757},{"id":1038,"depth":47,"text":1039},{"id":1063,"depth":47,"text":1064,"children":1871},[1872,1873],{"id":1096,"depth":53,"text":1097},{"id":1165,"depth":53,"text":1166},{"id":1352,"depth":47,"text":1353,"children":1875},[1876,1877],{"id":1373,"depth":53,"text":1374},{"id":1596,"depth":53,"text":1878},"3.2 编译为你量身定做的openni2_camera",{"id":1728,"depth":47,"text":1729},{"id":1837,"depth":47,"text":1837},"太夸张了，本以为一个摄像头能有多麻烦，结果还是惊掉了下巴。",{},"\u002Fblogs\u002F关于orbbec-astra-调试了半天的这件事",{"title":644,"description":1881},"blogs\u002F关于ORBBEC Astra 调试了半天的这件事\u002F关于ORBBEC Astra 调试了半天的这件事","8ASVLR7SOSPe6Pw1GPgw_qlyn-xRp8iQrPV2zwR-w8g",{"id":1888,"title":1889,"body":1890,"date":634,"description":1897,"extension":636,"meta":1922,"navigation":56,"path":1923,"seo":1924,"stem":1925,"__hash__":1926},"blogs\u002Fblogs\u002F关于职业规划.md","关于职业规划",{"type":8,"value":1891,"toc":1920},[1892,1895,1898,1901,1904,1907,1910,1913],[694,1893,1894],{"id":1894},"关于大厂的看法",[16,1896,1897],{},"至于自身是否优秀的问题，你要想想我说的\"大厂为什么选择你？\"如果你特别想去大厂：\n1.要想办法培养自己的核心优势，能够让大厂的HR眼前一亮\n2.想想自己为什么想去大厂，背后的核心原因是觉得大厂薪酬高还是可以有虚荣感，然后判断下如果自己比较难进大厂，能不能有其他渠道实现自己背后的那个想法\n3.我想说如果你自己都不相信自己，不只是进入大厂，做什么都很难成功的。从来没有一条规则说进入大厂就是人生赢家，在其他公司工作就是loser。于其追求大厂，不如追求适合自己的地方。大厂也好小厂也罢，最终都是为了幸福的人生。也许你觉得进入大厂就是幸福，但你不知道有多少大厂的人渴望逃出去休息休息。所以，有时候接受妥协也是一种幸福",[694,1899,1900],{"id":1900},"关于兴趣方向以及简历",[16,1902,1903],{},"你要根据你的专业和你的兴趣爱好定一个大的方向，其他人没办法帮助你确定职业发展的大方向的，一个工作可能一做就是三四十年，所以不要被迫选择自己不感兴趣的领域。你可以好好研究下对于你的专业和擅长点来说，现在主流招聘平台里的大企业都在找哪些岗位，哪些岗位收入偏高",[16,1905,1906],{},"对于你的简历，其实不太及格，全是文字，我很难看得进去，不要用文字去堆砌，甚至我都感觉你用AI去写了很多东西堆进去。简历结构要清晰，该加粗的加粗，该用序号的用序号分行，少一些感性的文字，多一些可量化的指标或者结果。",[16,1908,1909],{},"如果你要准备这种自己设计的简历，我建议是最多2页，正反面把自己的内容都写出来，如果不知道怎么结构化，上购物网站买个服务让他们帮你改改和设计下，切记花里胡哨。或者上猎聘，按照他的模板去填写，然后导出来一份PDF，也比你自己设计好很多。不过现在大企业校招或者社招，都是让你直接在他们的系统里填写信息了。",[694,1911,1912],{"id":1912},"关于就业",[16,1914,1915,1916,1919],{},"如果你最终目的是要就业的，",[113,1917,1918],{},"实习、项目、算法能力、工程能力是影响软件工程就业的核心因素","，如果本科你有比较匹配的实习和项目，我觉得优先秋招看看。除非你说你想去做科研或者高校这种，再有效考虑考研。还是要看你自己的目的和情况，想就业就不要通过考验延迟就业。",{"title":34,"searchDepth":47,"depth":47,"links":1921},[],{},"\u002Fblogs\u002F关于职业规划",{"title":1889,"description":1897},"blogs\u002F关于职业规划","SYBWfVsj-dnQypZkNgjB9jloGRBFyMnS1U95YAlzvMU",{"id":1928,"title":1929,"body":1930,"date":634,"description":2034,"extension":636,"meta":2035,"navigation":56,"path":2036,"seo":2037,"stem":2038,"__hash__":2039},"blogs\u002Fblogs\u002F关于自建new-api\u002F关于自建new-api.md","关于自建new-api",{"type":8,"value":1931,"toc":2028},[1932,1935,1942,1945,1950,1954,1968,1972,1975,1983,1987,1998,2005,2009,2016,2022,2025],[694,1933,1934],{"id":1934},"前言",[16,1936,1937,1938,1941],{},"在L站逛多了之后发现，太多公益站不用确实有点可惜，而且我老早之前就有一个痛点想解决，",[113,1939,1940],{},"就是base_url和api_key的方便管理","，我发现new-api这个项目非常契合我的需求，即可以集中管理api_key又方便调用。但是本地docker部署的，每次都需要运行docker，打开localhost：3000才行，相当麻烦，所以我想要自行部署一个站点，方便自己使用。",[694,1943,1944],{"id":1944},"步骤",[16,1946,1947],{},[113,1948,1949],{},"先叠个甲：我也是在ai的指导下完成的，有什么不明白的，还是问ai叠比较好",[11,1951,1953],{"id":1952},"_1-准备服务器","1. 准备服务器",[16,1955,1956,1957,1960,1963,1964,1967],{},"可以选择国内外比较有名的服务器，不管是付费的，像是：\n",[654,1958],{"alt":656,"src":1959},"\u002Fimages\u002Fblogs\u002F%E5%85%B3%E4%BA%8E%E8%87%AA%E5%BB%BAnew-api\u002Fimage-8.png",[654,1961],{"alt":656,"src":1962},"\u002Fimages\u002Fblogs\u002F%E5%85%B3%E4%BA%8E%E8%87%AA%E5%BB%BAnew-api\u002Fimage-9.png","\n或者是相对免费的：\n",[654,1965],{"alt":656,"src":1966},"\u002Fimages\u002Fblogs\u002F%E5%85%B3%E4%BA%8E%E8%87%AA%E5%BB%BAnew-api\u002Fimage-10.png","\n反正我是部署在huggingface的space上，不花一分钱",[11,1969,1971],{"id":1970},"_2-初始化space或者是服务器","2. 初始化space或者是服务器",[16,1973,1974],{},"可以在AI的指导下，具体问题具体分析，我是直接用ai给的dockerfile文件(当然是支持docker的)，文本如下：",[29,1976,1981],{"className":1977,"code":1979,"language":1980},[1978],"language-text","FROM calciumion\u002Fnew-api:latest\n\n# 1. 绕过 HF 的 \u002Fv1 拦截\nENV BASE_PATH=\u002Fhf\n\n# 2. 端口配置\nENV PORT=7860\nEXPOSE 7860\n\n# 3. 环境变量同步域名（确保你已经做了 Cloudflare Worker 转发）\nENV GLOBAL_WEB_BASE_URL= 你的域名\n\nENTRYPOINT [\"\u002Fnew-api\"]\n","text",[20,1982,1979],{"__ignoreMap":34},[11,1984,1986],{"id":1985},"_3-准备域名可选","3. 准备域名(可选)",[16,1988,1989,1990,1994,1995],{},"域名就像是门牌号，有了显得更专业一些，而且可以托管在cloudflare上，更安全。\n我是在这个链接：",[1089,1991,1992],{"href":1992,"rel":1993},"https:\u002F\u002Fwww.gname.com",[1093]," 上获得免费的域名，可以不可以免费续费我不知道，但是有一年的时间可以用\n",[654,1996],{"alt":656,"src":1997},"\u002Fimages\u002Fblogs\u002F%E5%85%B3%E4%BA%8E%E8%87%AA%E5%BB%BAnew-api\u002Fimage-11.png",[16,1999,2000,2001,2004],{},"选择",[113,2002,2003],{},"免费注册","就好了，然后根据相应的流程走",[11,2006,2008],{"id":2007},"_4-准备数据库","4. 准备数据库",[16,2010,2011,2012,2015],{},"我是使用",[113,2013,2014],{},"Neon数据库","，因为new-api需要后端数据库的支持，所以我们需要做相应的处理，相应的步骤也是可以问ai叠",[16,2017,2018,2019],{},"最后如果顺利的话，应该可以看到你的域名已经有new-api的界面了\n",[654,2020],{"alt":656,"src":2021},"\u002Fimages\u002Fblogs\u002F%E5%85%B3%E4%BA%8E%E8%87%AA%E5%BB%BAnew-api\u002Fimage-12.png",[694,2023,2024],{"id":2024},"最后",[16,2026,2027],{},"尽情往里面塞api_key吧",{"title":34,"searchDepth":47,"depth":47,"links":2029},[2030,2031,2032,2033],{"id":1952,"depth":47,"text":1953},{"id":1970,"depth":47,"text":1971},{"id":1985,"depth":47,"text":1986},{"id":2007,"depth":47,"text":2008},"在L站逛多了之后发现，太多公益站不用确实有点可惜，而且我老早之前就有一个痛点想解决，就是base_url和api_key的方便管理，我发现new-api这个项目非常契合我的需求，即可以集中管理api_key又方便调用。但是本地docker部署的，每次都需要运行docker，打开localhost：3000才行，相当麻烦，所以我想要自行部署一个站点，方便自己使用。",{},"\u002Fblogs\u002F关于自建new-api",{"title":1929,"description":2034},"blogs\u002F关于自建new-api\u002F关于自建new-api","j_rtaVvqJto_GStBJmxvG4f-X2AzibjTjttgp12p8hI",{"id":2041,"title":2042,"body":2043,"date":634,"description":2062,"extension":636,"meta":2063,"navigation":56,"path":2064,"seo":2065,"stem":2066,"__hash__":2067},"blogs\u002Fblogs\u002F关于读研生活.md","读研心得",{"type":8,"value":2044,"toc":2059},[2045,2048],[11,2046,2047],{"id":2047},"心得如下",[380,2049,2050,2053,2056],{},[383,2051,2052],{},"无论如何保持心态好",[383,2054,2055],{},"做永远不吃压力的人",[383,2057,2058],{},"导师说啥都是是是",{"title":34,"searchDepth":47,"depth":47,"links":2060},[2061],{"id":2047,"depth":47,"text":2047},"关于读研的一些感想",{},"\u002Fblogs\u002F关于读研生活",{"title":2042,"description":2062},"blogs\u002F关于读研生活","y4BvMwQ_-Dq66ZWpMtsN3CpVAQy-K_SEQIkPOYST5OQ",{"id":2069,"title":2070,"body":2071,"date":634,"description":2149,"extension":636,"meta":2150,"navigation":56,"path":2151,"seo":2152,"stem":2153,"__hash__":2154},"blogs\u002Fblogs\u002F实习的体会和经验.md","实习的体会和经验",{"type":8,"value":2072,"toc":2147},[2073,2077,2085,2088,2096,2099],[694,2074,2076],{"id":2075},"工作内容","工作内容：",[380,2078,2079,2082],{},[383,2080,2081],{},"负责医疗报告文本质控，技术栈为python + html，然后与真实的RIS接口开发的人员进行交流，不断优化和改善在生产环境中真正会遇到的问题",[383,2083,2084],{},"同时呢，也在开发yiji-医疗Agent，是一个比较全能的，为了解决医院里琐事的Agent，以及还有点科研方向，算是比较杂的",[694,2086,2087],{"id":2087},"一些体会",[380,2089,2090,2093],{},[383,2091,2092],{},"其实一开始作为一个实习生，不知道这个项目的上线速度只有短短的一个月，然后当时最开始的要求也是写一个demo.html就好了，没想到后面居然直接要接入RIS系统，然后各种赶工，莫名push，让人头皮发麻，确实真正体会到了打工人的痛苦",[383,2094,2095],{},"其实团队协作很重要，毕竟开发全部一人来做，肯定累，且无暇顾及测试这些，希望未来能遇到好的团队，好的co-worker",[694,2097,2098],{"id":2098},"一些经验",[380,2100,2101,2107,2117,2123,2129,2135,2141],{},[383,2102,2103,2106],{},[113,2104,2105],{},"需求和使用场景一定要弄清楚","，不然很容易导致开发一半发现不对，会导致迭代时间变长，修改的东西变多，甚至可能技术栈都要改变，最典型的例子就是这个报告文本质控，一开始就以为是demo，然后前端就直接用html写了，然后我理解的使用场景的偏差，也导致遗留代码，逐渐变为屎山，之后慢慢修，才好了很多",[383,2108,2109,2112,2113,2116],{},[113,2110,2111],{},"生产环境的坑远比想象的多","，只能说开发，闭门造车确实没什么压力，自己测试的好好的，怎么一到用户端就漏洞百出，就是因为没有考虑到生产环境的问题，就比如说前端为什么没有改变，然后哪一个环节之前没有问题，现在又有问题了，config配置文件怎么没有更新，所以说要做好",[113,2114,2115],{},"预防措施和fallback",",不可能完美的，一定会出现各种问题，代码里事先就需要做好debug的日志之类的，一有问题查日志，或者是print出来，方便定位问题",[383,2118,2119,2122],{},[113,2120,2121],{},"给自己留好退路","，选择方案时不能极端，一定要综合考虑，这一点其实不必多少，多一点疑虑，多一点和Claude讨论自己的疑虑，尽量找出最好可行的方案",[383,2124,2125,2128],{},[113,2126,2127],{},"团队协作","，搞清楚自己的职责边界，就算有能力，也要说自己没有能力，用好团队的力量，当然有靠谱的人多依靠，当然我这个是真的没办法，毕竟怎么感觉就我一个还行？",[383,2130,2131,2134],{},[113,2132,2133],{},"不要轻信AI","，就算AI再强，还是要review代码，不然稍微不留神，就不对了，还需要擦屁股",[383,2136,2137,2140],{},[113,2138,2139],{},"善用gitignore和Agent.md","，只能说之前太傻了，不懂得用这两种方式，gitignore完美解决了上传不了大文件，误传隐私文件的问题；然后Agent.md，是用了pi之后，常用来约束Agent，避免做出血压高的行为",[383,2142,2143,2146],{},[113,2144,2145],{},"思考设计远比写代码强","，毕竟AI时代，人人都是程序员，我们所拥有的只不过是比常人更强的代码理解能力，以及架构、设计的能力，更高的眼界和想法，一定要好好提升，更好地与AI协作，而不是AI推着你前进。",{"title":34,"searchDepth":47,"depth":47,"links":2148},[],"此文谨以记录我26年暑期在杭州九枢科技有限公司的实习",{},"\u002Fblogs\u002F实习的体会和经验",{"description":2149},"blogs\u002F实习的体会和经验","i-1Y8SxMxOuRG3MBmyIVg2mJxwG_pd3C_znM1qRt0hQ",{"id":2156,"title":2157,"body":2158,"date":634,"description":2206,"extension":636,"meta":2207,"navigation":56,"path":2208,"seo":2209,"stem":2210,"__hash__":2211},"blogs\u002Fblogs\u002F摸鱼牌侠开发日志.md","记录一下，Godot和AI结合开发",{"type":8,"value":2159,"toc":2201},[2160,2164,2167,2171,2178,2181,2184,2187,2194],[11,2161,2163],{"id":2162},"初窥godot","初窥Godot",[16,2165,2166],{},"一开始想做个手机游戏，感觉用flutter flame，就好了。但是了解了一下发现，好像并没有什么知名的游戏是使用flutter flame开发的，而且这也不寻常，所以我在朋友的推荐下，下载了godot engine，开始了我的开发之旅，一开始感觉这个界面跟unity差不多，但是开发起来很流畅，而且godot的编程语言GDScript跟python没什么区别，比较好上手，很容易读懂。",[11,2168,2170],{"id":2169},"接入ai","接入AI",[16,2172,2173,2174,2177],{},"然后手搓了一会儿，感觉自己在AI的指导下写效率还是太低下了，我就去寻找godot有没有plugin能够使用AI帮你写代码，找到了，但是用起来很难受。之后发现原来可以",[113,2175,2176],{},"直接接入vscode","(具体操作我是问AI的),那这就简单多了，我直接接入cline，直接开始vibe coding,一开始还以为AI使用写script文件，后来发现它连tscn，tres等文件都能改，我只需要在它的指导下，调整godot里面的一些设置就好了。",[11,2179,2180],{"id":2180},"开发调优",[16,2182,2183],{},"开发的过程中很多角色立绘都是使用AI生成的，而且发现很多东西确实不是那么简单的，感觉还需要学习很多东西，这只能算是一个demo，还要继续努力。",[16,2185,2186],{},"PS:AI太好用了",[16,2188,2189,2190],{},"最后展示一下项目链接：\n",[1089,2191,2192],{"href":2192,"rel":2193},"https:\u002F\u002Fgithub.com\u002Fyoruniubi\u002Fmo_yu_pai_xia",[1093],[16,2195,2196,2197],{},"在线玩：\n",[1089,2198,2199],{"href":2199,"rel":2200},"https:\u002F\u002Fyoruniubi.github.io\u002Fmo_yu_pai_xia\u002F",[1093],{"title":34,"searchDepth":47,"depth":47,"links":2202},[2203,2204,2205],{"id":2162,"depth":47,"text":2163},{"id":2169,"depth":47,"text":2170},{"id":2180,"depth":47,"text":2180},"最近，vibe coding比较火，然后我也陷入了游戏荒，感觉玩什么游戏都没有意思，于是乎，我拍脑门一想，自己开发一款游戏不就好了吗？说干就干。",{},"\u002Fblogs\u002F摸鱼牌侠开发日志",{"title":2157,"description":2206},"blogs\u002F摸鱼牌侠开发日志","tKZoadRptxfqhjJSZetnNbsUaNM7et_SIoeWn_TuCtA",{"id":2213,"title":2214,"body":2215,"date":634,"description":2282,"extension":636,"meta":2283,"navigation":56,"path":2284,"seo":2285,"stem":2286,"__hash__":2287},"blogs\u002Fblogs\u002F浏览器扩展开发\u002F浏览器扩展开发.md","关于浏览器拓展插件开发的那些事",{"type":8,"value":2216,"toc":2278},[2217,2220,2224,2241,2247,2253,2256,2261,2267,2272],[16,2218,2219],{},"如果使用原生的web开发 (html,css,js)",[11,2221,2223],{"id":2222},"首先是必须的文件列表","首先是必须的文件列表：",[380,2225,2226,2229,2232,2235,2238],{},[383,2227,2228],{},"manifest.json",[383,2230,2231],{},"background.js",[383,2233,2234],{},"popup.html (类似于index.html,就是浏览器拓展的主界面)",[383,2236,2237],{},"popup.js（国际化啊，",[383,2239,2240],{},"popup.css (样式文件)",[16,2242,2243,2244],{},"对于火狐浏览器：在manifest.json文件中现需要写成这样：\n",[654,2245],{"alt":656,"src":2246},"\u002Fimages\u002Fblogs\u002F%E6%B5%8F%E8%A7%88%E5%99%A8%E6%89%A9%E5%B1%95%E5%BC%80%E5%8F%91\u002Fimage-3.png",[16,2248,2249,2250],{},"对于谷歌浏览器：在manifest.json文件中现需要写成这样：\n",[654,2251],{"alt":656,"src":2252},"\u002Fimages\u002Fblogs\u002F%E6%B5%8F%E8%A7%88%E5%99%A8%E6%89%A9%E5%B1%95%E5%BC%80%E5%8F%91\u002Fimage-4.png",[11,2254,2255],{"id":2255},"加载文件目录",[16,2257,2258],{},[113,2259,2260],{},"chrome浏览器",[16,2262,2263,2264],{},"chrome:\u002F\u002Fextensions\u002F\n",[654,2265],{"alt":656,"src":2266},"\u002Fimages\u002Fblogs\u002F%E6%B5%8F%E8%A7%88%E5%99%A8%E6%89%A9%E5%B1%95%E5%BC%80%E5%8F%91\u002Fimage.png",[16,2268,2269],{},[113,2270,2271],{},"edge浏览器",[16,2273,2274,2275],{},"edge:\u002F\u002Fextensions\u002F\n",[654,2276],{"alt":656,"src":2277},"\u002Fimages\u002Fblogs\u002F%E6%B5%8F%E8%A7%88%E5%99%A8%E6%89%A9%E5%B1%95%E5%BC%80%E5%8F%91\u002Fimage-1.png",{"title":34,"searchDepth":47,"depth":47,"links":2279},[2280,2281],{"id":2222,"depth":47,"text":2223},{"id":2255,"depth":47,"text":2255},"写在前面",{},"\u002Fblogs\u002F浏览器扩展开发",{"title":2214,"description":2282},"blogs\u002F浏览器扩展开发\u002F浏览器扩展开发","jDtEB6PJ3MIx8k5TnYktb2pYMDg_TX43AjUf8-h939Q",1791390054240]