基于DWC_ether_qos的以太网驱动开发-LWIP的ICMP模块介绍与PING收发测试

原创 嵌入式Lee 2023-09-18 17:45

一. 前言

ICMPInternet Control Message Protocol因特网控制消息协议。

ICMP是网络层协议,IP不可分割的一部分。

ICMP用于报告数据报处理中的错误,比如以下情况下时发送ICMP消息:当数据报无法到达其目的地时,当网关没有转发数据报的缓冲能力时,以及当网关可以指示主机在较短的路由上发送数据时。

互联网协议的设计并不是绝对可靠的。ICMP这些控制消息的目的是提供有关通信环境中问题的反馈,而不是使IP可靠。不能确保数据报传递或控制消息返回一些数据报可能无法送达时也没有任何丢失报告。如果需要可靠的通信,则使用IP的更高级别协议必须实现其自己的可靠性程序。

ICMP消息通常报告数据报处理中的错误,且不发送关于ICMP消息的ICMP消息,否则消息会无限递归。此外,ICMP消息只发送关于处理分段数据报的零分段时的错误。(片段零的片段offeset等于零)。

参考

RFC 792

https://www.iana.org/assignments/icmp-parameters/icmp-parameters.xhtml

二. ICMP消息格式

ICMP消息格式

ICMP 的报文格式来说,ICMP IP 的上层协议,他是在IP报的基础上再添加ICMP报格式。但是 ICMP 是分担了 IP 的一部分功能。所以,他也被认为是与 IP 同层的协议。

 

我们这里只关注ICMP部分,ICMP由首部和数据两部分组成,如下

区域

类型

Type

代码

Code

校验和

Checksum

字节大小

1

1

2

区域

首部数据,根据类型不一样而不一样,对于ping拆为了16位的ID16位的序列号

字节大小

4

区域

ICMP数据部分

字节大小

类型不同长度不同

TypeCode如下表

类型TYPE

代码CODE

用途|描述 Description

查询类Query

差错类Error

0

0

Echo Reply——回显应答(Ping应答)

x


3

0

Network Unreachable——网络不可达


x

3

1

Host Unreachable——主机不可达


x

3

2

Protocol Unreachable——协议不可达


x

3

3

Port Unreachable——端口不可达


x

3

4

Fragmentation needed but no frag. bit set——需要进行分片但设置不分片比特


x

3

5

Source routing failed——源站选路失败


x

3

6

Destination network unknown——目的网络未知


x

3

7

Destination host unknown——目的主机未知


x

3

8

Source host isolated (obsolete)——源主机被隔离(作废不用)


x

3

9

Destination network administratively prohibited——目的网络被强制禁止


x

3

10

Destination host administratively prohibited——目的主机被强制禁止


x

3

11

Network unreachable for TOS——由于服务类型TOS,网络不可达


x

3

12

Host unreachable for TOS——由于服务类型TOS,主机不可达


x

3

13

Communication administratively prohibited by filtering——由于过滤,通信被强制禁止


x

3

14

Host precedence violation——主机越权


x

3

15

Precedence cutoff in effect——优先中止生效


x

4

0

Source quench——源端被关闭(基本流控制)



5

0

Redirect for network——对网络重定向



5

1

Redirect for host——对主机重定向



5

2

Redirect for TOS and network——对服务类型和网络重定向



5

3

Redirect for TOS and host——对服务类型和主机重定向



8

0

Echo request——回显请求(Ping请求)

x


9

0

Router advertisement——路由器通告



10

0

Route solicitation——路由器请求



11

0

TTL equals 0 during transit——传输期间生存时间为0


x

11

1

TTL equals 0 during reassembly——在数据报组装期间生存时间为0


x

12

0

IP header bad (catchall error)——坏的IP首部(包括各种差错)


x

12

1

Required options missing——缺少必需的选项


x

13

0

Timestamp request (obsolete)——时间戳请求(作废不用)

x


14


Timestamp reply (obsolete)——时间戳应答(作废不用)

x


15

0

Information request (obsolete)——信息请求(作废不用)

x


16

0

Information reply (obsolete)——信息应答(作废不用)

x


17

0

Address mask request——地址掩码请求

x


18

0

Address mask reply——地址掩码应答



使用wirshark协助解析

 

 

三. LWIPICMP相关代码分析

这里只看IPV4相关的,IPV6下也有对应的实现。

ipv4/icmp.c

icmp.h

3.1调试打印

可以配置宏ICMP_DEBUG,使能调试打印,一遍跟踪对应的程序处理过程。

lwipopts.h中配置

#define ICMP_DEBUG LWIP_DBG_ON

3.2数据结构

实现了以下Type

#define ICMP_ER   0    /* echo reply */
#define ICMP_DUR 3 /* destination unreachable */
#define ICMP_SQ 4 /* source quench */
#define ICMP_RD 5 /* redirect */
#define ICMP_ECHO 8 /* echo */
#define ICMP_TE 11 /* time exceeded */
#define ICMP_PP 12 /* parameter problem */
#define ICMP_TS 13 /* timestamp */
#define ICMP_TSR 14 /* timestamp reply */
#define ICMP_IRQ 15 /* information request */
#define ICMP_IR 16 /* information reply */
#define ICMP_AM 17 /* address mask request */
#define ICMP_AMR 18 /* address mask reply */

定义了头的数据结构

struct icmp_hdr {
PACK_STRUCT_FLD_8(u8_t type);
PACK_STRUCT_FLD_8(u8_t code);
PACK_STRUCT_FIELD(u16_t chksum);
PACK_STRUCT_FIELD(u32_t data);
} PACK_STRUCT_STRUCT;

如果四echo则,ICMP首部后面4字节数据拆分成id和序列号

struct icmp_echo_hdr {
PACK_STRUCT_FLD_8(u8_t type);
PACK_STRUCT_FLD_8(u8_t code);
PACK_STRUCT_FIELD(u16_t chksum);
PACK_STRUCT_FIELD(u16_t id);
PACK_STRUCT_FIELD(u16_t seqno);
} PACK_STRUCT_STRUCT;

3.3输入数据流

关键代码是icmp_input

ethernet_input->Type=0x0800 ip4_input-> Protocol=0x01 icmp_input

通过switch处理各种类型

switch (type) {
case ICMP_ER:

比如对于收到别人的ping请求就是进入

case ICMP_ECHO:

如果是多播地址不响应

然后检查ICMP头部至少要8字节。

然后检查checksum

最后调用ip4_output_if发送响应包。

3.4输出数据流

icmp_dest_unreach

icmp_time_exceeded

都是调用

icmp_send_response

3.5发送PING

收到响应进入icmp_input

  case ICMP_ER:
/* This is OK, echo reply might have been parsed by a raw PCB
(as obviously, an echo request has been sent, too). */
MIB2_STATS_INC(mib2.icmpinechoreps);
break

发送ping可以裸机可以使用raw PCB,带OS可以使用socket实现

详见ping.c/h

#include "lwip/opt.h"
#if LWIP_RAW /* don't build if not configured for use in lwipopts.h */
#include "ping.h"
#include "lwip/mem.h"#include "lwip/raw.h"#include "lwip/icmp.h"#include "lwip/netif.h"#include "lwip/sys.h"#include "lwip/timeouts.h"#include "lwip/inet_chksum.h"#include "lwip/prot/ip4.h"
#if PING_USE_SOCKETS#include "lwip/sockets.h"#include "lwip/inet.h"#include #endif /* PING_USE_SOCKETS */

/** * PING_DEBUG: Enable debugging for PING. */#ifndef PING_DEBUG#define PING_DEBUG LWIP_DBG_ON#endif
/** ping receive timeout - in milliseconds */#ifndef PING_RCV_TIMEO#define PING_RCV_TIMEO 1000#endif
/** ping delay - in milliseconds */#ifndef PING_DELAY#define PING_DELAY 1000#endif
/** ping identifier - must fit on a u16_t */#ifndef PING_ID#define PING_ID 0xAFAF#endif
/** ping additional data size to include in the packet */#ifndef PING_DATA_SIZE#define PING_DATA_SIZE 32#endif
/** ping result action - no default action */#ifndef PING_RESULT#define PING_RESULT(ping_ok)#endif
/* ping variables */static const ip_addr_t* ping_target;static u16_t ping_seq_num;#ifdef LWIP_DEBUGstatic u32_t ping_time;#endif /* LWIP_DEBUG */#if !PING_USE_SOCKETSstatic struct raw_pcb *ping_pcb;#endif /* PING_USE_SOCKETS */
/** Prepare a echo ICMP request */static voidping_prepare_echo( struct icmp_echo_hdr *iecho, u16_t len){ size_t i; size_t data_len = len - sizeof(struct icmp_echo_hdr);
ICMPH_TYPE_SET(iecho, ICMP_ECHO); ICMPH_CODE_SET(iecho, 0); iecho->chksum = 0; iecho->id = PING_ID; iecho->seqno = lwip_htons(++ping_seq_num);
/* fill the additional data buffer with some data */ for(i = 0; i < data_len; i++) { ((char*)iecho)[sizeof(struct icmp_echo_hdr) + i] = (char)i; }
iecho->chksum = inet_chksum(iecho, len);}
#if PING_USE_SOCKETS
/* Ping using the socket ip */static err_tping_send(int s, const ip_addr_t *addr){ int err; struct icmp_echo_hdr *iecho; struct sockaddr_storage to; size_t ping_size = sizeof(struct icmp_echo_hdr) + PING_DATA_SIZE; LWIP_ASSERT("ping_size is too big", ping_size <= 0xffff);
#if LWIP_IPV6 if(IP_IS_V6(addr) && !ip6_addr_isipv4mappedipv6(ip_2_ip6(addr))) { /* todo: support ICMP6 echo */ return ERR_VAL; }#endif /* LWIP_IPV6 */
iecho = (struct icmp_echo_hdr *)mem_malloc((mem_size_t)ping_size); if (!iecho) { return ERR_MEM; }
ping_prepare_echo(iecho, (u16_t)ping_size);
#if LWIP_IPV4 if(IP_IS_V4(addr)) { struct sockaddr_in *to4 = (struct sockaddr_in*)&to; to4->sin_len = sizeof(*to4); to4->sin_family = AF_INET; inet_addr_from_ip4addr(&to4->sin_addr, ip_2_ip4(addr)); }#endif /* LWIP_IPV4 */
#if LWIP_IPV6 if(IP_IS_V6(addr)) { struct sockaddr_in6 *to6 = (struct sockaddr_in6*)&to; to6->sin6_len = sizeof(*to6); to6->sin6_family = AF_INET6; inet6_addr_from_ip6addr(&to6->sin6_addr, ip_2_ip6(addr)); }#endif /* LWIP_IPV6 */
err = lwip_sendto(s, iecho, ping_size, 0, (struct sockaddr*)&to, sizeof(to));
mem_free(iecho);
return (err ? ERR_OK : ERR_VAL);}
static voidping_recv(int s){ char buf[64]; int len; struct sockaddr_storage from; int fromlen = sizeof(from);
while((len = lwip_recvfrom(s, buf, sizeof(buf), 0, (struct sockaddr*)&from, (socklen_t*)&fromlen)) > 0) { if (len >= (int)(sizeof(struct ip_hdr)+sizeof(struct icmp_echo_hdr))) { ip_addr_t fromaddr; memset(&fromaddr, 0, sizeof(fromaddr));
#if LWIP_IPV4 if(from.ss_family == AF_INET) { struct sockaddr_in *from4 = (struct sockaddr_in*)&from; inet_addr_to_ip4addr(ip_2_ip4(&fromaddr), &from4->sin_addr); IP_SET_TYPE_VAL(fromaddr, IPADDR_TYPE_V4); }#endif /* LWIP_IPV4 */
#if LWIP_IPV6 if(from.ss_family == AF_INET6) { struct sockaddr_in6 *from6 = (struct sockaddr_in6*)&from; inet6_addr_to_ip6addr(ip_2_ip6(&fromaddr), &from6->sin6_addr); IP_SET_TYPE_VAL(fromaddr, IPADDR_TYPE_V6); }#endif /* LWIP_IPV6 */
LWIP_DEBUGF( PING_DEBUG, ("ping: recv ")); ip_addr_debug_print_val(PING_DEBUG, fromaddr); LWIP_DEBUGF( PING_DEBUG, (" %"U32_F" ms\n", (sys_now() - ping_time)));
/* todo: support ICMP6 echo */#if LWIP_IPV4 if (IP_IS_V4_VAL(fromaddr)) { struct ip_hdr *iphdr; struct icmp_echo_hdr *iecho;
iphdr = (struct ip_hdr *)buf; iecho = (struct icmp_echo_hdr *)(buf + (IPH_HL(iphdr) * 4)); if ((iecho->id == PING_ID) && (iecho->seqno == lwip_htons(ping_seq_num))) { /* do some ping result processing */ PING_RESULT((ICMPH_TYPE(iecho) == ICMP_ER)); return; } else { LWIP_DEBUGF( PING_DEBUG, ("ping: drop\n")); } }#endif /* LWIP_IPV4 */ } fromlen = sizeof(from); }
if (len == 0) { LWIP_DEBUGF( PING_DEBUG, ("ping: recv - %"U32_F" ms - timeout\n", (sys_now()-ping_time))); }
/* do some ping result processing */ PING_RESULT(0);}
static voidping_thread(void *arg){ int s; int ret;
#if LWIP_SO_SNDRCVTIMEO_NONSTANDARD int timeout = PING_RCV_TIMEO;#else struct timeval timeout; timeout.tv_sec = PING_RCV_TIMEO/1000; timeout.tv_usec = (PING_RCV_TIMEO%1000)*1000;#endif LWIP_UNUSED_ARG(arg);
#if LWIP_IPV6 if(IP_IS_V4(ping_target) || ip6_addr_isipv4mappedipv6(ip_2_ip6(ping_target))) { s = lwip_socket(AF_INET6, SOCK_RAW, IP_PROTO_ICMP); } else { s = lwip_socket(AF_INET6, SOCK_RAW, IP6_NEXTH_ICMP6); }#else s = lwip_socket(AF_INET, SOCK_RAW, IP_PROTO_ICMP);#endif if (s < 0) { return; }
ret = lwip_setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout)); LWIP_ASSERT("setting receive timeout failed", ret == 0); LWIP_UNUSED_ARG(ret);
while (1) { if (ping_send(s, ping_target) == ERR_OK) { LWIP_DEBUGF( PING_DEBUG, ("ping: send ")); ip_addr_debug_print(PING_DEBUG, ping_target); LWIP_DEBUGF( PING_DEBUG, ("\n"));
#ifdef LWIP_DEBUG ping_time = sys_now();#endif /* LWIP_DEBUG */ ping_recv(s); } else { LWIP_DEBUGF( PING_DEBUG, ("ping: send ")); ip_addr_debug_print(PING_DEBUG, ping_target); LWIP_DEBUGF( PING_DEBUG, (" - error\n")); } sys_msleep(PING_DELAY); }}
#else /* PING_USE_SOCKETS */
/* Ping using the raw ip */static u8_tping_recv(void *arg, struct raw_pcb *pcb, struct pbuf *p, const ip_addr_t *addr){ struct icmp_echo_hdr *iecho; LWIP_UNUSED_ARG(arg); LWIP_UNUSED_ARG(pcb); LWIP_UNUSED_ARG(addr); LWIP_ASSERT("p != NULL", p != NULL);
if ((p->tot_len >= (PBUF_IP_HLEN + sizeof(struct icmp_echo_hdr))) && pbuf_remove_header(p, PBUF_IP_HLEN) == 0) { iecho = (struct icmp_echo_hdr *)p->payload;
if ((iecho->id == PING_ID) && (iecho->seqno == lwip_htons(ping_seq_num))) { LWIP_DEBUGF( PING_DEBUG, ("ping: recv ")); ip_addr_debug_print(PING_DEBUG, addr); LWIP_DEBUGF( PING_DEBUG, (" %"U32_F" ms\n", (sys_now()-ping_time)));
/* do some ping result processing */ PING_RESULT(1); pbuf_free(p); return 1; /* eat the packet */ } /* not eaten, restore original packet */ pbuf_add_header(p, PBUF_IP_HLEN); }
return 0; /* don't eat the packet */}
static voidping_send(struct raw_pcb *raw, const ip_addr_t *addr){ struct pbuf *p; struct icmp_echo_hdr *iecho; size_t ping_size = sizeof(struct icmp_echo_hdr) + PING_DATA_SIZE;
LWIP_DEBUGF( PING_DEBUG, ("ping: send ")); ip_addr_debug_print(PING_DEBUG, addr); LWIP_DEBUGF( PING_DEBUG, ("\n")); LWIP_ASSERT("ping_size <= 0xffff", ping_size <= 0xffff);
p = pbuf_alloc(PBUF_IP, (u16_t)ping_size, PBUF_RAM); if (!p) { return; } if ((p->len == p->tot_len) && (p->next == NULL)) { iecho = (struct icmp_echo_hdr *)p->payload;
ping_prepare_echo(iecho, (u16_t)ping_size);
raw_sendto(raw, p, addr);#ifdef LWIP_DEBUG ping_time = sys_now();#endif /* LWIP_DEBUG */ } pbuf_free(p);}
static voidping_timeout(void *arg){ struct raw_pcb *pcb = (struct raw_pcb*)arg;
LWIP_ASSERT("ping_timeout: no pcb given!", pcb != NULL);
ping_send(pcb, ping_target);
sys_timeout(PING_DELAY, ping_timeout, pcb);}
static voidping_raw_init(void){ ping_pcb = raw_new(IP_PROTO_ICMP); LWIP_ASSERT("ping_pcb != NULL", ping_pcb != NULL);
raw_recv(ping_pcb, ping_recv, NULL); raw_bind(ping_pcb, IP_ADDR_ANY); sys_timeout(PING_DELAY, ping_timeout, ping_pcb);}
voidping_send_now(void){ LWIP_ASSERT("ping_pcb != NULL", ping_pcb != NULL); ping_send(ping_pcb, ping_target);}
#endif /* PING_USE_SOCKETS */
voidping_init(const ip_addr_t* ping_addr){ ping_target = ping_addr;
#if PING_USE_SOCKETS sys_thread_new("ping_thread", ping_thread, NULL, DEFAULT_THREAD_STACKSIZE, DEFAULT_THREAD_PRIO);#else /* PING_USE_SOCKETS */ ping_raw_init();#endif /* PING_USE_SOCKETS */}
#endif /* LWIP_RAW */
#ifndef LWIP_PING_H#define LWIP_PING_H
#include "lwip/ip_addr.h"
/** * PING_USE_SOCKETS: Set to 1 to use sockets, otherwise the raw api is used */#ifndef PING_USE_SOCKETS#define PING_USE_SOCKETS LWIP_SOCKET#endif
void ping_init(const ip_addr_t* ping_addr);
#if !PING_USE_SOCKETSvoid ping_send_now(void);#endif /* !PING_USE_SOCKETS */
#endif /* LWIP_PING_H */

如下是带OS的测试

  ip_addr_t ping_addr;
IP4_ADDR(&ping_addr, 192, 168, 1, 9);
ping_init(&ping_addr);

打印如下,(这里printf不支持某些格式所以IP地址打印显示不对)

 

四. 总结

了解ICMP包的格式,了解LWIP发送ping和对堆ping请求响应的过程。


评论
  • 嘿,咱来聊聊RISC-V MCU技术哈。 这RISC-V MCU技术呢,简单来说就是基于一个叫RISC-V的指令集架构做出的微控制器技术。RISC-V这个啊,2010年的时候,是加州大学伯克利分校的研究团队弄出来的,目的就是想搞个新的、开放的指令集架构,能跟上现代计算的需要。到了2015年,专门成立了个RISC-V基金会,让这个架构更标准,也更好地推广开了。这几年啊,这个RISC-V的生态系统发展得可快了,好多公司和机构都加入了RISC-V International,还推出了不少RISC-V
    丙丁先生 2025-01-21 12:10 111浏览
  • 高速先生成员--黄刚这不马上就要过年了嘛,高速先生就不打算给大家上难度了,整一篇简单但很实用的文章给大伙瞧瞧好了。相信这个标题一出来,尤其对于PCB设计工程师来说,心就立马凉了半截。他们辛辛苦苦进行PCB的过孔设计,高速先生居然说设计多大的过孔他们不关心!另外估计这时候就跳出很多“挑刺”的粉丝了哈,因为翻看很多以往的文章,高速先生都表达了过孔孔径对高速性能的影响是很大的哦!咋滴,今天居然说孔径不关心了?别,别急哈,听高速先生在这篇文章中娓娓道来。首先还是要对各位设计工程师的设计表示肯定,毕竟像我
    一博科技 2025-01-21 16:17 95浏览
  •  光伏及击穿,都可视之为 复合的逆过程,但是,复合、光伏与击穿,不单是进程的方向相反,偏置状态也不一样,复合的工况,是正偏,光伏是零偏,击穿与漂移则是反偏,光伏的能源是外来的,而击穿消耗的是结区自身和电源的能量,漂移的载流子是 客席载流子,须借外延层才能引入,客席载流子 不受反偏PN结的空乏区阻碍,能漂不能漂,只取决于反偏PN结是否处于外延层的「射程」范围,而穿通的成因,则是因耗尽层的过度扩张,致使跟 端子、外延层或其他空乏区 碰触,当耗尽层融通,耐压 (反向阻断能力) 即告彻底丧失,
    MrCU204 2025-01-17 11:30 179浏览
  • 本文介绍瑞芯微开发板/主板Android配置APK默认开启性能模式方法,开启性能模式后,APK的CPU使用优先级会有所提高。触觉智能RK3562开发板演示,搭载4核A53处理器,主频高达2.0GHz;内置独立1Tops算力NPU,可应用于物联网网关、平板电脑、智能家居、教育电子、工业显示与控制等行业。源码修改修改源码根目录下文件device/rockchip/rk3562/package_performance.xml并添加以下内容,注意"+"号为添加内容,"com.tencent.mm"为AP
    Industio_触觉智能 2025-01-17 14:09 161浏览
  • 2024年是很平淡的一年,能保住饭碗就是万幸了,公司业绩不好,跳槽又不敢跳,还有一个原因就是老板对我们这些员工还是很好的,碍于人情也不能在公司困难时去雪上加霜。在工作其间遇到的大问题没有,小问题还是有不少,这里就举一两个来说一下。第一个就是,先看下下面的这个封装,你能猜出它的引脚间距是多少吗?这种排线座比较常规的是0.6mm间距(即排线是0.3mm间距)的,而这个规格也是我们用得最多的,所以我们按惯性思维来看的话,就会认为这个座子就是0.6mm间距的,这样往往就不会去细看规格书了,所以这次的运气
    wuliangu 2025-01-21 00:15 181浏览
  • 现在为止,我们已经完成了Purple Pi OH主板的串口调试和部分配件的连接,接下来,让我们趁热打铁,完成剩余配件的连接!注:配件连接前请断开主板所有供电,避免敏感电路损坏!1.1 耳机接口主板有一路OTMP 标准四节耳机座J6,具备进行音频输出及录音功能,接入耳机后声音将优先从耳机输出,如下图所示:1.21.2 相机接口MIPI CSI 接口如上图所示,支持OV5648 和OV8858 摄像头模组。接入摄像头模组后,使用系统相机软件打开相机拍照和录像,如下图所示:1.3 以太网接口主板有一路
    Industio_触觉智能 2025-01-20 11:04 150浏览
  • 日前,商务部等部门办公厅印发《手机、平板、智能手表(手环)购新补贴实施方案》明确,个人消费者购买手机、平板、智能手表(手环)3类数码产品(单件销售价格不超过6000元),可享受购新补贴。每人每类可补贴1件,每件补贴比例为减去生产、流通环节及移动运营商所有优惠后最终销售价格的15%,每件最高不超过500元。目前,京东已经做好了承接手机、平板等数码产品国补优惠的落地准备工作,未来随着各省市关于手机、平板等品类的国补开启,京东将第一时间率先上线,满足消费者的换新升级需求。为保障国补的真实有效发放,基于
    华尔街科技眼 2025-01-17 10:44 221浏览
  • 临近春节,各方社交及应酬也变得多起来了,甚至一月份就排满了各式约见。有的是关系好的专业朋友的周末“恳谈会”,基本是关于2025年经济预判的话题,以及如何稳定工作等话题;但更多的预约是来自几个客户老板及副总裁们的见面,他们为今年的经济预判与企业发展焦虑而来。在聊天过程中,我发现今年的聊天有个很有意思的“点”,挺多人尤其关心我到底是怎么成长成现在的多领域风格的,还能掌握一些经济趋势的分析能力,到底学过哪些专业、在企业管过哪些具体事情?单单就这个一个月内,我就重复了数次“为什么”,再辅以我上次写的:《
    牛言喵语 2025-01-22 17:10 27浏览
  •  万万没想到!科幻电影中的人形机器人,正在一步步走进我们人类的日常生活中来了。1月17日,乐聚将第100台全尺寸人形机器人交付北汽越野车,再次吹响了人形机器人疯狂进厂打工的号角。无独有尔,银河通用机器人作为一家成立不到两年时间的创业公司,在短短一年多时间内推出革命性的第一代产品Galbot G1,这是一款轮式、双臂、身体可折叠的人形机器人,得到了美团战投、经纬创投、IDG资本等众多投资方的认可。作为一家成立仅仅只有两年多时间的企业,智元机器人也把机器人从梦想带进了现实。2024年8月1
    刘旷 2025-01-21 11:15 360浏览
  • 数字隔离芯片是一种实现电气隔离功能的集成电路,在工业自动化、汽车电子、光伏储能与电力通信等领域的电气系统中发挥着至关重要的作用。其不仅可令高、低压系统之间相互独立,提高低压系统的抗干扰能力,同时还可确保高、低压系统之间的安全交互,使系统稳定工作,并避免操作者遭受来自高压系统的电击伤害。典型数字隔离芯片的简化原理图值得一提的是,数字隔离芯片历经多年发展,其应用范围已十分广泛,凡涉及到在高、低压系统之间进行信号传输的场景中基本都需要应用到此种芯片。那么,电气工程师在进行电路设计时到底该如何评估选择一
    华普微HOPERF 2025-01-20 16:50 73浏览
  •     IPC-2581是基于ODB++标准、结合PCB行业特点而指定的PCB加工文件规范。    IPC-2581旨在替代CAM350格式,成为PCB加工行业的新的工业规范。    有一些免费软件,可以查看(不可修改)IPC-2581数据文件。这些软件典型用途是工艺校核。    1. Vu2581        出品:Downstream     
    电子知识打边炉 2025-01-22 11:12 46浏览
  • Ubuntu20.04默认情况下为root账号自动登录,本文介绍如何取消root账号自动登录,改为通过输入账号密码登录,使用触觉智能EVB3568鸿蒙开发板演示,搭载瑞芯微RK3568,四核A55处理器,主频2.0Ghz,1T算力NPU;支持OpenHarmony5.0及Linux、Android等操作系统,接口丰富,开发评估快人一步!添加新账号1、使用adduser命令来添加新用户,用户名以industio为例,系统会提示设置密码以及其他信息,您可以根据需要填写或跳过,命令如下:root@id
    Industio_触觉智能 2025-01-17 14:14 121浏览
我要评论
0
点击右上角,分享到朋友圈 我知道啦
请使用浏览器分享功能 我知道啦