【EtherCAT】FMMU和SM简介

ops/2024/10/22 11:05:01/

目录

一、简介

       1、 FMMU

       2、SM

        (1) 缓冲模式

        (2)邮箱模式

 3、FMMU将物理存储器映射到逻辑过程数据映射的配置原理

二、FMMU和SM在EtherCAT从站控制器的存储空间分配

三、FMMU和SM部分寄存器描述(LAN9253)

1、FMMU

2、SM

四、FMMU和SM的数据结构(soem主站)

 (1)  FMMU数据结构

 (2) SM数据结构

 五、FMMU和SM映射关系代码参考(soem)

六、其他相关链接


一、简介

       1、 FMMU

                Fieldbus Memory Management Unit,现场总线存储器管理单元, 通过内部地址映射逻辑地址转换为物理地址

                FMMU允许跨越多个从设备的数据段使用逻辑地址;一个数据报寻址几个任意分布的EtherCAT从站控制器内的数据。

                每个FMMU通道将一个连续的逻辑地址空间映射到从站的一个连续物理地址空间。

                EtherCAT从站控制器的FMMU支持逐位映射,支持的FMMU数量取决于EtherCAT从站控制器。

                FMMU支持的访问类型可配置为读、写或读/写。   

       2、SM

                Sync Manager, 同步管理;

                直接用EtherCAT从站控制器的存储器实现EtherCAT主站和本地应用程序之间交换数据,没有任何限制,这种直接通过内存通信存在缺点。所以需要SM来同步管理。SM可在EtherCAT主站本地应用程序之间实现一致且安全的数据交换,并生成中断来通知双方发生数据更改。

        SM管理DPRAM,保证了应用数据的一致性和安全性。

        SM由EtherCAT主站配置。

        SM支持两种通信模式。

        (1) 缓冲模式

                缓冲模式允许EtherCAT主站和本地应用程序随时访问通信缓冲区。

                缓冲模式通常应用与循环过程数据。

        (2)邮箱模式

                邮箱模式以握手机制实现数据交换,不会丢数据。

                邮箱模式通常用于应用程序层协议。

 3、FMMU将物理存储器映射到逻辑过程数据映射的配置原理

              

二、FMMU和SM在EtherCAT从站控制器的存储空间分配

      

三、FMMU和SM部分寄存器描述(LAN9253)

1、FMMU

        

2、SM

        

四、FMMU和SM的数据结构(soem主站)

 (1)  FMMU数据结构

/** record for FMMU */
typedef __packed struct
{uint32 LogStart;uint16 LogLength;uint8 LogStartbit;uint8 LogEndbit;uint16 PhysStart;uint8 PhysStartBit;uint8 FMMUtype;uint8 FMMUactive;uint8 unused1;uint16 unused2;} ec_fmmut;

   (2) SM数据结构

/** record for sync manager */
typedef __packed struct
{uint16 StartAddr;uint16 SMlength;uint32 SMflag;
} ec_smt;

五、FMMU和SM映射关系代码参考(soem)

/** Map all PDOs in one group of slaves to IOmap.
*
* @param[in]  context        = context struct
* @param[out] pIOmap     = pointer to IOmap  
* @param[in]  group      = group to map, 0 = all groups  
* @return IOmap size
*/
int ecx_config_map_group(ecx_contextt *context, void *pIOmap, uint8 group)
{uint16 slave, configadr;int Isize, Osize, BitCount, ByteCount, FMMUsize, FMMUdone;uint16 SMlength, EndAddr;uint8 BitPos;uint8 SMc, FMMUc;uint32 LogAddr = 0;uint32 oLogAddr = 0;uint32 diff;int nSM, rval;ec_eepromPDOt eepPDO;uint16 currentsegment = 0;uint32 segmentsize = 0;if ((*(context->slavecount) > 0) && (group < context->maxgroup)){  EC_PRINT("ec_config_map_group IOmap:%p group:%d\n \r", pIOmap, group);LogAddr = context->grouplist[group].logstartaddr;oLogAddr = LogAddr;BitPos = 0;context->grouplist[group].nsegments = 0;context->grouplist[group].outputsWKC = 0;context->grouplist[group].inputsWKC = 0;/* find output mapping of slave and program FMMU */for (slave = 1; slave <= *(context->slavecount); slave++){configadr = context->slavelist[slave].configadr;ecx_statecheck(context, slave, EC_STATE_PRE_OP, EC_TIMEOUTSTATE); /* check state change pre-op */EC_PRINT(" >Slave %d, configadr %x, state %2.2x\n \r",slave, context->slavelist[slave].configadr, context->slavelist[slave].state);/* execute special slave configuration hook Pre-Op to Safe-OP */if(context->slavelist[slave].PO2SOconfig) /* only if registered */{context->slavelist[slave].PO2SOconfig(slave);        }
if(context->slavelist[slave].proc_init) /* only if registered */
{context->slavelist[slave].proc_init(context,slave);        
}if (!group || (group == context->slavelist[slave].group)){  /* if slave not found in configlist find IO mapping in slave self */if (!context->slavelist[slave].configindex){Isize = 0;Osize = 0;if (context->slavelist[slave].mbx_proto & ECT_MBXPROT_COE) /* has CoE */{rval = 0;if (context->slavelist[slave].CoEdetails & ECT_COEDET_SDOCA) /* has Complete Access *//* read PDO mapping via CoE and use Complete Access */{rval = ecx_readPDOmapCA(context, slave, &Osize, &Isize);}if (!rval) /* CA not available or not succeeded */{/* read PDO mapping via CoE */rval = ecx_readPDOmap(context, slave, &Osize, &Isize);}EC_PRINT("  CoE Osize:%d Isize:%d\n \r", Osize, Isize);}if ((!Isize && !Osize) && (context->slavelist[slave].mbx_proto & ECT_MBXPROT_SOE)) /* has SoE */{/* read AT / MDT mapping via SoE */rval = ecx_readIDNmap(context, slave, &Osize, &Isize);context->slavelist[slave].SM[2].SMlength = htoes((Osize + 7) / 8);context->slavelist[slave].SM[3].SMlength = htoes((Isize + 7) / 8);EC_PRINT("  SoE Osize:%d Isize:%d\n \r", Osize, Isize);}if (!Isize && !Osize) /* find PDO mapping by SII */{memset(&eepPDO, 0, sizeof(eepPDO));Isize = (int)ecx_siiPDO(context, slave, &eepPDO, 0);EC_PRINT("  SII Isize:%d\n \r", Isize);              for( nSM=0 ; nSM < EC_MAXSM ; nSM++ ){  if (eepPDO.SMbitsize[nSM] > 0){  context->slavelist[slave].SM[nSM].SMlength =  htoes((eepPDO.SMbitsize[nSM] + 7) / 8);context->slavelist[slave].SMtype[nSM] = 4;EC_PRINT("    SM%d length %d\n \r", nSM, eepPDO.SMbitsize[nSM]);}  }  Osize = (int)ecx_siiPDO(context, slave, &eepPDO, 1);EC_PRINT("  SII Osize:%d\n \r", Osize);              for( nSM=0 ; nSM < EC_MAXSM ; nSM++ ){  if (eepPDO.SMbitsize[nSM] > 0){  context->slavelist[slave].SM[nSM].SMlength =  htoes((eepPDO.SMbitsize[nSM] + 7) / 8);context->slavelist[slave].SMtype[nSM] = 3;EC_PRINT("    SM%d length %d\n \r", nSM, eepPDO.SMbitsize[nSM]);}  }  }context->slavelist[slave].Obits = Osize;context->slavelist[slave].Ibits = Isize;EC_PRINT("     ISIZE:%d %d OSIZE:%d\n \r",context->slavelist[slave].Ibits, Isize,context->slavelist[slave].Obits);   }EC_PRINT("  SM programming\n \r"); if (!context->slavelist[slave].mbx_l && context->slavelist[slave].SM[0].StartAddr){ecx_FPWR(context->port, configadr, ECT_REG_SM0,sizeof(ec_smt), &(context->slavelist[slave].SM[0]), EC_TIMEOUTRET3);EC_PRINT("    SM0 Type:%d StartAddr:%4.4x Flags:%8.8x\n \r",context->slavelist[slave].SMtype[0],context->slavelist[slave].SM[0].StartAddr,context->slavelist[slave].SM[0].SMflags);  }if (!context->slavelist[slave].mbx_l && context->slavelist[slave].SM[1].StartAddr){ecx_FPWR(context->port, configadr, ECT_REG_SM1,sizeof(ec_smt), &context->slavelist[slave].SM[1], EC_TIMEOUTRET3);EC_PRINT("    SM1 Type:%d StartAddr:%4.4x Flags:%8.8x\n \r",context->slavelist[slave].SMtype[1],context->slavelist[slave].SM[1].StartAddr,context->slavelist[slave].SM[1].SMflags);  }/* program SM2 to SMx */for( nSM = 2 ; nSM < EC_MAXSM ; nSM++ ){  if (context->slavelist[slave].SM[nSM].StartAddr){/* check if SM length is zero -> clear enable flag */if( context->slavelist[slave].SM[nSM].SMlength == 0){context->slavelist[slave].SM[nSM].SMflags =htoel( etohl(context->slavelist[slave].SM[nSM].SMflags) & EC_SMENABLEMASK);}ecx_FPWR(context->port, configadr, ECT_REG_SM0 + (nSM * sizeof(ec_smt)),sizeof(ec_smt), &context->slavelist[slave].SM[nSM], EC_TIMEOUTRET3);EC_PRINT("    SM%d Type:%d StartAddr:%4.4x Flags:%8.8x\n \r", nSM,context->slavelist[slave].SMtype[nSM],context->slavelist[slave].SM[nSM].StartAddr,context->slavelist[slave].SM[nSM].SMflags);  }}if (context->slavelist[slave].Ibits > 7){context->slavelist[slave].Ibytes = (context->slavelist[slave].Ibits + 7) / 8;}if (context->slavelist[slave].Obits > 7){context->slavelist[slave].Obytes = (context->slavelist[slave].Obits + 7) / 8;}FMMUc = context->slavelist[slave].FMMUunused;SMc = 0;BitCount = 0;ByteCount = 0;EndAddr = 0;FMMUsize = 0;FMMUdone = 0;/* create output mapping */if (context->slavelist[slave].Obits){EC_PRINT("  OUTPUT MAPPING\n \r");/* search for SM that contribute to the output mapping */while ( (SMc < (EC_MAXSM - 1)) && (FMMUdone < ((context->slavelist[slave].Obits + 7) / 8))){  EC_PRINT("    FMMU %d\n \r", FMMUc);while ( (SMc < (EC_MAXSM - 1)) && (context->slavelist[slave].SMtype[SMc] != 3)) SMc++;EC_PRINT("      SM%d\n \r", SMc);context->slavelist[slave].FMMU[FMMUc].PhysStart =context->slavelist[slave].SM[SMc].StartAddr;SMlength = etohs(context->slavelist[slave].SM[SMc].SMlength);ByteCount += SMlength;BitCount += SMlength * 8;EndAddr = etohs(context->slavelist[slave].SM[SMc].StartAddr) + SMlength;while ( (BitCount < context->slavelist[slave].Obits) && (SMc < (EC_MAXSM - 1)) ) /* more SM for output */{SMc++;while ( (SMc < (EC_MAXSM - 1)) && (context->slavelist[slave].SMtype[SMc] != 3)) SMc++;/* if addresses from more SM connect use one FMMU otherwise break up in mutiple FMMU */if ( etohs(context->slavelist[slave].SM[SMc].StartAddr) > EndAddr ){break;}EC_PRINT("      SM%d\n \r", SMc);SMlength = etohs(context->slavelist[slave].SM[SMc].SMlength);ByteCount += SMlength;BitCount += SMlength * 8;EndAddr = etohs(context->slavelist[slave].SM[SMc].StartAddr) + SMlength;              }  /* bit oriented slave */if (!context->slavelist[slave].Obytes){  context->slavelist[slave].FMMU[FMMUc].LogStart = htoel(LogAddr);context->slavelist[slave].FMMU[FMMUc].LogStartbit = BitPos;BitPos += context->slavelist[slave].Obits - 1;if (BitPos > 7){LogAddr++;BitPos -= 8;}  FMMUsize = LogAddr - etohl(context->slavelist[slave].FMMU[FMMUc].LogStart) + 1;context->slavelist[slave].FMMU[FMMUc].LogLength = htoes(FMMUsize);context->slavelist[slave].FMMU[FMMUc].LogEndbit = BitPos;BitPos ++;if (BitPos > 7){LogAddr++;BitPos -= 8;}  }/* byte oriented slave */else{if (BitPos){LogAddr++;BitPos = 0;}  context->slavelist[slave].FMMU[FMMUc].LogStart = htoel(LogAddr);context->slavelist[slave].FMMU[FMMUc].LogStartbit = BitPos;BitPos = 7;FMMUsize = ByteCount;if ((FMMUsize + FMMUdone)> (int)context->slavelist[slave].Obytes){FMMUsize = context->slavelist[slave].Obytes - FMMUdone;}LogAddr += FMMUsize;context->slavelist[slave].FMMU[FMMUc].LogLength = htoes(FMMUsize);context->slavelist[slave].FMMU[FMMUc].LogEndbit = BitPos;BitPos = 0;}FMMUdone += FMMUsize;context->slavelist[slave].FMMU[FMMUc].PhysStartBit = 0;context->slavelist[slave].FMMU[FMMUc].FMMUtype = 2;context->slavelist[slave].FMMU[FMMUc].FMMUactive = 1;/* program FMMU for output */ecx_FPWR(context->port, configadr, ECT_REG_FMMU0 + (sizeof(ec_fmmut) * FMMUc),sizeof(ec_fmmut), &(context->slavelist[slave].FMMU[FMMUc]), EC_TIMEOUTRET3);context->grouplist[group].outputsWKC++;if (!context->slavelist[slave].outputs){  context->slavelist[slave].outputs =(uint8 *)(pIOmap) + etohl(context->slavelist[slave].FMMU[FMMUc].LogStart);context->slavelist[slave].Ostartbit =context->slavelist[slave].FMMU[FMMUc].LogStartbit;EC_PRINT("    slave %d Outputs %p startbit %d\n \r",slave,context->slavelist[slave].outputs,context->slavelist[slave].Ostartbit);}FMMUc++;}  context->slavelist[slave].FMMUunused = FMMUc;diff = LogAddr - oLogAddr;oLogAddr = LogAddr;if ((segmentsize + diff) > (EC_MAXLRWDATA - EC_FIRSTDCDATAGRAM)){context->grouplist[group].IOsegment[currentsegment] = segmentsize;if (currentsegment < (EC_MAXIOSEGMENTS - 1)){currentsegment++;segmentsize = diff;  }}else{segmentsize += diff;}}}  }if (BitPos){LogAddr++;oLogAddr = LogAddr;BitPos = 0;if ((segmentsize + 1) > (EC_MAXLRWDATA - EC_FIRSTDCDATAGRAM)){context->grouplist[group].IOsegment[currentsegment] = segmentsize;if (currentsegment < (EC_MAXIOSEGMENTS - 1)){currentsegment++;segmentsize = 1;  }}else{segmentsize += 1;}}  context->grouplist[group].outputs = pIOmap;context->grouplist[group].Obytes = LogAddr;context->grouplist[group].nsegments = currentsegment + 1;context->grouplist[group].Isegment = currentsegment;context->grouplist[group].Ioffset = segmentsize;if (!group){  context->slavelist[0].outputs = pIOmap;context->slavelist[0].Obytes = LogAddr; /* store output bytes in master record */}  /* do input mapping of slave and program FMMUs */for (slave = 1; slave <= *(context->slavecount); slave++){configadr = context->slavelist[slave].configadr;FMMUc = context->slavelist[slave].FMMUunused;if (context->slavelist[slave].Obits) /* find free FMMU */{while ( context->slavelist[slave].FMMU[FMMUc].LogStart ) FMMUc++;}SMc = 0;BitCount = 0;ByteCount = 0;EndAddr = 0;FMMUsize = 0;FMMUdone = 0;/* create input mapping */if (context->slavelist[slave].Ibits){EC_PRINT(" =Slave %d, INPUT MAPPING\n \r", slave);/* search for SM that contribute to the input mapping */while ( (SMc < (EC_MAXSM - 1)) && (FMMUdone < ((context->slavelist[slave].Ibits + 7) / 8))){  EC_PRINT("    FMMU %d\n \r", FMMUc);while ( (SMc < (EC_MAXSM - 1)) && (context->slavelist[slave].SMtype[SMc] != 4)) SMc++;EC_PRINT("      SM%d\n \r", SMc);context->slavelist[slave].FMMU[FMMUc].PhysStart =context->slavelist[slave].SM[SMc].StartAddr;SMlength = etohs(context->slavelist[slave].SM[SMc].SMlength);ByteCount += SMlength;BitCount += SMlength * 8;EndAddr = etohs(context->slavelist[slave].SM[SMc].StartAddr) + SMlength;while ( (BitCount < context->slavelist[slave].Ibits) && (SMc < (EC_MAXSM - 1)) ) /* more SM for input */{SMc++;while ( (SMc < (EC_MAXSM - 1)) && (context->slavelist[slave].SMtype[SMc] != 4)) SMc++;/* if addresses from more SM connect use one FMMU otherwise break up in mutiple FMMU */if ( etohs(context->slavelist[slave].SM[SMc].StartAddr) > EndAddr ){break;}EC_PRINT("      SM%d\n \r", SMc);SMlength = etohs(context->slavelist[slave].SM[SMc].SMlength);ByteCount += SMlength;BitCount += SMlength * 8;EndAddr = etohs(context->slavelist[slave].SM[SMc].StartAddr) + SMlength;              }  /* bit oriented slave */if (!context->slavelist[slave].Ibytes){  context->slavelist[slave].FMMU[FMMUc].LogStart = htoel(LogAddr);context->slavelist[slave].FMMU[FMMUc].LogStartbit = BitPos;BitPos += context->slavelist[slave].Ibits - 1;if (BitPos > 7){LogAddr++;BitPos -= 8;}  FMMUsize = LogAddr - etohl(context->slavelist[slave].FMMU[FMMUc].LogStart) + 1;context->slavelist[slave].FMMU[FMMUc].LogLength = htoes(FMMUsize);context->slavelist[slave].FMMU[FMMUc].LogEndbit = BitPos;BitPos ++;if (BitPos > 7){LogAddr++;BitPos -= 8;}  }/* byte oriented slave */else{if (BitPos){LogAddr++;BitPos = 0;}  context->slavelist[slave].FMMU[FMMUc].LogStart = htoel(LogAddr);context->slavelist[slave].FMMU[FMMUc].LogStartbit = BitPos;BitPos = 7;FMMUsize = ByteCount;if ((FMMUsize + FMMUdone)> (int)context->slavelist[slave].Ibytes){FMMUsize = context->slavelist[slave].Ibytes - FMMUdone;}LogAddr += FMMUsize;context->slavelist[slave].FMMU[FMMUc].LogLength = htoes(FMMUsize);context->slavelist[slave].FMMU[FMMUc].LogEndbit = BitPos;BitPos = 0;}FMMUdone += FMMUsize;if (context->slavelist[slave].FMMU[FMMUc].LogLength){  context->slavelist[slave].FMMU[FMMUc].PhysStartBit = 0;context->slavelist[slave].FMMU[FMMUc].FMMUtype = 1;context->slavelist[slave].FMMU[FMMUc].FMMUactive = 1;/* program FMMU for input */ecx_FPWR(context->port, configadr, ECT_REG_FMMU0 + (sizeof(ec_fmmut) * FMMUc),sizeof(ec_fmmut), &(context->slavelist[slave].FMMU[FMMUc]), EC_TIMEOUTRET3);/* add one for an input FMMU */context->grouplist[group].inputsWKC++;}  if (!context->slavelist[slave].inputs){  context->slavelist[slave].inputs =(uint8 *)(pIOmap) + etohl(context->slavelist[slave].FMMU[FMMUc].LogStart);context->slavelist[slave].Istartbit =context->slavelist[slave].FMMU[FMMUc].LogStartbit;EC_PRINT("    Inputs %p startbit %d\n \r",context->slavelist[slave].inputs,context->slavelist[slave].Istartbit);}FMMUc++;}  context->slavelist[slave].FMMUunused = FMMUc;diff = LogAddr - oLogAddr;oLogAddr = LogAddr;if ((segmentsize + diff) > (EC_MAXLRWDATA - EC_FIRSTDCDATAGRAM)){context->grouplist[group].IOsegment[currentsegment] = segmentsize;if (currentsegment < (EC_MAXIOSEGMENTS - 1)){currentsegment++;segmentsize = diff;  }}else{segmentsize += diff;}  }ecx_eeprom2pdi(context, slave); /* set Eeprom control to PDI */        ecx_FPWRw(context->port, configadr, ECT_REG_ALCTL, htoes(EC_STATE_SAFE_OP) , EC_TIMEOUTRET3); /* set safeop status */if (context->slavelist[slave].blockLRW){   context->grouplist[group].blockLRW++;                    }context->grouplist[group].Ebuscurrent += context->slavelist[slave].Ebuscurrent;}if (BitPos){LogAddr++;oLogAddr = LogAddr;BitPos = 0;if ((segmentsize + 1) > (EC_MAXLRWDATA - EC_FIRSTDCDATAGRAM)){context->grouplist[group].IOsegment[currentsegment] = segmentsize;if (currentsegment < (EC_MAXIOSEGMENTS - 1)){currentsegment++;segmentsize = 1;  }}else{segmentsize += 1;}}  context->grouplist[group].IOsegment[currentsegment] = segmentsize;context->grouplist[group].nsegments = currentsegment + 1;context->grouplist[group].inputs = (uint8 *)(pIOmap) + context->grouplist[group].Obytes;context->grouplist[group].Ibytes = LogAddr - context->grouplist[group].Obytes;if (!group){  context->slavelist[0].inputs = (uint8 *)(pIOmap) + context->slavelist[0].Obytes;context->slavelist[0].Ibytes = LogAddr - context->slavelist[0].Obytes; /* store input bytes in master record */}  EC_PRINT("IOmapSize %d\n \r", LogAddr - context->grouplist[group].logstartaddr);     return (LogAddr - context->grouplist[group].logstartaddr);}return 0;
}  

六、其他相关链接

EtherCAT从站开发要点-CSDN博客

【EtherCAT】COE对象字典与PDO映射简介-CSDN博客


http://www.ppmy.cn/ops/5528.html

相关文章

R:UpSet韦恩图制作

#安装UpSetR install.packages("UpSetR") library(UpSetR) #install.packages("UpSetR") library(UpSetR) library(Cairo) # 从CSV文件中读取数据 setwd("C:/Users/fordata/Desktop/研究生/第二个想法(16s肠型&#xff0b;宏基因组功能)/第二篇病毒组…

【网站项目】党员之家服务系统小程序

&#x1f64a;作者简介&#xff1a;拥有多年开发工作经验&#xff0c;分享技术代码帮助学生学习&#xff0c;独立完成自己的项目或者毕业设计。 代码可以私聊博主获取。&#x1f339;赠送计算机毕业设计600个选题excel文件&#xff0c;帮助大学选题。赠送开题报告模板&#xff…

2024年——区块链技术进入全新高度

BTC生态蓬勃发展&#xff0c;以太坊的L1和L2模块化重塑智能合约生态。RAAS&#xff08;区块链即服务&#xff09;、Depin、并行EVM等技术的崛起&#xff0c;为区块链应用提供了更高的性能和可扩展性。以太坊再质押成为焦点。技术创新与日俱进&#xff0c;一同探索这个充满活力的…

centos操作命令

CentOS操作命令包括但不限于以下几种&#xff1a; 系统操作命令&#xff1a; 关机、重启及登出&#xff1a; shutdown -h now&#xff1a;关闭系统。init 0 或 telinit 0&#xff1a;关闭系统。shutdown -r now&#xff1a;重启系统。reboot&#xff1a;重启系统。logout&…

【Java笔记】第4章:深入学习循环结构

前言1. 循环的理解2. while循环3. do...while循环4. for循环5. 循环的控制语句6. 循环的嵌套结语 ↓ 上期回顾: 【Java笔记】第3章&#xff1a;深入学习分支结构 个人主页&#xff1a;C_GUIQU 归属专栏&#xff1a;【Java学习】 ↑ 前言 各位小伙伴大家好&#xff01;上期小编…

程序员自由创业周记#32:新产品构思

程序员自由创业周记#32&#xff1a;新产品构思 新作品 我时常把自己看做一位木匠&#xff0c;有点手艺&#xff0c;能做一些作品养活自己。而 加一、Island Widgets、Nap 就是我的作品。 接下来在持续维护迭代的同时&#xff0c;要开启下一个作品的创造了。 其实早在2022的1…

python爬虫-----深入了解 requests 库下篇(第二十五天)

&#x1f388;&#x1f388;作者主页&#xff1a; 喔的嘛呀&#x1f388;&#x1f388; &#x1f388;&#x1f388;所属专栏&#xff1a;python爬虫学习&#x1f388;&#x1f388; ✨✨谢谢大家捧场&#xff0c;祝屏幕前的小伙伴们每天都有好运相伴左右&#xff0c;一定要天天…

深度学习之目标检测从入门到精通——json转yolo格式

记录点&#xff1a; import json import osname2id {person:0,helmet:1,Fire extinguisher:2,Hook:3,Gas cylinder:4}def convert(img_size, box):dw 1./(img_size[0])dh 1./(img_size[1])x (box[0] box[2])/2.0 - 1y (box[1] box[3])/2.0 - 1w box[2] - box[0]h box…