EtherCAT 开源主站 IGH 在 linux 开发板的移植和伺服通信测试

手边有一套正点原子linux开发板imax6ul,一直在吃灰,周末业余时间无聊,把EtherCAT的开源IGH主站移植到开发板上玩玩儿,搞点事情做。顺便学习研究下EtherCAT总线协议及其对伺服驱动器的运动控制过程。实验很有意思,这里总结下实验过程,分享给有需要的小伙伴。

前言

igh EtherCAT Master是一个用于控制EtherCAT网络的软件模块,它提供了主站功能。主站负责与从站进行通信和同步,控制从站的操作。igh EtherCAT Master具有丰富的功能和灵活的配置选项,可以满足不同应用场景的需求。它提供了一系列的API和工具,使得开发者可以方便地进行EtherCAT网络的开发和调试。

igh EtherCAT Master是用的最多且实时性最好的 EtherCAT 开源主站。很多公司项目软件主站都是用的它,有很多软件专利可以挖掘。一些公司的机器人主控四肢电机驱动器通信和运动板卡,采用的也是IgH 。基于IgH作产品开发,基本能满足大部分使用场景。

关于EtherCAT主站协议栈,目前有两大主流开源代码为SOEM(即支持Linux,又支持windows )和IgH EtherCAT Master只支持Linux )。

本文以IgH最新稳定版本1.6来移植,简单记录下IgH EtherCAT Master在嵌入式系统中的移植过程及主从站伺服驱动器通信测试。( [Linux 内核版本:Linux-4.1.15] )。

IgH官方介绍:

EtherCAT-Master | EtherLab

整个交叉编译过程很顺利,没遇到一点儿报错。本次移植仅是测试,简单起见使用通用的网卡驱动,性能上肯定不是最好。要想高性能一方面需要给内核打实时性补丁,一方面还需对特定的网卡驱动进行优化适配。源码里自带了一些网卡驱动,如8139和e1000网卡驱动,Igb(Intel Gigabit )以太网驱动程序。

8139和e1000是两种常见的网卡芯片,分别由Realtek和Intel生产。Realtek 8139(也称为RTL8139)是Realtek生产的一款常用的乙太网网卡芯片,广泛应用于早期的计算机和嵌入式系统中。Intel e1000系列是Intel生产的一组高性能千兆位乙太网控制器芯片,包括e1000、e1000e和82574等型号,适用于桌面计算机、服务器和嵌入式系统。这两种网卡芯片均具有集成的MAC(Media Access Control)功能,用于管理数据链路层的访问和控制,以及PHY(Physical Layer)功能,用于处理物理层的信号传输和解调。它们同时具备MAC和PHY功能。

移植准备

IGH最新稳定版1.6源码下载地址:

https://gitlab.com/etherlab.org/ethercat/-/archive/stable-1.6/ethercat-stable-1.6.tar.gz

准备Linux-4.1.15内核源码,(编译驱动模块需要) 我的路径:

/root/test/imax6ul/linux

开发板提供的gcc交叉编译工具链:

/opt/fsl-imx-x11/4.1.15-2.1.0/environment-setup-cortexa7hf-neon-poky-linux-gnueabi

如果还想要给内核打上实时性补丁包,可以在这找到:Index of /pub/linux/kernel/projects/rt/4.14/

#为内核源码打上实时补丁
cd linux
patch -p 1 -i ../patch-4.10.199-rt97.patch

至此,准备工作完成。 

源码编译过程

先加载编译环境变量,直接执行以下指令即可。

source /opt/fsl-imx-x11/4.1.15-2.1.0/environment-setup-cortexa7hf-neon-poky-linux-gnueabi

执行完成后, arm-poky-linux-gnueabi-gcc已经加入到环境变量中了。可以在命令行输出echo $CC试试看,输出了arm-poky-linux-gnueabi-gcc,说明环境已经生效了。

 编译主站程序和协议栈

# EtherCAT 源码存放目录为:/root/test/ethercat/ethercat-stable-1.6
# Linux-4.1.15 源码存放目录为:/root/test/imax6ul/linux/ linux-4.1.15tar -zxvf ethercat-stable-1.6.tar.gz	# 解压源码 /root/test/ethercat/ethercat-stable-1.6
cd ethercat-stable-1.6# --prefix是指定你下面make install时的安装目录,--with-linux-dir是指定你的linux内核目录
./configure --prefix=/root/test/ethercat/output --with-linux-dir=/root/test/imax6ul/linux --enable-8139too=no --enable-generic=yes --host=arm-poky-linux-gnueabimake	# 编译主站和协议栈源码make install #安装到指定目录

经过上面的交叉编译,只是编译出了主站协议栈库和自带主站工具及程序,但是这还不算完。

ethercat:可执行程序是用于配置和管理 EtherCAT 主站(IGH 主站)的命令行工具。

ethercatctl:是一个用于控制 EtherCAT Master 运行状态的命令行工具。它提供了启动、停止、重启 EtherCAT Master 等操作的命令,用于管理 EtherCAT Master 的运行。

经过上面的编译,编译出来的内容如下图所示:

库和头文件: 

linux内核驱动模块还没出来,所以直接是运行不起来的,还需要编译出内核网络驱动模块。

编译内核驱动模块

#编译网卡驱动模块
# 指定交叉编译工具,编译modules
make ARCH=arm CROSS_COMPILE=arm-poky-linux-gnueabi- modules 		# 编译通过会对应生成ethercat-stable-1.6/devices/ec_generic.ko和ethercat-stable-1.6/master/ec_master.ko
sudo make install		# 在该目录下生成output目录

成功编译出了ec_master.ko 和 ec_generic.ko的linux驱动模块。 

ec_master.ko:用于支持 EtherCAT 主站运行的 Linux 内核模块。它实现了 EtherCAT 主站协议栈,允许在 Linux 系统上与 EtherCAT 从站设备进行实时通信和数据交换。主要负责存储一些ethercat从站信息,管理domains域,管理从站配置等有关于ethercat系统的资源,在/etc/sysconfig/ethercat中配置的MASTER0_DEVICE会作为该模块参数传入主站模块,最终成为主站模块的mac使用网络地址,即master->macs;

ec_generic.ko,经由系统网络栈利用标准以太网 (Ethernet) 的网络驱动程序。

ec_generic,这个通用的驱动文件是在TCP/IP协议栈接口之上进行调用的,所以会走TCP/IP协议栈,会影响实时性。正式用应优化网卡驱动,在网卡驱动上直接支持IgH接口。

放到板子上运行

复制ec_generic.ko和ec_master.ko到/lib/modules/内核版本号,复制ethercat到usr/local/bin目录下。安装通用网卡驱动,配置rules,创建设备号。

操作步骤

# 在/root/test/ethercat目录下创建modules文件夹,并复制ec_generic.ko和ec_master.ko到modules下
mkdir -p output/modules
cp devices/ec_generic.ko output/modules/
cp master/ec_master.ko output/modules/# 将output文件夹打包,传输到开发板(nfs/tftp/scp)
tar -cjf output.tar.bz2 output/-------------------------------------------------------------------------------------------------------------------------------------
# 开发板上执行
tar -jxvf output.tar.bz2cp output/modules/ec_generic.ko /lib/modules/4.1.15
# 复制ec_master.ko到/lib/modules/内核版本号/ 
cp output/modules/ec_master.ko /lib/modules/4.1.15 # 内核版本可以通过uname -r 查看depmodln -fs output/etc/init.d/ethercat /etc/init.d/ # 创建链接,相比于复制节省内存空间
ln -fs output/bin/ethercat /usr/local/bin/mkdir /etc/sysconfig
ln -fs output/etc/sysconfig/ethercat /etc/sysconfig/# 配置rules,创建设备号
echo KERNEL==\"EtherCAT[0-9]*\", MODE=\"0664\" > /etc/udev/rules.d/99-EtherCAT.rules# 获取板子MAC地址
ifconfig
# eth2  Link encap:以太网  硬件地址 00:0c:29:01:69:aa-------------------------------------------------------------------------------------------------------------------------------------
# 启动EtherCAT
# 配置主站的MAC地址
modprobe ec_master main_devices=1E:ED:19:27:1A:B3 # 启动ethercat
/etc/init.d/ethercat start# 安装通用网卡驱动
insmod  output/modules/ec_generic.ko# 通过ethercat查看信息
Ethercat --help

运行测试

通过网线直连ethercat主从站,从站启动完成后,启动ethercat。

/etc/init.d/ethercat start

下面就可以使用 ethercat 工具来进行一些操作了。

sudo ethercat cstruct

ethercat 命令行

EtherCAT 命令行在 《EtherCAT IGH 1.52.pdf》中的 <7.1 Command-line Tool> 也有很详细的一个介绍。在编译和安装IGH的时候,如果不修改默认的编译参数,那么就是会提供 EtherCAT 命令行工具的。每个主站的实例都有生成一个字符设备,名字为:/dev/EtherCATx, 其中 x ∈ {0 . . . n}为主站实例的索引。

常用命令介绍

ethercat master

该命令行用来显示主站和以太网设备信息。

列出主站状态:

ethercat slaves

列出连接的从站:

ethercat cstruct
ethercat sdos

该命令行用来输出当前驱动器支持的所有的SDO信息。

举例:

@:~$ ethercat upload 0x2001 0x0000
0x03e8 1000

解析:读取从站0中索引号为 0x2001(16位),子索引号为00(8位)的SDO条目。返回的参数值为 1000。

注意:必须有从站连接才能使用此命令,不运行应用程序也可以使用。

 ethercat download

该命令行用以向指定的从站 SDO 中的子索引中写入相应的参数值。

例子:

向从站0的索引号为0x6060(16位),子索引号为00(8位)的地址写入参数值"0x08"。

@:~$ sudo ethercat download -t int16 -p 0 0x6060 00 08

有的SDO 可能是由于厂家的限制,不能写入参数。

@:~$ sudo ethercat download -t uint16 0x2008 0x0000 0x000f
SDO transfer aborted with code 0x08000021: Data cannot be transferred or stored to the application because of local control

注意:必须有从站连接才能使用此命令,不运行应用程序也可以使用。 

@:~$ ethercat sdos
SDO 0x1000, "Device type"0x1000:00, r-r-r-, uint32, 32 bit, "Device type"
SDO 0x1001, "Error register"0x1001:00, r-r-r-, uint8, 8 bit, "Error register"
SDO 0x1008, "Device name"0x1008:00, r-r-r-, string, 72 bit, "Device name"
SDO 0x1009, "Hardware version"0x1009:00, r-r-r-, string, 24 bit, "Hardware version"
SDO 0x100a, "Software version"0x100a:00, r-r-r-, string, 32 bit, "Software version"
SDO 0x1010, "store parameters"0x1010:00, r-r-r-, uint8, 8 bit, "SubIndex 000"0x1010:01, rwrwrw, uint32, 32 bit, "save all parameters"0x1010:02, rwrwrw, uint32, 32 bit, "save communication parameters"0x1010:03, rwrwrw, uint32, 32 bit, "save application parameters"0x1010:04, rwrwrw, uint32, 32 bit, "save manufacturer defined parameters"
..............
SDO 0x6007, "Abort_connection_option_code"0x6007:00, rwrwrw, int16, 16 bit, "Abort_connection_option_code"
SDO 0x603f, "errorcode"0x603f:00, r-r-r-, uint16, 16 bit, "errorcode"
SDO 0x6040, "controlword"0x6040:00, rwrwrw, uint16, 16 bit, "controlword"
SDO 0x6041, "statusword"0x6041:00, r-r-r-, uint16, 16 bit, "statusword"
..............
ethercat pdos

该命令行用来显示出同步管理器的参数和PDO分配和映射信息。

ethercat upload

该命令行用以读取指定从站相应PDO设定的参数值。

其他一些命令,参考:EtherCAT IGH 命令行介绍_igh ethercat-CSDN博客

@:~$ ethercat --helpalias      Write alias addresses.config     Show slave configurations.crc        CRC error register diagnosis.cstruct    Generate slave PDO information in C language.data       Output binary domain process data.debug      Set the master's debug level.domains    Show configured domains.download   Write an SDO entry to a slave.eoe        Display Ethernet over EtherCAT statictics.foe_read   Read a file from a slave via FoE.foe_write  Store a file on a slave via FoE.graph      Output the bus topology as a graph.ip         Set EoE IP parameters.master     Show master and Ethernet device information.pdos       List Sync managers, PDO assignment and mapping.reg_read   Output a slave's register contents.reg_write  Write data to a slave's registers.rescan     Rescan the bus.sdos       List SDO dictionaries.sii_read   Output a slave's SII contents.sii_write  Write SII contents to a slave.slaves     Display slaves on the bus.soe_read   Read an SoE IDN from a slave.soe_write  Write an SoE IDN to a slave.states     Request application-layer states.upload     Read an SDO entry from a slave.version    Show version information.xml        Generate slave information XML.Global options:--master  -m <master>  Comma separated list of mastersto select, ranges are allowed.Examples: '1,3', '5-7,9', '-3'.Default: '-' (all).--force   -f           Force a command.--quiet   -q           Output less information.--verbose -v           Output more information.--help    -h           Show this help.Numerical values can be specified either with decimal (no
prefix), octal (prefix '0') or hexadecimal (prefix '0x') base.Call 'ethercat <COMMAND> --help' for command-specific help.

测试效果

网上有一组测试效果,连接五个从站,主站单次收发数据的平均耗时以及实时性。测试主站单次收发数据的平均耗时的程序每隔 100 μs 发送并接收一次过程数据,如此每循环 10000 次记录一下当前时间,相邻两次记录的时间间隔减去其间空闲时间 100 μs × 10000 = 1 s 再除以收发次数 10000 便得到单次收发数据的平均耗时,使用三种不同的网卡驱动,三种情形下的大致结果如下表:

主站测试代码

#include <errno.h>
#include <signal.h>
#include <stdio.h>
#include <string.h>
#include <sys/resource.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>/****************************************************************************/#include "ecrt.h"/****************************************************************************/// Application parameters
#define FREQUENCY 100
#define PRIORITY 1// Optional features
#define CONFIGURE_PDOS  1/****************************************************************************/// EtherCAT
static ec_master_t *master = NULL;
static ec_master_state_t master_state = {};static ec_domain_t *domain1 = NULL;
static ec_domain_state_t domain1_state = {};
static ec_domain_t *domain2 = NULL;
static ec_domain_state_t domain2_state = {};static ec_slave_config_t *sc;
static ec_slave_config_state_t sc_ana_in_state = {};// Timer
static unsigned int sig_alarms = 0;
static unsigned int user_alarms = 0;/****************************************************************************/// process data
static uint8_t *domain1_pd = NULL;
static uint8_t *domain2_pd = NULL;#define BusCouplerPos  0, 0#define TI_AM3359ICE    0xE000059D, 0x54490001// offsets for PDO entries
static unsigned int off_dig_out2;
static unsigned int off_dig_in2;static unsigned int counter = 0;
static unsigned int blink = 0x00;/*****************************************************************************/#if CONFIGURE_PDOS
ec_pdo_entry_info_t slave_0_pdo_entries[] = {{0x7010, 0x00, 32},{0x6000, 0x00, 4*8},
};
ec_pdo_info_t slave_0_pdos[] = {{0x1601, 1, slave_0_pdo_entries + 0},{0x1a00, 1, slave_0_pdo_entries + 1},
};
static ec_sync_info_t slave_0_pdo_syncs[] = {{2, EC_DIR_OUTPUT, 1, slave_0_pdos + 0},{3, EC_DIR_INPUT,  1, slave_0_pdos + 1},{0xff}
};#endif/*****************************************************************************/void check_domain1_state(void)
{ec_domain_state_t ds;ecrt_domain_state(domain1, &ds);if (ds.working_counter != domain1_state.working_counter)printf("Domain1: WC %u.\n", ds.working_counter);if (ds.wc_state != domain1_state.wc_state)printf("Domain1: State %u.\n", ds.wc_state);domain1_state = ds;
}/*****************************************************************************/
void check_domain2_state(void)
{ec_domain_state_t ds;ecrt_domain_state(domain2, &ds);if (ds.working_counter != domain2_state.working_counter)printf("Domain2: WC %u.\n", ds.working_counter);if (ds.wc_state != domain2_state.wc_state)printf("Domain2: State %u.\n", ds.wc_state);domain2_state = ds;
}/*****************************************************************************/void check_master_state(void)
{ec_master_state_t ms;ecrt_master_state(master, &ms);if (ms.slaves_responding != master_state.slaves_responding)printf("%u slave(s).\n", ms.slaves_responding);if (ms.al_states != master_state.al_states)printf("AL states: 0x%02X.\n", ms.al_states);if (ms.link_up != master_state.link_up)printf("Link is %s.\n", ms.link_up ? "up" : "down");master_state = ms;
}/*****************************************************************************/void check_slave_config_states(void)
{ec_slave_config_state_t s;ecrt_slave_config_state(sc, &s);if (s.al_state != sc_ana_in_state.al_state)printf("AnaIn: State 0x%02X.\n", s.al_state);if (s.online != sc_ana_in_state.online)printf("AnaIn: %s.\n", s.online ? "online" : "offline");if (s.operational != sc_ana_in_state.operational)printf("AnaIn: %soperational.\n",s.operational ? "" : "Not ");sc_ana_in_state = s;
}/*****************************************************************************/void cyclic_task()
{// receive process dataecrt_master_receive(master);ecrt_domain_process(domain1);ecrt_domain_process(domain2);// check process data state (optional)check_domain1_state();check_domain2_state();//    if (counter) {
//        counter--;
//    } else { // do this at 1 Hzcounter = FREQUENCY;// calculate new process datablink ++;// check for master state (optional)check_master_state();// check for islave configuration state(s) (optional)check_slave_config_states();//	printf("AnaIn: value=0x%x\n", EC_READ_U32(domain2_pd + off_dig_in2));printf("AnaIn: value=0x%x\n", EC_READ_U32(domain2_pd + off_dig_in2));
//printf("AnaIn: value=0x%x\n", EC_READ_U32(domain2_pd + off_dig_in2 + 4));EC_WRITE_U32(domain1_pd + off_dig_out2, blink);
//		printf("AnaIn: value=0x%x\n", EC_READ_U32(domain1_pd + off_dig_out2));
//    }// send process dataecrt_domain_queue(domain1);ecrt_domain_queue(domain2);ecrt_master_send(master);
}/****************************************************************************/void signal_handler(int signum) {switch (signum) {case SIGALRM:sig_alarms++;break;}
}/****************************************************************************/int main(int argc, char **argv)
{struct sigaction sa;struct itimerval tv;master = ecrt_request_master(0);if (!master)return -1;domain1 = ecrt_master_create_domain(master);if (!domain1)return -1;domain2 = ecrt_master_create_domain(master);if (!domain2)return -1;#if CONFIGURE_PDOSif (!(sc = ecrt_master_slave_config(master, BusCouplerPos, TI_AM3359ICE))) {fprintf(stderr, "Failed to get slave configuration.\n");return -1;}if (ecrt_slave_config_pdos(sc, EC_END, slave_0_pdo_syncs)) {fprintf(stderr, "Failed to configure PDOs.\n");return -1;}printf("Configuring PDOs...\n");// Create configuration for bus coupleroff_dig_out2 = ecrt_slave_config_reg_pdo_entry(sc,0x7010, 0, domain1, NULL);if (off_dig_out2 < 0)return -1;off_dig_in2 = ecrt_slave_config_reg_pdo_entry(sc,0x6000, 0, domain2, NULL);if (off_dig_in2 < 0)return -1; 
#endifprintf("Activating master...\n");if (ecrt_master_activate(master))return -1;if (!(domain1_pd = ecrt_domain_data(domain1))) {return -1;}if (!(domain2_pd = ecrt_domain_data(domain2))) {return -1;}sa.sa_handler = signal_handler;sigemptyset(&sa.sa_mask);sa.sa_flags = 0;if (sigaction(SIGALRM, &sa, 0)) {fprintf(stderr, "Failed to install signal handler!\n");return -1;}printf("Starting timer...\n");tv.it_interval.tv_sec = 0;tv.it_interval.tv_usec = 1000000 / FREQUENCY;tv.it_value.tv_sec = 0;tv.it_value.tv_usec = 2000;if (setitimer(ITIMER_REAL, &tv, NULL)) {fprintf(stderr, "Failed to start timer: %s\n", strerror(errno));return 1;}printf("Started.\n");while (1) {pause();while (sig_alarms != user_alarms) {cyclic_task();user_alarms++;}}return 0;
}/****************************************************************************//***********IGH demo编译*****************/
arm-linux-gnueabi-gcc main.c -o ethercat_test -I../../ethercat/include/ -L../..ethercat/lib -lethercat

IGH在Linux应用空间的其他使用

参考EtherCAT源码下的example。

git clone https://gitee.com/wllw7176/MyEthercat-IGH-1.5.2.git

 参考EtherCAT二次开发的源代码

其他资源

EtherCAT使用与解析-ethercat系统内核模块加载与初始化操作_ec_generic.ko-CSDN博客

https://www.cnblogs.com/wujingcqu/p/16295570.html

https://blog.51cto.com/u_15858333/6406909

IgH详解 一、概述-CSDN博客

EtherCAT设备协议详解二、EtherCAT状态机及配置流程-CSDN博客

在x86-64和arm64 Linux上调试IgH EtherCAT主站软件以及实现星形走线连接多从站 - 知乎

ethercatpack/mytest/test_ethercat.c · wllw7176_gitee/MyEthercat-IGH 1.5.2 - Gitee.com

https://pwl999.blog.csdn.net/article/details/109397917

IgH EtherCAT主站开发案例分享——基于NXP i.MX 8M Mini - 知乎

开源工业以太网现场总线协议栈汇总_soes从站模拟器-CSDN博客

raspberry pi RT-Linux平台搭建IgH环境_一种用于igh的网络驱动系统及方法与流程-CSDN博客

EtherCAT主站IgH解析(一)--主站初始化、状态机与EtherCAT报文_igh ethercat-CSDN博客

EtherCAT IGH 命令行介绍_igh ethercat-CSDN博客

LinuxCNC搭配Igh EtherCat Master开源Ethercat主站通讯控制测试_linuxcnc igh-CSDN博客

【虹科干货】使用Profishark进行EtherCAT主站性能测试 – 宏网络安全信息门户网站2

基于Zynq平台的igh EtherCAT主站的配置和使用方法,包括Preempt RT和Xenomai两种实时内核的介绍和配置示例_ethercat1.5.2中文-CSDN博客

https://www.cnblogs.com/tdyizhen1314/p/17628400.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/543944.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

vite打包时发布时,放在服务器的二级目录中

方式一 hash模式 如果我们的站点根目录为 public , 我们访问的时候使用的是 http://www.abc.com/ 访问到了站点的根目当&#xff0c;现在我们要访问 http://www.abc.com/mysite/#/ 配置如下 修改 vite.config.js base:“/mysite/” 修改 router中的配置 上面的步骤完成&…

RocketMQ学习笔记四(黑马)项目

课程地址&#xff1a; 1.Rocket第二章内容介绍_哔哩哔哩_bilibili &#xff08;视频35~88&#xff0c;搭建了一个电商项目&#xff09; 待学&#xff0c;待完善。

Microsoft Visio 编辑属性值

Microsoft Visio 编辑属性值 1. 编辑属性值References 1. 编辑属性值 单击长度或高度位置&#xff0c;弹出形状的各属性值&#xff0c;点击编辑对应的属性值。 ​ References [1] Yongqiang Cheng, https://yongqiang.blog.csdn.net/

创业板指399006行情数据API接口

# 测试&#xff1a;返回不超过10条数据&#xff08;2年历史&#xff09; https://tsanghi.com/api/fin/index/CHN/daily?tokendemo&ticker399006&order2Python示例 import requestsurl f"https://tsanghi.com/api/fin/index/CHN/daily?tokendemo&ticker399…

win10 + cpu + pycharm + mindspore

MindSpore是华为公司自研的最佳匹配昇腾AI处理器算力的全场景深度学习框架。 1、打开官网&#xff1a; MindSpore官网 2、选择以下选项&#xff1a; 3、创建conda 环境&#xff0c;这里python 选择3.9.0&#xff0c;也可以选择其他版本&#xff1a; conda create -c conda-…

flink1.18.0 自定义函数 接收row类型的参数

比如sql中某字段类型 array<row<f1 string,f2 string,f3 string,f4 bigint>> 现在需要编写 tableFunction 需要接受的参数如上 解决方案 用户定义函数|阿帕奇弗林克 --- User-defined Functions | Apache Flink

【List集合】List接口源码解读一(ArrayList)

目录 前言 1. List接口的基本信息 2. ArrayList 2.1.ArrayList 的基本信息 2.2. ArrayList 的构造方法 2.2.1 ArrayList 的构造方法一 2.2.2 ArrayList 的构造方法二 2.2.3 ArrayList 的构造方法三 2.3 ArrayList 的扩容方式 总结 前言 Java 语言由于其跨平台、社区良…

代码学习记录21--回溯算法第二天

随想录日记part21 t i m e &#xff1a; time&#xff1a; time&#xff1a; 2024.03.16 主要内容&#xff1a;今天主要是结合类型的题目加深对回溯算法的理解&#xff1a;1&#xff1a;组合总和&#xff1b;2&#xff1a;电话号码的字母组合 216.组合总和III17.电话号码的字母…

Docker----Dockerfile构建微服务镜像

目录 一、关键步骤 二、具体步骤 1、准备后端jar包(这里以java后端演示) 2、编写Dockerfile 3、构建镜像 4、运行镜像容器 5、测试是否成功 一、关键步骤 1、准备后端jar包(这里以java后端演示) 2、编写Dockerfile 3、构建镜像 4、运行镜像容器 5、测试是否成功 二…

阅读 - 二维码扫码登录原理

在日常生活中&#xff0c;二维码出现在很多场景&#xff0c;比如超市支付、系统登录、应用下载等等。了解二维码的原理&#xff0c;可以为技术人员在技术选型时提供新的思路。对于非技术人员呢&#xff0c;除了解惑&#xff0c;还可以引导他更好地辨别生活中遇到的各种二维码&a…

WebGIS之实现查询地区天气并让地区高亮

一.预览>> 二.思路>> 根据搜索框的内容来进行页面视角的切换&#xff0c;对应的地区高亮&#xff0c;右边有关天气的地方实时更新&#xff0c;并且因为代码体量非常小&#xff0c;并没有选择在框架下完成。直接一个html文件搞定了&#xff0c;但实际上还是有一些坑…

PMP的学习方法

PMBOK编撰了管理项目需要的49个过程&#xff08;输入、工具技术、输出&#xff09;。工具技术文件&#xff0c;林林总总百余个。第一部分&#xff0c;按照十大知识领域顺序从前到后编排&#xff1b;第二部分&#xff0c;按照五大过程组顺序重新编排了一遍。 一&#xff0c;PMB…