某款扫地机器人源码分析1——指令数据解析处理部分

【硬件+代码】STM32F103_FreeRTOS_扫地机器人_带支持IAP的Bootloader 使用STM32F103芯片,FreeRTOS系统开发的扫地机器人项目,支持多种外设和功能,比如电机、按键、LED、ADC(电池温度检测、边刷电流检测和放电电流IBAT)、电池管理、陀螺仪、掉落检测、悬空传感器、碰撞传感器、超声波距离传感器、垃圾盒检测、捕获输入等。Bootloader支持IAP功能,可方便升级固件。一个学习STM32不可多得的项目,通过该项目可以熟悉STM32各种片内资源的使用。 阅读详情

前言

本文对一款基于stm32实现的扫地机器人程序进行分析。
链接: 某款stm32扫地机器人程序

扫地机器人通过串口接收或发送数据,数据包括控制端向扫地机器人发送的控制指令,扫地机器人向控制端反馈当前状态等。
从串口接收数据里解析出来的数据放在FR_Rx变量中,其结构体为:

/*帧接收记录*/
__packed typedef struct
{
    Frame_t tFrame;//帧信息
    u8 DataBuf[FRAME_DATA_MAX_LENGTH];//帧数据
    u8 NextFrameSeq;//下次应该的序列
    
    u8 ContinueErrNum;//连续错误次数
    bool IsStartReceive;//是否开始接收
    bool IsFrameNotProcess;//帧数据还未处理
    FrameErr_e FrameErrType;//帧错误类型
}Rx_FrameRecord;

这是控制端向扫地机器人发送的数据。

向控制端发送的数据,在放入串口发送缓冲区之前先放在变量FR_Tx里,其结构体为:

/*帧发送记录*/
__packed typedef struct
{
    Frame_t tFrame;//帧信息
    u8 DataBuf[FRAME_DATA_MAX_LENGTH];//帧数据
    u8 NextFrameSeq;//下次应该的序列
    bool IsSendOut;//是否发送了一帧数据?
    bool IsReceiveRespond;//是否接受到回应
}Tx_FrameRecord;

这是扫地机器人向控制端发送的数据。
由于FR_Rx和FR_Tx是全局变量,可见整个系统同一时刻只处理一条接收数据或者发送数据。

对串口接收数据解析,或者对串口发送数据组帧的任务都在Protocol文件夹里。

FrameHandle.c

void vFrameDataHandlerTask(void *p)

帧处理函数任务,将串口接收到的数据解析为协议帧数据。
处理步骤:
1、查看串口1缓冲区是否有新接收到的数据,并且FR_Rx里没有未被处理的接收数据,符合条件则对串口1接收数据进行解析。
2、从串口1接收缓冲区里对数据进行解析,执行代码为:

eFrame_Analy(ucUSART1ReceiveBuffer[ucUSART1ReadBufferIndex],length,&FR_Rx);//解析数据

其中
ucUSART1ReceiveBuffer[ucUSART1ReadBufferIndex]是串口1接收数据存放缓冲区。
length是该缓冲区中数据长度。
FR_Rx是解析出来的有效数据存放的接收数据帧。
3、判断接收到的数据帧类型不是回复帧,就通过

ucCode_RespondFrame(&FR_Tx,&FR_Rx,ucUSART1TrainsmitBuffer[ucWtiteDataToUSART1TransmitGrooveIndex]);

组一个接收数据的回复帧,并放到串口发送缓冲区中等待发送。

4、如果判断到接收数据帧里此刻有未被处理的数据帧,则根据帧类型进行分类数据。
5、调用

vFrameAutoResendByUsart1(&FR_Rx);

判断发送数据是否有回复帧,如果回复帧表示需要重发,或者超时未接收到回应帧(回复帧),则进行重发。
源码:

void vFrameDataHandlerTask(void *p)
{
    u8 length=0;
    while(1)
    {
        /*串口接收到数据 并且帧数据已经全部处理完毕*/
        if(ucUSART1_ReceiveMessageNumber && FR_Rx.IsFrameNotProcess == false)
        {
            length=ucUSART1ReceiveBufferLength[ucUSART1ReadBufferIndex];//获取接收数据的长度
            eFrame_Analy(ucUSART1ReceiveBuffer[ucUSART1ReadBufferIndex],length,&FR_Rx);//解析数据
            USART1ReceiveDataReadDone(  );//串口数据读取完毕
            
            /*成功接收到的不是回应帧*/
            if( FR_Rx.tFrame.FrameFunction != ffRespond  )
            {
                /*配置回应帧*/
                ucCode_RespondFrame(&FR_Tx,&FR_Rx,ucUSART1TrainsmitBuffer[ucWtiteDataToUSART1TransmitGrooveIndex]);
                /*发送回应帧到串口发送缓冲区*/
                ucUSART1TrainsmitLength[ucWtiteDataToUSART1TransmitGrooveIndex]=5+FR_Tx.tFrame.DataLength;
                WriteDataToUSART1TraismitBufferDone();
            }              
        }
        
        /*帧数据处理*/
        if(FR_Rx.IsFrameNotProcess)
        {
            switch(FR_Rx.tFrame.FrameFunction)
            {
                case ffRespond: //接收到的是回应帧
                    FR_Tx.IsReceiveRespond=true;//表示接收到回应帧
                    break;
                
                case ffCommand: //接收到的是命令帧
                    vCommandFrameHandle(&FR_Rx);
                    break;
                
                case ffData: //接收到的是数据帧
                    vDataFrameHandle(&FR_Rx);
                    break;
                
                case ffIdle: break;//接收到的是空闲帧,不处理
                case ffMax: break;
            }
            FR_Rx.IsFrameNotProcess=false;//标记数据已经处理
        }
        vFrameAutoResendByUsart1(&FR_Rx);
        vTaskDelay(5);
    }
}
void vCommandFrameHandle(Rx_FrameRecord *R)

命令帧处理函数,控制端在向扫地机器人发送数据帧前,会先发送一个命令帧,表明接下来发送的数据帧是什么类型。
所以根据命令帧类型对g_tLastCommand变量进行赋值,在数据帧处理时使用。
源码:

void vCommandFrameHandle(Rx_FrameRecord *R)
{
    
    if( R->tFrame.DataLength==1 )//命令字节只有一字节
    {
        switch(R->tFrame.FrameData[0])//查看命令
        {
            case UpdateFirmwareStart: //是开始更新固件命令
                g_tLastCommand=UpdateFirmwareStart;//标记命令
                ProductAppPassword=0;//产品密钥清理
                STMFLASH_Write(PASSWORD_ADDR,(u16*)&ProductAppPassword,2);//擦除产品秘钥
                ((void (*)())(*((u32 *)(0x08000004))))();//复位 进入bootloader程序
                break;
            
            case UpdateFirmwareDone: //是结束更新固件命令 firmware程序不会用到
                g_tLastCommand=UpdateFirmwareDone;
                break;
            
            case BehaviorControl: //是行为控制命令
                g_tLastCommand=BehaviorControl;//记录命令
                break;
            
            case RequestState://请求状态命令
                g_tLastCommand=RequestState;
                vRequestStateCommandHandle(&FR_Tx);//处理 请求状态命令
                break;
            
            case RouteCoord://线路坐标命令
                g_tLastCommand=RouteCoord;
                break;
        }
        
    }
}

void vDataFrameHandle(Rx_FrameRecord *R)

数据帧数据处理函数。根据g_tLastCommand变量,判断当前数据帧是什么类型数据,并调用相应的函数进行处理。
源码:

void vDataFrameHandle(Rx_FrameRecord *R)
{
    switch(g_tLastCommand)
    {
        case UpdateFirmwareStart://命令为开始更新固件 不会执行
            break;
        
        case UpdateFirmwareDone://命令为固件更新完毕 不会执行
            break;  
        
        case RequestState://命令为请求状态 不会执行
            break;
        
        case BehaviorControl://命令为行为控制
            vBehaviorControlHandle(R);//运行 行为控制处理函数
            break;

        case RouteCoord://线路坐标命令
            vRouteCoordHandle(R);//运行 线路坐标处理函数
            break;        
    }
}

void vBehaviorControlHandle(Rx_FrameRecord *R)

在数据帧处理函数中判断出该数据帧为行为控制指令,则调用该函数进行处理。
首先判断出行为控制指令的类型:停止、前进、后退、原地转弯、向左绕轴转弯、向右绕轴转弯。然后对g_sExpect_Angle变量和g_tRobotState.Robotstate.eDirection变量进行赋值。
在vBehaviorManageTask任务里会根据g_tRobotState.Robotstate.eDirection变量得知现在扫地机器人要执行什么动作,并结合g_sExpect_Angle变量设置机器人两个轮子的速度。
源码:

void vBehaviorControlHandle(Rx_FrameRecord *R)
{
    BehaviorControl_t *pBC = (BehaviorControl_t *)R->DataBuf;//数据赋值给结构体成员
    
    switch(pBC->Com)//控制类型
    {
        case bccStop ://停止  
            g_tRobotState.Robotstate.eDirection = zStop;
            break;
        
        case bccForward ://前进
            
            g_sExpect_Angle = pBC->TargetAngle*10;//获取目标角度 
            g_tRobotState.Robotstate.eDirection = zForward;
            break;
        
        case bccRetreat ://后退
            g_sExpect_Angle = pBC->TargetAngle*10;//获取目标角度 
            g_tRobotState.Robotstate.eDirection = zRetreat;
            break;
        
        case bccTurnRotate ://原地转弯
            g_sExpect_Angle = pBC->TargetAngle*10;//获取目标角度 
            g_tRobotState.Robotstate.eDirection = zRotate;
            break;
        
        case bccTurnLeft ://向左绕轴转弯
            g_sExpect_Angle = pBC->TargetAngle*10;//获取目标角度   
            g_tRobotState.Robotstate.eDirection = zTurnLeft;
            break;
            
        case bccTurnRight ://向右绕轴转弯
            g_sExpect_Angle = pBC->TargetAngle*10;//获取目标角度 
            g_tRobotState.Robotstate.eDirection = zTurnRight;
            break;
    }
}

void vRouteCoordHandle(Rx_FrameRecord *R)

接收到路线坐标数据的处理函数,这款扫地机器人没用到路线坐标。
源码:

void vRouteCoordHandle(Rx_FrameRecord *R)
{
    /*每次都会接受到5个 坐标点 。第一个是当前机器人坐标 一个 坐标X Y为8字节*/
    memcmp(&g_tRouteCoord,R->DataBuf,5*8);
}

void vRequestStateCommandHandle(Tx_FrameRecord *T)

接收到数据为请求状态的处理函数 ,请求状态数据是指控制端向机器人索要状态数据,控制端发一帧请求状态数据,机器人返回一帧状态数据。
对机器人的状态数据进行组帧,并放到串口数据发送缓冲区中。
源码:

void vRequestStateCommandHandle(Tx_FrameRecord *T)
{
    s16 loc_CurrentAngle;//当前角度
    u16 loc_Size;//用于记录数据大小
    
    if(T->IsSendOut == false)//若有数据发送 但是没有收到回应,则等待接收回应帧
    {   
        /*写入机器人全局信息*/
        loc_Size=sizeof g_tRobotState;
        memcpy(T->DataBuf,(void *)&g_tRobotState,loc_Size);

        /*写入机器人当前角度信息*/
        loc_CurrentAngle=CURRENT_ANGLE;
        loc_Size=sizeof loc_CurrentAngle;
        memcpy(T->DataBuf+sizeof g_tRobotState,&loc_CurrentAngle,loc_Size);
        
        /*写入数据到串口BUF 等待串口发送*/  
        loc_Size=(sizeof g_tRobotState)+(sizeof loc_CurrentAngle);//获取总数据字节
        if(loc_Size > FRAME_DATA_MAX_LENGTH)
        {
            loc_Size=FRAME_DATA_MAX_LENGTH;//数据溢出 标记为发送最大字节
            DEBUG("Tx Frame Over!\r\n");//输出信息
        }
        ucCode_DataFrame(&FR_Tx,T->DataBuf,loc_Size,ucUSART1TrainsmitBuffer[ucWtiteDataToUSART1TransmitGrooveIndex]); 
        ucUSART1TrainsmitLength[ucWtiteDataToUSART1TransmitGrooveIndex]=loc_Size+5;//数据字节+5个字节帧信息
        WriteDataToUSART1TraismitBufferDone();
        
        T->IsSendOut=true;//标记 已经发送了一帧数据
    }
}

void vFrameAutoResendByUsart1(Rx_FrameRecord *R)

1、根据发送数据帧FR_Tx的变量IsSendOut判断是否有数据发送出去了,如果有执行接下来的处理,没有则返回。
2、如果判断到回复帧,则把发送数据帧FR_Tx里的一些状态进行清除。
3、如果判断到超过1秒没收到回复帧,或者回复帧内容错误,则重发一次指令,并且发完清除
FR_Tx里的一些状态,也就是对于超时没有回复帧的数据只重发1次。

源码:

void vFrameAutoResendByUsart1(Rx_FrameRecord *R)
{
    static  bool  IsFirstIn=true;
    static  OS_TimeStruct TimFrameAutoResend;
    static  bool  IsRespondErr=false;
    
    if(FR_Tx.IsSendOut == true)//有发送数据
    {
        if(true == IsFirstIn)
        {
            TimFrameAutoResend=GetOSRunTimeNow();//第一次进入  获得进入时间
            IsFirstIn = false;
        }
        
        if(FR_Tx.IsReceiveRespond == true)//接收到回应帧
        {
            //回应帧反馈的是 帧正确
            if(R->tFrame.FrameFunction == ffRespond && R->tFrame.FrameData[0] == FrameSuccess)
            {
                FR_Tx.IsReceiveRespond=false;//清理 接收到回应帧
                FR_Tx.IsSendOut=false;//清零发送标志位
                IsFirstIn= true;//;重新标记第一次进入
            }else//数据有误 需要重新发送
            {
                IsRespondErr= true;
            }
        }
        /*超时还没有接收到回应帧 1秒 或者回应帧表示数据出错*/
        if(TimeOut == MultipleTimeoutCheck( &TimFrameAutoResend,0, 5, 0 ) || IsRespondErr)
        {
            /*发送指针回移动一位  重新发送刚刚缓存区的数据*/
            ucDMA1_Stream4TransmitGrooveIndex = ( (ucDMA1_Stream4TransmitGrooveIndex-1) > \
            USART1_TRANSMIT_GROOVE_SIZE ) ? USART1_TRANSMIT_GROOVE_SIZE : (ucDMA1_Stream4TransmitGrooveIndex-1);
            
            ucUSART1_TransmitMessageNumber++;//串口发送数据加1  表示重发数据
            
            FR_Tx.IsReceiveRespond=false;//清理 接收到回应帧
            FR_Tx.IsSendOut=false;//清零发送标志位
            IsFirstIn= true;//;重新标记第一次进入
        }
    }
}
扫地机器人完整代码 【代码】扫地机器人完整代码。 阅读详情

相关推荐

AI学习-langchain

也可以安装一下读取环境变量的依赖。

qq_62408075的博客 332

扫地机器人 源代码 企业级 扫地机器人源代码额外加一份iap升级

扫地机器人 源代码 企业级 扫地机器人源代码额外加一份iap升级,代码整齐,注释清楚。扫地机器人源代码额外加一份iap升级,代码整齐,注释清楚。

2301_77033770的博客 645

Freertos工程、stm32、某米扫地机器人

如题。程序驱动包含I2C、PWM、SPI、多路ADC与DMA、编码器输入捕获、外部中断、通信协议、IAP升级、PID、freertos操作系统等 代码注释清晰、代码规范 stm32f103ev工程 硬件驱动包括陀螺仪姿态bmi160、电源管理bq24773等

[C艹递归]深度优先扫地机器人

代码】[C艹递归]深度优先扫地机器人。

Left_Tale的博客 769

ROS 扫地机器人路径覆盖及控制源码

基于turtlesim小乌龟实现的ROS 扫地机器人路径覆盖算法,及差速控制。 使用方法: 1、下载源码 cd catkin_ws/src catkin_create_pkg turtlesim_cleaner cd catkin_ws catkin_make 2、运行 roscore //ROS Master rosrun turtlesim turtlesim_node //turtlesim rosrun turtlesim_cleaner robot_cleaner_node

小米扫地机器人工程源码程序STM32103 freeRTOS.zip

小米扫地机器人工程源码程序STM32103 freeRTOS,某米早起的扫地机器人的源码,使用的是STM32开发,freeRTOS系统,包含完整的工程源码,可以做为你的学习设计参考。

小米MiMo V2.5:Agent时代Token计费与端云协同的工程实践

大模型正从通用对话工具演进为具备感知、决策与执行能力的智能体(Agent),其核心挑战在于如何平衡推理质量、响应延迟与计算成本。Token计费模型的兴起,标志着AI服务从‘按次交互’迈向‘按量消耗’的经济理性阶段;而多模态传感器融合、端云协同推理、硬件直控API等技术,则共同支撑起真实场景下的毫秒级闭环。小米MiMo V2.5系列正是这一范式跃迁的典型代表——它不追求参数规模竞赛,而是通过源码级工具理解、轻量化多模态融合网络和Hardware API抽象,将大模型深度嵌入手机与IoT生态。对于智能硬件开发者

weixin_33804582的博客 679

扫地机器人源码及解释.zip_fairqx8_rightxv5_扫地_扫地 机器人_机器人

扫地机器人基本功能实现,内部各个模块驱动完成,能按照正常的弓字行路劲行走

25万+字干货|Java面试85题图解版:43道高频真题速查手册(八股+源码双吃透)

本文为25万字超全干货的Java面试85题图解完整版手册,精选43道大厂高频面试真题,摒弃传统死记硬背八股文模式,采用三句标准答案、生活化场景比喻、核心结构图解的方式,通俗讲解Java基础、并发、JVM、数据库、框架等核心考点。每道题目配套实战避坑指南、面试官高频追问与源码解析,实现八股背诵与底层源码双向吃透,适合校招、社招程序员考前速刷、长期复盘,轻松攻克Java面试重难点。

折哥|智能物流与Java实战,副高数据库工程师。深耕出版社物流WMS/OMS(线体/立库/VGA),也分享Java进阶与OMS电商对接。Oracle→PG实战派。相信沉淀可迁移能力,分享通用技术,不藏不虚。 795

STM32扫地机器人开源资料分享.zip

STM32扫地机器人开源资料分享。STM32扫地机器人开源资料分享。STM32扫地机器人开源资料分享。STM32扫地机器人开源资料分享。STM32扫地机器人开源资料分享。STM32扫地机器人开源资料分享。STM32扫地机器人开源资料分享。

SweepRobot:扫地机器人项目开源代码

扫地机器人 扫地机器人项目开源代码

机器人工程毕业设计☞开源学习(扫地)

机器人工程毕业设计☞区域覆盖(扫地) 提及一个中文案例,非常好的案例。 这里存到如下位置: zhangrelay / turtlebot3_cleaner · GitCode 扫地机器人仿真(机器人工程毕业设计)学习资料 功能包配置: sudo apt install ros-noetic-turtlebot3 ros-noetic-navigation ros-noetic-dwa-local-planner ros-noetic-slam-karto roslaunch clean_

zhangrelay的专栏 3796

STM32扫地机器人开源资料分享

STM32扫地机器人开源资料分享STM32扫地机器人开源资料分享STM32扫地机器人开源资料分享STM32扫地机器人开源资料分享STM32扫地机器人开源资料分享STM32扫地机器人开源资料分享STM32扫地机器人开源资料分享STM32扫地机器人开源资料分享STM32扫地机器人开源资料分享

深度强化学习之gym扫地机器人环境的搭建(持续更新算法,附源码,python实现)

深度强化学习之gym扫地机器人环境的搭建(持续更新算法,附源码,python实现) 包括扫地机器人的动画演示

showswoller的博客 2824

从病毒分析到安全研究:手把手教你用OD破解加壳程序的反调试机制

本文深入探讨了如何识别并绕过加壳程序的反调试机制,特别是针对使用IsDebuggerPresent等API检测的防护手段。通过实战案例和工具链配置,详细介绍了逆向工程中的关键技巧,包括内存补丁、硬件断点定位OEP等,帮助安全研究人员有效突破软件保护技术。

tgb345678的博客 824

FOC控制必看:单/双/三电阻电流采样方案全对比(附NXP实战避坑指南)

本文深入对比了FOC控制中单电阻、双电阻和三电阻电流采样方案的优劣与适用场景,重点剖析了采样时序、窗口与ADC转换的工程挑战。针对NXP平台,提供了解决采样窗口过窄的实战方案与配置指南,帮助工程师根据成本与性能需求做出最优选择,并规避常见设计陷阱。

n2o3p4的博客 413

大厂扫地机器人 源代码,freertos实时操作系统

大厂扫地机器人 源代码,freertos实时操作系统,企业级应用源码,适合需要学习嵌入式以及实时操作系统的工程师,32端代码能实现延边避障防跌 落充电等功能。软件驱动包括 IIC、PWM、SPI、多路ADC与DMA、编码器输入捕获、外部中断、通信协议、IAP升级、PID、freertos操作系统等。代码注释清晰、代码规范好、每个函数必有输入输出范围以及参数解释,便于阅读理解,很适合入门以及需要提升的工程师学习。提供一个固件以及一个升级版固件。爱吃地瓜丸子的黄油欧阳。

m0_73642613的博客 2265

基于Arduino UNO的OLED显示器使用方法x2(Arduino系列五)

Arduino使用OLED显示模块可以实现串口数据显示,还可以与其他模块联合使用,实现实时显示开发板实时数据。

LNN0212的博客 4171

开源硬件实现扫地机器人_开源硬件协会的创始人分享了她的故事

开源机器人车子软硬件 艾丽西亚·吉布(Alicia Gibb)对硬件黑客充满热情,她创立了并且目前正在运行开源硬件协会 (OSHWA)。 她还是ADA倡议委员会 , 防御性专利许可委员会和开放源代码生态委员会的成员 ,从信息学和图书馆学等多种背景开始了作为技术专家的工作。 Alicia之前曾在Bug Labs担任研究员和原型制作员,负责学术研究计划和R&D实验室。 她的工作令人着迷,她优雅地...

cumj63710的博客 1508

小红书图文笔记图像批量爬取:Python爬虫实战与反反爬策略全解析

在当今社交媒体盛行的时代,小红书作为中国领先的生活方式分享平台,积累了海量的优质图文内容。对于数据分析师、市场研究人员或内容创作者来说,能够高效获取这些数据具有重要意义。本文将详细介绍如何使用Python构建一个高效、稳定的小红书图文笔记图像批量爬取工具,涵盖最新技术栈和反反爬策略。本文详细介绍了如何使用Python构建一个高效、稳定的小红书图文笔记图像批量爬取系统。通过结合Playwright、aiohttp等现代工具,实现了从列表页采集到图片下载的完整流程。

2201_76125261的博客 2364

V4L2教程(1):Ubuntu V4L2开发环境搭建与设备探索

欢迎来到V4L2学习指南的第一篇!本文将带你从零开始,在Ubuntu系统上搭建完整的V4L2视频采集开发环境。无论你是想开发视频监控、视频会议还是机器视觉应用,掌握V4L2都是Linux视频开发的必经之路。 **本节学习目标**: - 理解V4L2的基本概念和架构 - 搭建Ubuntu下的V4L2开发环境 - 掌握v4l2-ctl等调试工具的使用 - 学会检测和配置USB摄像头设备

琅嬛福地 417

【免费下载】 探秘SweepRobot:一款智能扫地机器人开源项目

探秘SweepRobot:一款智能扫地机器人开源项目 在智能家居日益普及的时代,是一个值得关注的开源项目。它提供了一个基础框架,让开发者能够自定义和控制自己的智能扫地机器人,从而满足个性化的需求。 项目简介 SweepRobot是由爱好者开发的一个基于微控制器(MCU)的扫地机器人平台。它的核心是通过软件控制硬件,实现自动清扫功能。这个项目旨在降低创建智能扫地机器人的门槛,让更多的业余爱好者和专业...

gitblog_00099的博客 3119

YOLOv11 模型轻量化全流程:从剪枝到量化,打造移动端“极速检测利器”

将浮点模型量化为INT8模型,减少内存占用并加速推理。# 加载剪枝后的模型# 转换为TorchScript# 静态量化# 保存量化模型量化后模型推理速度可再提升20%,而mAP损失小于1%。

m0_64661770的博客 465

强化深度学习中利用时序差分法确定扫地机器人问题的最优解(附源码 超详细必看)

强化深度学习中利用时序差分法确定扫地机器人问题的最优解(附源码 超详细必看)

showswoller的博客 866

Spring AI Alibaba实战训练营-14基于A2A协议智能体应用开发指南

本文介绍了基于A2A协议的智能体应用开发流程,主要包括客户端和服务端两个模块的实现。关键技术包括A2A通信协议、Nacos服务发现、Spring AI Alibaba框架和DashScope通义千问API。开发步骤涵盖环境准备(JDK17、Maven、Nacos)、项目创建、依赖配置(重点引入spring-ai-alibaba相关组件)以及Nacos和DashScope的核心配置。整个系统架构采用客户端通过Nacos发现服务端Agent,再调用阿里云AI服务的模式,实现了AI能力的解耦与复用。

program哲学 505

【72】【OpenCV C++ & C#】 将cv::Mat 图像转换成imgINFO 传给c#在winform上显示,OpenCV C++如何将处理后的图像传给C#呢? 如何获取图像信息呢?

本文介绍了通过OpenCV C++处理图像后传递给C#的方法。首先定义了一个结构体imgINFO存储图像信息(数据指针、宽高、通道数等),然后通过getImgInfo函数将cv::Mat转换为该结构体。文章特别指出当图像宽度不能被4整除时可能出现失真问题,并给出了两种解决方案:调整输入图像或创建新的对齐图像。此外还解释了img.step和img.cols*img.elemSize()的关系,说明它们在大多数情况下是相等的。最后提到需要通过DLL将结构体传递给C#(具体方法参见其他文章)。

程序员,他们想的是什么?他们想的永远都是技术,他们崇尚的也永远都是技术。 697
上一篇: 【SoC设计指南 基于Arm Cortex-M】学习笔记1——AMBA
下一篇: git学习笔记1
inputA
博客等级 码龄7年 297粉丝 44原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值