rk3568安卓13驱动适配-HDMI分流(GSV2001)
本文记录工作中基于rk3568安卓13的SDK适配板载外设GSV2001芯片驱动时具体的修改项和问题目录前言一、GSV2001工作原理梳理二、GSV2001软件适配1.驱动移植1.1 底层接口移植1.2 Main函数移植1.3 设备树文件2.问题记录2.1 I2C读协议错误2.2 edid写入失败总结前言GSV2001 是一款由 GSCoolink基石酷联生产的 HDMI 2.0 芯片‌主要功能是将 1 路 HDMI 信号分配为 2 路输出支持 4K 高清视频传输与音频处理 。‌‌‌本文介绍如何在rk3568安卓13的SDK中适配GSV2001让其能正常工作。一、GSV2001工作原理梳理通过芯片规格书和硬件设计原理可以看出主控通过I2C对GSV芯片的寄存器进行配置使其正常工作。官方有提供应用SDK不过是跑在STM32F030C8裸机上的需要移植到RK3568上当作驱动去运行。从硬件上可以看出工作很简单匹配多个电源后控制复位引脚拉低10ms以上即可复位然后通过I2C对GSV芯片进行轮询配置。二、GSV2001软件适配1.驱动移植1.1 底层接口移植首先需要把底层I2C读写接口还有串口打印移植到linux驱动上去都有现成的接口需要注意I2C读时是起始位设备地址写位ACK寄存器地址高字节ACK寄存器地址低字节ACKReStart设备地址读数据一定要注意那个ReStart信号读的接口如下才能规范int ManI2cRead(uint8_t dev_addr, uint16_t reg_addr, uint8_t *buf, int len) { struct i2c_msg msgs[2]; uint8_t reg_buf[2]; int ret; if (!g_i2c_client) return -EINVAL; if (!buf || len 0) { return -EINVAL; } /* 准备寄存器地址大端高字节在前 */ reg_buf[0] (reg_addr 8) 0xFF; reg_buf[1] reg_addr 0xFF; /* 消息1: 写寄存器地址不发送 STOP */ msgs[0].addr g_i2c_client-addr; msgs[0].flags 0; /* 写 */ msgs[0].len 2; msgs[0].buf reg_buf; /* 消息2: 读取数据发送 RESTART STOP */ msgs[1].addr g_i2c_client-addr; msgs[1].flags I2C_M_RD; /* 读 */ msgs[1].len len; msgs[1].buf buf; /* 执行传输: 两个消息之间会自动产生 RESTART */ ret i2c_transfer(g_i2c_client-adapter, msgs, 2); if (ret 0) { dev_err(g_i2c_client-dev, GSV: I2C read failed: dev0x%02x reg0x%04x len%d ret%d\n, dev_addr, reg_addr, len, ret); return ret; } if (ret ! 2) { dev_err(g_i2c_client-dev, GSV: I2C read partial: dev0x%02x reg0x%04x ret%d\n, dev_addr, reg_addr, ret); return -EIO; } return len; }SDK中的I2C源文件用普通IO模拟的这里可以删除掉只需要改写bsp.c文件中的接口注释掉不用的接口即可如下/** * file bsp.c * * brief sample bsp support */ #include bsp.h #include linux/i2c.h #include linux/delay.h static struct i2c_client *g_i2c_client NULL; /* 在驱动probe中调用此函数设置client */ void i2c_set_client(struct i2c_client *client) { g_i2c_client client; } int ManI2cRead(uint8_t dev_addr, uint16_t reg_addr, uint8_t *buf, int len) { struct i2c_msg msgs[2]; uint8_t reg_buf[2]; int ret; if (!g_i2c_client) return -EINVAL; if (!buf || len 0) { return -EINVAL; } /* 准备寄存器地址大端高字节在前 */ reg_buf[0] (reg_addr 8) 0xFF; reg_buf[1] reg_addr 0xFF; /* 消息1: 写寄存器地址不发送 STOP */ msgs[0].addr g_i2c_client-addr; msgs[0].flags 0; /* 写 */ msgs[0].len 2; msgs[0].buf reg_buf; /* 消息2: 读取数据发送 RESTART STOP */ msgs[1].addr g_i2c_client-addr; msgs[1].flags I2C_M_RD; /* 读 */ msgs[1].len len; msgs[1].buf buf; /* 执行传输: 两个消息之间会自动产生 RESTART */ ret i2c_transfer(g_i2c_client-adapter, msgs, 2); if (ret 0) { dev_err(g_i2c_client-dev, GSV: I2C read failed: dev0x%02x reg0x%04x len%d ret%d\n, dev_addr, reg_addr, len, ret); return ret; } if (ret ! 2) { dev_err(g_i2c_client-dev, GSV: I2C read partial: dev0x%02x reg0x%04x ret%d\n, dev_addr, reg_addr, ret); return -EIO; } return len; } int ManI2cWrite(uint8_t dev_addr, uint16_t reg_addr, uint8_t *buf, int len) { uint8_t tx_buf[512]; int i; if (!g_i2c_client) return -EINVAL; if (len 509){ dev_info(g_i2c_client-dev, ManI2cWrite fail overSize\n); return -EINVAL; } tx_buf[0] (reg_addr 8) 0xFF; tx_buf[1] reg_addr 0xFF; for (i 0; i len; i) { tx_buf[2 i] buf[i]; } return i2c_master_send(g_i2c_client, tx_buf, len 2); } /** * brief bsp i2c read function, support bus/dev address, 8/16 register address * return AvOk - success */ AvRet BspI2cRead(uint32 devAddress, uint32 regAddress, uint8 *data, uint16 count) { AvRet ret AvOk; int rst 0; uint8 deviceAddress (uint8)AvGetI2cDeviceAddress(devAddress); uint16 regAdress (uint32)((AvGetRegAddress(devAddress)8) | AvGetRegAddress(regAddress)); rst ManI2cRead(deviceAddress, regAdress, data, count); if(rst 0){ ret rst; } else if(rst 0){ ret AvError; } return ret; } /** * brief bsp i2c write function, support bus/dev address, 8/16 register address * return AvOk - success */ AvRet BspI2cWrite(uint32 devAddress, uint32 regAddress, uint8 *data, uint16 count) { AvRet ret AvOk; int rst 0; char buf[300]; char print_buf[512] {0}; int offset 0; int i 0; uint8 deviceAddress (uint8)AvGetI2cDeviceAddress(devAddress); uint16 regAdress (uint32)((AvGetRegAddress(devAddress)8) | AvGetRegAddress(regAddress)); rst ManI2cWrite(deviceAddress, regAdress, data, count); if(rst 0 ){ ret rst; } else if(rst 0){ ret AvError; } return ret; } /** * brief send one byte from uart * return AvOk - success */ AvRet BspUartSendByte(uint8 *data, uint16 size) { char buf[256]; int i, len; // 1. 检查 g_i2c_client 是否有效 if (!g_i2c_client) { printk(KERN_INFO GSV: UART send %d bytes (client not ready)\n, size); return AvOk; } // 2. 检查数据有效性 if (!data || size 0) { dev_dbg(g_i2c_client-dev, GSV: UART send empty\n); return AvOk; } // 3. 只打印可见字符 len min((int)size, 255); for (i 0; i len; i) { uint8 c data[i]; if (c 0x20 c 0x7F) { buf[i] c; } else if (c \n || c \r) { buf[i] c; } else { buf[i] .; } } buf[i] \0; dev_info(g_i2c_client-dev, GSV: %s\n, buf); return AvOk; } /** * brief get one byte from uart * return AvOk - success */ AvRet BspUartGetByte(uint8 *data) { AvRet ret AvOk; return ret; } /** * brief get current time in ms * return AvOk - success */ AvRet BspGetMilliSecond(uint32 *ms) { *ms (uint32)(ktime_get_real_ns() / 1000000); return AvOk; } AvRet BspGetKey(uint8 *data) { AvRet ret AvNotAvailable; return ret; } AvRet BspIrdaGetByte(uint8 *data) { AvRet ret AvOk; return ret; }1.2 Main函数移植将官方提供的av_main.c文件中的main函数改写成linux驱动中的工作队列形式定时执行。修改后的av_main.c文件如下/** * file av_main.c * * brief sample main entry for audio/video based software */ #include av_main.h #include global_var.h #include linux/module.h #include linux/i2c.h #include linux/delay.h #include linux/workqueue.h #include linux/of.h #include linux/gpio/consumer.h #include linux/of_gpio.h #include linux/gpio.h struct gsv_device_data { struct gpio_desc *reset_gpio; struct i2c_client *client; }; static struct i2c_client *gsv_client; static struct delayed_work gsv_work; static bool gsv_running false; /* 2. Device Level Declaration */ /* 2.1 total devices */ /* it must be declared in AvDevice */ static AvDevice devices[1] {0}; static AvPort gsv2k1Ports[7] {0}; static Gsv2k1Device gsv2k1_0 {0}; extern void i2c_set_client(struct i2c_client *client); static void gsv_work_handler(struct work_struct *work) { if (!gsv_running) return; // 调用官方SDK主循环 AvApiUpdate(); AvPortConnectUpdate(devices[0]); // 重新调度 - 50ms轮询 schedule_delayed_work(gsv_work, msecs_to_jiffies(50)); } static int gsv_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct device *dev client-dev; /* 2.2 specific devices and ports */ /* they must be able to be linked to the device in 1. */ dev_info(dev, GSV2001 probe start\n); gsv_client client; i2c_set_client(client); /* 1. Low Level Hardware Level Initialization */ /* 1.1 init bsp support (user speficic) */ // BspInit(); /* 1.2 init software package and hookup users bsp functions */ AvApiInit(); AvApiHookBspFunctions(BspI2cRead, BspI2cWrite, BspUartSendByte, BspUartGetByte, BspGetMilliSecond, BspGetKey, BspIrdaGetByte); AvApiHookUserFunctions(ListenToKeyCommand, ListenToUartCommand, ListenToIrdaCommand); /* 2.3 init device address in 2.2 */ gsv2k1_0.DeviceAddress AvGenerateDeviceAddress(0x00,0x01,0xB0,0x00); /* 2.4 connect devices to device declaration */ AvApiAddDevice(devices[0], Gsv2k1, 0, (void *)gsv2k1_0, (void *)gsv2k1Ports[0], NULL); /* 3. Port Level Declaration */ /* 3.1 init devices and port structure, must declare in number order */ /* 0-3 HdmiRx, 4-7 HdmiTx, 8-9 TTLTx, 10-11 TTLRx, 20-23 Scaler, 24-27 Color, 28 VideoGen, 30 VideoIn, 32 VideoOut, 34 AudioGen, 36 ClockGen */ AvApiAddPort(devices[0],gsv2k1Ports[0] ,0 ,HdmiRx); AvApiAddPort(devices[0],gsv2k1Ports[1] ,4 ,HdmiTx); AvApiAddPort(devices[0],gsv2k1Ports[2] ,5 ,HdmiTx); AvApiAddPort(devices[0],gsv2k1Ports[3] ,8 ,LogicAudioTx); AvApiAddPort(devices[0],gsv2k1Ports[4] ,20,VideoScaler); AvApiAddPort(devices[0],gsv2k1Ports[5] ,24,VideoColor); AvApiAddPort(devices[0],gsv2k1Ports[6] ,10,LogicAudioRx); // AvApiAddPort(devices[0],gsv2k1Ports[6], 28,VideoGen); // AvApiAddPort(devices[0],gsv2k1Ports[8] ,34,AudioGen); // AvApiAddPort(devices[0],gsv2k1Ports[9] ,36,ClockGen); /* 3.2 initialize port content */ #if AvEnableCecFeature gsv2k1Ports[1].content.cec-CecEnable 1; if(AudioStatus 0) gsv2k1Ports[1].content.cec-EnableAudioAmplifier AV_CEC_AMP_TO_DISABLE; else { gsv2k1Ports[1].content.cec-EnableAudioAmplifier AV_CEC_AMP_TO_ENABLE; gsv2k1Ports[1].content.cec-EnableARC AV_CEC_ARC_TO_INITIATE; } Cec_Tx_Audio_Status.Volume 30; Cec_Tx_Audio_Status.Mute 0; /* */ Cec_Tx_Audio_Status.AudioMode 1; /* Audio Mode is ON to meet ARC */ Cec_Tx_Audio_Status.AudioRate 1; /* 100% rate */ Cec_Tx_Audio_Status.AudioFormatCode AV_AUD_FORMAT_LINEAR_PCM; /* Follow Spec */ Cec_Tx_Audio_Status.MaxNumberOfChannels 2; /* Max Channels */ Cec_Tx_Audio_Status.AudioSampleRate 0x07; /* 32KHz/44.1KHz/48KHz */ Cec_Tx_Audio_Status.AudioBitLen 0x01; /* 16-bit only */ Cec_Tx_Audio_Status.MaxBitRate 0; /* default */ Cec_Tx_Audio_Status.ActiveSource 0; /* default */ #endif //------------------------- /* 3.3 init fsms */ AvApiInitDevice(devices[0]); AvApiPortStart(); /* 3.4 routing */ /* connect the port by video using AvConnectVideo */ /* connect the port by audio using AvConnectAudio */ /* connect the port by video and audio using AvConnectAV */ /* 3.4.1 video routing */ /* case 1: default routing RxA-TxA/TxB */ AvApiConnectPort(gsv2k1Ports[0], gsv2k1Ports[1], AvConnectAV); // AvApiConnectPort(gsv2k1Ports[0], gsv2k1Ports[2], AvConnectAV); AvApiConnectPort(gsv2k1Ports[0], gsv2k1Ports[3], AvConnectAudio); ///* case 2: audio insertion */ //AvApiConnectPort(gsv2k1Ports[0], gsv2k1Ports[1], AvConnectVideo); //AvApiConnectPort(gsv2k1Ports[0], gsv2k1Ports[2], AvConnectVideo); //AvApiConnectPort(gsv2k1Ports[9], gsv2k1Ports[1], AvConnectAudio); //AvApiConnectPort(gsv2k1Ports[9], gsv2k1Ports[2], AvConnectAudio); /* case 3: videogen and audiogen */ //AvApiConnectPort(gsv2k1Ports[6], gsv2k1Ports[1], AvConnectVideo); //AvApiConnectPort(gsv2k1Ports[6], gsv2k1Ports[2], AvConnectVideo); //AvApiConnectPort(gsv2k1Ports[7], gsv2k1Ports[1], AvConnectAudio); //AvApiConnectPort(gsv2k1Ports[7], gsv2k1Ports[2], AvConnectAudio); /* 3.4.2 ARC Connection, set after rx port connection to avoid conflict */ #if AvEnableCecFeature if(AudioStatus 1) { AvApiConnectPort(gsv2k1Ports[1], gsv2k1Ports[3], AvConnectAudio); } #endif /* 3.4.3 Internal Video Generator*/ #if AvEnableInternalVideoGen //gsv2k1Ports[6].content.video-timing.Vic 0x61; /* 4K60 */ gsv2k1Ports[6].content.video-timing.Vic 0x60; gsv2k1Ports[6].content.video-AvailableVideoPackets AV_BIT_AV_INFO_FRAME; gsv2k1Ports[6].content.video-Cd AV_CD_24; gsv2k1Ports[6].content.video-Y AV_Y2Y1Y0_RGB; gsv2k1Ports[6].content.vg-Pattern AV_PT_COLOR_BAR; #endif /* 3.4.4 Audio Insertion */ #if AvEnableAudioTTLInput gsv2k1Ports[3].content.audio-AudioMute 0; gsv2k1Ports[3].content.audio-AudFormat AV_AUD_I2S; gsv2k1Ports[3].content.audio-AudType AV_AUD_TYPE_ASP; gsv2k1Ports[3].content.audio-AudCoding AV_AUD_FORMAT_LINEAR_PCM; gsv2k1Ports[3].content.audio-AudMclkRatio AV_MCLK_256FS; gsv2k1Ports[3].content.audio-Layout 0; /* 2 channel Layout 0 */ gsv2k1Ports[3].content.audio-Consumer 0; /* Consumer */ gsv2k1Ports[3].content.audio-Copyright 0; /* Copyright asserted */ gsv2k1Ports[3].content.audio-Emphasis 0; /* No Emphasis */ gsv2k1Ports[3].content.audio-CatCode 0; /* Default */ gsv2k1Ports[3].content.audio-SrcNum 0; /* Refer to Audio InfoFrame */ gsv2k1Ports[3].content.audio-ChanNum 2; /* Audio Channel Count */ gsv2k1Ports[3].content.audio-SampFreq AV_AUD_FS_48KHZ; /* Sample Frequency */ gsv2k1Ports[3].content.audio-ClkAccur 0; /* Level 2 */ gsv2k1Ports[3].content.audio-WordLen 0x0B; /* 24-bit word length */ #endif // 8. 启动工作队列 gsv_running true; INIT_DELAYED_WORK(gsv_work, gsv_work_handler); schedule_delayed_work(gsv_work, msecs_to_jiffies(100)); dev_info(dev, GSV2001 driver loaded\n); return 0; } static int gsv_remove(struct i2c_client *client) { gsv_running false; cancel_delayed_work_sync(gsv_work); dev_info(client-dev, GSV2001 removed\n); return 0; } static const struct of_device_id gsv_of_match[] { { .compatible gsv,gsv2001 }, {} }; MODULE_DEVICE_TABLE(of, gsv_of_match); static struct i2c_driver gsv_driver { .driver { .name gsv2001, .of_match_table gsv_of_match, }, .probe gsv_probe, .remove gsv_remove, }; module_i2c_driver(gsv_driver); MODULE_LICENSE(GPL v2); MODULE_AUTHOR(board); MODULE_DESCRIPTION(GSV2001 HDMI Splitter Driver for RK3568);1.3 设备树文件在板级设备树文件中配置I2C需要注意从源码SDK中能看出设备地址是0x58这里是7位和I2C的协议有关7位地址位第八位是读写位也就是读的话是0xB1,写的话是0xB0,linux底层中I2C的接口都给处理好了。i2c3 { status okay; gsv2001: gsv200158 { compatible gsv,gsv2001; reg 0x58; reset-gpios gpio0 RK_PB6 GPIO_ACTIVE_LOW; status okay; }; };2.问题记录这里记录我调试过程中遇到的问题2.1 I2C读协议错误一开始用以下接口实现的I2C读导致restart信号变成了stop信号gsv芯片不响应。是通过示波器抓I2C总线上的波形对比gsv正常I2C通信才发现的这个错误gsv规格书中关于I2C时序也有列出这点。/* 从 16位 寄存器读一个字节 */ int gsv_i2c_read_reg(u32 dev_addr, u16 reg, u8 *val) { u8 buf[2]; buf[0] (reg 8) 0xFF; buf[1] reg 0xFF; if (i2c_master_send(g_client, buf, 2) 0) return -EIO; return i2c_master_recv(g_client, val, 1); }2.2 edid写入失败编写写接口时会申请tx_buf数组一般我们都喜欢申请256但GSV芯片驱动程序中会写edid加上寄存器地址长度正好257刚好超界导致写入失败。这里需要申请大一些。int ManI2cWrite(uint8_t dev_addr, uint16_t reg_addr, uint8_t *buf, int len) { uint8_t tx_buf[512]; int i; if (!g_i2c_client) return -EINVAL; if (len 509){ dev_info(g_i2c_client-dev, ManI2cWrite fail overSize\n); return -EINVAL; } tx_buf[0] (reg_addr 8) 0xFF; tx_buf[1] reg_addr 0xFF; for (i 0; i len; i) { tx_buf[2 i] buf[i]; } return i2c_master_send(g_i2c_client, tx_buf, len 2); }总结本文介绍了本人在工作过程中适配GSV2001芯片驱动时具体的修改项和遇到的问题为gsv同系列芯片在linux下适配提供了参考。程序包下载链接如下已测试可用。https://download.csdn.net/download/x150061/93278461

相关新闻

Linux系统最新版Docker安装与配置全流程指南

Linux系统最新版Docker安装与配置全流程指南

1. 项目概述:为什么需要一篇“最新版”Docker安装指南?如果你在Linux上折腾过Docker,大概率遇到过这样的场景:兴冲冲地打开官方文档,照着步骤一路敲命令,结果在某个环节卡住,报错信息看得一头雾…

2026/10/21 12:55:32 阅读更多 →
FreeSWITCH呼叫流程全解析:从SIP信令到媒体协商的实战指南

FreeSWITCH呼叫流程全解析:从SIP信令到媒体协商的实战指南

1. 项目概述:从“fs呼叫流程”说起 最近在调试一个基于FreeSWITCH的通信项目,又遇到了那个老生常谈但又无比核心的问题——呼叫流程。无论是刚接触的新手,还是像我这样摸爬滚打多年的老鸟,一旦涉及到SIP协议栈的交互、媒体协商或是…

2026/10/20 7:24:10 阅读更多 →
OpenClaw智能体框架:基于大语言模型的自动化工作流实战指南

OpenClaw智能体框架:基于大语言模型的自动化工作流实战指南

1. 项目概述:OpenClaw (Moltbot) 是什么? 如果你最近在关注AI智能体或者自动化工作流,大概率已经听过 OpenClaw 或者 Moltbot 这两个名字了。简单来说,OpenClaw是一个开源的、基于大语言模型的智能体(Agent&#x…

2026/10/22 14:50:10 阅读更多 →

最新新闻

Electron桌面应用开发实战:从环境搭建到打包发布全流程

Electron桌面应用开发实战:从环境搭建到打包发布全流程

做前端这些年,我大部分时间都在跟浏览器标签页打交道,直到第一次把桌面应用跑起来,才发现原来自己一直被限制在地址栏和刷新按钮围起来的框框里。Electron这个词,最开始是在某段时间频繁出现在同事的讨论里,一个用HTML…

2026/10/22 10:18:38 阅读更多 →
滑盖智能锁T109深度解析:结构原理、安装调试与故障排查

滑盖智能锁T109深度解析:结构原理、安装调试与故障排查

简介:亚太天能T109滑盖智能锁产品说明书是一份PDF格式的官方技术文档,主要面向智能锁安装人员、终端用户及售后维护者,帮助快速掌握产品安装、配置与常见故障处理。全包仅1个PDF文件,大小4.37MB,内容结构清晰&#xff…

2026/10/22 11:01:53 阅读更多 →
PMSM弱磁控制原理与Simulink建模:高速AGV驱动系统设计指南

PMSM弱磁控制原理与Simulink建模:高速AGV驱动系统设计指南

上个月我在调试一台高速AGV的驱动系统,整车要求空载跑到8m/s,电机转速已经拉到额定点,驱动器的输出电压也顶到了母线电压极限附近。再往上踩速度指令,转速纹丝不动,三相电流反而开始震荡。那会儿我的第一反应就是&…

2026/10/22 9:44:47 阅读更多 →
C++核心知识点:从内存管理到STL的实战指南

C++核心知识点:从内存管理到STL的实战指南

C 这门语言我前前后后折腾了十几年,用它写过嵌入式驱动、做过游戏服务端,也搭过基础组件库。每次看到新人一头扎进"C 核心知识点"这个搜索词,我其实挺感慨的——这门语言的难点从来不是语法多,而是知识点之间的耦合太深…

2026/10/22 10:42:00 阅读更多 →
T109滑盖智能锁怎么装?安装调试与故障排查全攻略

T109滑盖智能锁怎么装?安装调试与故障排查全攻略

简介:亚太天能T109滑盖智能锁产品说明书以PDF格式发布,适合智能锁用户、安装人员与售后维修人员阅读。内容围绕T109系列指纹密码刷卡锁展开,先介绍前面板、后面板、锁体、机械钥匙、电池盒盖等部件名称与功能,再给出完整安装步骤&…

2026/10/22 10:40:08 阅读更多 →
LLM知识降熵:从信息垄断到理解权下放

LLM知识降熵:从信息垄断到理解权下放

你有没有过这种经历:翻开源码注释、论文摘要或者一份专业报告,每个字都认识,连在一起却像天书。想找人聊聊,身边要么没人懂,要么懂的懒得跟你解释。后来我试着把同一段内容丢给一个大语言模型,几秒钟之后&a…

2026/10/22 10:56:37 阅读更多 →

日新闻

周新闻

基于GMM的语音识别系统原理与MATLAB实现详解

基于GMM的语音识别系统原理与MATLAB实现详解

说到基于高斯混合模型(GMM)的语音识别系统,很多人第一反应就是一堆数学公式,觉得门槛很高。但如果你真的在MATLAB里把它落地跑通,会发现核心其实就是三件事:把声音变成特征向量,用GMM给每个类别…

2026/10/22 1:47:45 阅读更多 →
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理这四个字听起来挺唬人,但落到具体操作上,无非就是让计算机按你的想法“摆弄”像素。我在一个模拟项目X里用了一套特别经典的基础处理流程:对图像做反白、改调色板、彩色转灰度,最后把像素数据导出成txt文件。单看每一…

2026/10/22 21:33:42 阅读更多 →
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

机器人大脑技术盘点:具身智能的感知、决策与数据闭环

如果你的信息流最近也天天刷到“机器人大脑”这个词,你会发现一个很有意思的现象:每个人说的“大脑”根本不是同一个东西。有人指的是大语言模型,有人指的是运动控制系统,还有人指的是能理解物理世界的端到端模型。在2026年这个时…

2026/10/22 5:12:39 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/22 22:56:44 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/22 22:56:12 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/22 19:06:46 阅读更多 →