ESP32 VHCI实现BLE广播,就是这么神奇

原创 专注于无线通信的蓬勃 2022-04-20 22:20

零. 声明


本专栏文章我们会以连载的方式持续更新,本专栏计划更新内容如下:

第一篇:ESP-IDF基本介绍,主要会涉及模组,芯片,开发板的介绍,环境搭建,程序编译下载,启动流程等一些基本的操作,让你对ESP-IDF开发有一个总体的认识,比我们后续学习打下基础!

第二篇:ESP32-IDF外设驱动介绍,主要会根据esp-idf现有的driver,提供各个外设的驱动,比如LED,OLED,SPI LCD,TOUCH,红外,Codec ic等等,在这一篇中,我们不仅仅来做外设驱动,还会对常用的外设总线做一个介绍,让大家知其然又知其所以然!

第三篇:目前比较火热的GUI LVGL介绍,主要会设计LVGL7.1,LVGL8的移植介绍,并且也会介绍各个组件,知道原理后,最后,我们会推出一款组态软件来构建我们的GUI,来提升我们的效率!

第四篇:ESP32-蓝牙,熟悉我的,应该都知道,我即使从事蓝牙协议栈的开发的,所以这个是我们独有的优势,在这一篇章,我们会提供不仅仅是蓝牙应用方法的知识,也会应用结合蓝牙底层协议栈的理论,让你彻底从上到下打通蓝牙任督二脉!

第五篇:Wi-Fi介绍,熟悉我的,应该也知道,我们也做过一款sdio wifi的驱动教程板子,所以在wifi这方面我们也是有独有的优势,在这一篇章,我们同样不仅仅提供Wi-Fi应用方面的知识,也会结合底层理论,让你对Wi-Fi有一个清晰的认知!

另外,我们的教程包括但是不局限于以上篇章,为了给你一个更好的导航,以下信息尤其重要,请详细查看!!

------------------------------------------------------------------------------------------------------------------------------------------

购买开发板(点击我)

ESP32系列文章目录(点击我)

Github代码仓库(点击我)

蓝牙交流扣扣群:539357317

微信公众号↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓

​​​​

------------------------------------------------------------------------------------------------------------------------------------------

一. 整体介绍

此文章主要介绍基于ESP32 VHCI的架构实现BLE的搜索,也就是不使用默认的Host API,自己编写一部分代码来实现功能,具体ESP32的架构如下图所示:

那我们做的事情是什么呢?我们相当于把默认的Host拿掉,也就是如图所示的bluedroid部分,写Host部分的广播实现

此文章算是熟悉一个VHCI的开发模式,不管对于默认的Host(Bluedroid/nimble)甚至自己移植进来一个Host都有很大的帮助,我就算起到一个抛砖引玉的作用吧!

二. menuconfig实现

我们虽然不用ESP32的默认Host,但是我们要用他默认的Controller,所以还是要配置一下的,一共三个地方需要特别留意一下,其他保持默认,如下图所示:

1.Bluetooth controller mode

2.HCI mode

3.bluetooth Host

三. 程序实现

1.初始化NVS

/* Initialize NVS — it is used to store PHY calibration data */
esp_err_t ret = nvs_flash_init();
if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
    ESP_ERROR_CHECK(nvs_flash_erase());
    ret = nvs_flash_init();
}
ESP_ERROR_CHECK( ret );

这一段必须要加上,主要是用于存储PHY的信息,否则无法正常使用controller

2.初始化controller,注册Controller的callback函数实现

esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();

ret = esp_bt_controller_mem_release(ESP_BT_MODE_CLASSIC_BT);
if (ret) {
    ESP_LOGI(TAG, "Bluetooth controller release classic bt memory failed: %s", esp_err_to_name(ret));
    return;
}

if ((ret = esp_bt_controller_init(&bt_cfg)) != ESP_OK) {
    ESP_LOGI(TAG, "Bluetooth controller initialize failed: %s", esp_err_to_name(ret));
    return;
}

if ((ret = esp_bt_controller_enable(ESP_BT_MODE_BLE)) != ESP_OK) {
    ESP_LOGI(TAG, "Bluetooth controller enable failed: %s", esp_err_to_name(ret));
    return;
}

esp_vhci_host_register_callback(&vhci_host_cb);

此段我们在介绍esp32 controller api的时候已经详细介绍,看API名字也知道主要在做什么事情,没什么难度,我们来看下注册给controller的callback的实现

static void controller_rcv_pkt_ready(void)
{
    printf("controller rcv pkt ready\n");
}


static int host_rcv_pkt(uint8_t *data, uint16_t len)
{
    printf("host rcv pkt: ");
    for (uint16_t i = 0; i < len; i  ) {
        printf("0xx ", data[i]);
    }
    printf("\n");
    return 0;
}

static esp_vhci_host_callback_t vhci_host_cb = {
    controller_rcv_pkt_ready,
    host_rcv_pkt
};

以上代码,我们接受到数据,并没有做什么事情,只是打印下数据的hex而已!

3.实现HCI 的广播

while (1) {
    bool send_avail = false;
    vTaskDelay(1000 / portTICK_PERIOD_MS);
    send_avail = esp_vhci_host_check_send_available();
    if (send_avail) {
        switch (cmd_cnt) {
            case 0: hci_cmd_send_reset();   cmd_cnt; break;
            case 1: hci_cmd_send_ble_set_adv_param();   cmd_cnt; break;
            case 2: hci_cmd_send_ble_set_adv_data();   cmd_cnt; break;
            case 3: hci_cmd_send_ble_adv_start();   cmd_cnt; break;
        }
    }
    printf("BLE Advertise, flag_send_avail: %d, cmd_sent: %d\n", send_avail, cmd_cnt);
}

在代码中,我们不去解析hci event的parse,只是一个个命令的发送hci command来实现广播,此部分也是我们本文章的重点,下面我就来一一详细介绍下

3.1 hci广播的流程

如果不考虑整个蓝牙Host的健壮性以及可用性,只考虑用ESP32 VHCI架构实现BLE广播功能,那么其实4个步骤就能实现,分别如下:

1) 发送HCI reset command

2) 发送ble set adv param,也就是设置广播的参数

3) 发送ble set adv data,也就是设置广播的数据

4) 发送ble adv start command,也就是开启广播

在后面的小节我们再一一介绍下每个command的格式以及作用!

3.2 hci command的格式

我们知道了步骤,并且知道了发送哪些command,但是command的格式是什么呢?那么这个算是一个比较大的话题,牵扯到蓝牙core spec hci章节的内容,我们本章本着应用文章,此部门我们简单的一笔带过,如果想彻底了解内部原理,那么我建议你看下这两篇文章:

蓝牙HCI command/event/acl/sco格式介绍_Wireless_Link的博客-CSDN博客

蓝牙传输介质Transport UART H4(RS232)介绍_Wireless_Link的博客-CSDN博客_蓝牙通过什么介质传输

以上两篇文章,分别介绍H4以及HCI的格式,好了,我们回归主题来介绍下HCI command的格式。

Opcode:每个命令被分配一个2字节的操作码(opcode),用来唯一地识别不同类型的命令,操作码(opcode)参数分为两个字段,称为操作码组字段(Opcode Group Field, OGF)和操作码命令字段(Opcode Command Field, OCF)。其中OGF占用高6bit字节,OCF占用低10bit字节。

一共有以下几组OGF:

1)Link Control commands, the OGF is defined as 0x01.链路控制OGF,也就是控制蓝牙芯片跟remote沟通的命令

2)Link Policy commands, the OGF is defined as 0x02,链路策略OGF,也就是写一些Policy,比如转换角色等

3)HCI Control and Baseband commands, the OGF is defined as 0x03,控制本地芯片跟基带的OGF。比如reset本地芯片等。

4)Informational Parameters commands, the OGF is defined as 0x04。读取信息的OGF,比如读取本地芯片的LMP版本呢,支持的command,蓝牙地址等,

5)status parameters commands, the OGF is defined as 0x05,状态参数OGF,比如读取RSSI等。

6)Testing commands, the OGF is defined as 0x06,测试命令的OGF,比如让芯片进入测试模式(DUT,device under test)

7)LE Controller commands, the OGF code is defined as 0x08,BLE 的comand

8)vendor-specific debug commands,the OGF code is defined as 0x3F,此部分是vendor定义的,也就是芯片厂商为了扩展core文档的HCI command定义

OCF众多,在每个OGF下都有一堆的OCF定义

Parameter Total Length:后续参数的长度

Parameter:每个command的para不同

3.3 hci reset命令

hci command的命令如下:

OGF是0x03,OCF是0x03

hci reset作用如下:

The HCI_Reset command willreset the Controller and the Link Manager on the BR/EDR Controller or the Link Layer on an LE Controller. If the Controller supports both BR/EDR and LEthen the HCI_Reset command shall reset the Link Manager, Baseband and Link Layer. The HCI_Reset command shall not affect the used HCI transport layer since the HCI transport layers may have reset mechanisms of their own. After the reset is completed, the current operational state will be lost, the Controller will enter standby mode and the Controller will automatically revert to the default values for the parameters for which default values are defined in the specification.

Note: The HCI_Reset command will not necessarily perform a hardware reset. This is implementation defined.

The Host shall not send additional HCI commands before the HCI_Command_Complete event related to the HCI_Reset command has been received。

函数实现如下:

/*  HCI Command Opcode group Field (OGF) */
#define HCI_GRP_HOST_CONT_BASEBAND_CMDS    (0x03 << 10)            /* 0x0C00 */
#define HCI_GRP_BLE_CMDS                   (0x08 << 10)

/*  HCI Command Opcode Command Field (OCF) */
#define HCI_RESET                       (0x0003 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)

uint16_t make_cmd_reset(uint8_t *buf)
{
    UINT8_TO_STREAM (buf, H4_TYPE_COMMAND);
    UINT16_TO_STREAM (buf, HCI_RESET);
    UINT8_TO_STREAM (buf, 0);
    return HCI_H4_CMD_PREAMBLE_SIZE;
}
static void hci_cmd_send_reset(void)
{
    uint16_t sz = make_cmd_reset (hci_cmd_buf);
    esp_vhci_host_send_packet(hci_cmd_buf, sz);
}

组成的数据格式是:0x01 ,0x03 0x0c 0x00

3.4 hci set adv param命令

hci command的格式如下:

OGF=0x08,OCF=0x06

我们来看下这个command的格式:

这个命令是设置广播的参数,其中参数如下:

Advertising_Interval_Min:广播的最小间隔

Advertising_Interval_Max:广播的最大间隔

设备每次广播时,会在3个广播信道上(根据设置的channel map而决定哪个信道)发送相同的报文。这些报文被称为一个广播事件。除了定向报文以外,其他广播事件均可以选择“20ms ~ 10.24s”不等的间隔。两个相邻广播事件之间的时间称为广播间隔。

但是,设备周期性的发送广播会有一个问题:由于设备间的时钟会不同程度的漂移,两个设备可能在很长一段时间同时广播而造成干扰。为防止这一情况的发生,除定向广播之外的其他广播类型,发送时间均会被扰动。实现该扰动的方式为,在上一次广播事件后加入“0 ~ 10ms”的随机延时。这意味着,即使两个设备广播间隔相同,并在相同信道及时间点上发送造成了冲突,但它们发送下一个广播事件时也会有很大可能不再冲突。

所以,两个相邻的广播事件的之间的时间间隔(T_advEvent)为:T_AdvEvent = advInterval advDelay

其中,advInterval 必须是“0.625ms”的整数倍,范围是“20ms ~ 10.24s”之间。对于可扫描非定向广播和不可连接非定向广播这两种广播类型,该值最好不小于100ms,即(160个0.625ms)。advDelay是Link Layer(链接层)分配的一个伪随机数,它的范围为“0 ~ 10ms”。

广播包的截图如下:

当然,实际设置过程中没有广播间隔参数,而是设置Advertising_Interval_Min(最小广播间隔)和Advertising_Interval_Max(最大广播间隔)这两个参数来调整广播间隔,它们都是以“0.625ms”为单位,如果要固定广播间隔为某一个值,只需要将这两个参数设置为同一个有效数值即可。

Advertising_Type:广播类型

一共分为四种广播类型:

1)可连接的非定向广播(Connectable Undirected Event Type):这是一种用途最广的广播类型,包括广播数据和扫描响应数据,它表示当前设备可以接受其他任何设备的连接请求。

鉴于此种广播类型用的最多,下面我们来讨论一下此类型下广播事件中广播包的发送情况,另外要注意在一个广播事件中,前一个“ADV_IND PDUs”的开始到相邻的下一个“ADV_IND PDUs”的开始处的时间要小于等于 10ms :

第一种情况:仅仅有广播 PDUs 。截图显示如下:

第二种情况:在广播事件的中间有“SCAN_REQ”和“SCAN_RSP PDUs”。截图显示如下:

第三种情况:在广播事件的结尾有“SCAN_REQ”和“SCAN_RSP PDUs”。截图显示如下:

第四种情况:在广播事件的中间接收到“CONNECT_REQ PDU”的情况。截图显示如下:

此情况下,广播事件会关闭,不会继续在下一个信道上广播。

2)可连接的定向广播(Connectable Directed Event Type):定向广播类型是为了尽可能快的建立连接。这种报文包含两个地址:广播者的地址和发起者的地址。发起者收到发给自己的定向广播报文之后,可以立即发送连接请求作为回应。

定向广播类型有特殊的时序要求。完整的广播事件必须每3.75ms重复一次。这一要求使得扫描设备只需扫描3.75ms便可以收到定向广播设备的消息。

当然,如此快的发送会让报文充斥着广播信道,进而导致该区域内的其他设备无法进行广播。因此,定向广播不可以持续1.28s以上的时间。如果主机没有主动要求停止,或者连接没有建立,控制器都会自动停止广播。一旦到了1.28s,主机便只能使用间隔长得多的可连接非定向广播让其他设备来连接。

当使用定向广播时,设备不能被主动扫描。此外,定向广播报文的净荷中也不能带有其他附加数据。该净荷只能包含两个必须的地址。

3)不可连接的非定向广播(Non-connectable Undirected Event Type):仅仅发送广播数据。

4)可扫描的非定向广播(Scannable Undirected Event Type):这种广播不能用于发起连接,但允许其他设备扫描该广播设备。这意味着该设备可以被发现,既可以发送广播数据,也可以响应扫描发送扫描回应数据,但不能建立连接。这是一种适用于广播数据的广播形式,动态数据可以包含于广播数据之中,而静态数据可以包含于扫描响应数据之中。

注意:所谓的定向和非定向针对的是广播的对象,如果是针对特定的对象进行广播(在广播包PDU中会包含目标对象的MAC)就是定向广播,反之就是非定向。可连接和不可连接是指是否接受连接请求,如果是不可连接的广播类型,它将不回应连接请求。可扫描广播类型是指回应扫描请求。

不同的广播类型对扫描请求和连接请求的不同结果如下图:

Own_Address_Type:本地地址类型

Peer_Address_Type:对端地址类型

Public Device Addrss:公有设备地址是设备所特有的并且是不可改变的。类似网络设备的MAC地址,它的长度为48位。由两部分组成:

Ramdom Device Address:随机设备地址(私有设备地址),它也是48位。组成如下所示:

Peer_Address:对端蓝牙地址

Advertising_Channel_Map:广播信道表

决定在哪个信道上广播,如果0x07就是在广播全信道(37,38,39)

Advertising_Filter_Policy:过滤策略

对应上图的内容解释如下:

接受任何设备的扫描请求或连接请求。(Value:0x00)

仅仅接受白名单中的特定设备的扫描请求,但是接受任何设备的连接请求。(Value:0x01)

接受任何设备的扫描请求,但仅仅接受白名单中的特定设备的连接请求。(Value:0x02)

仅仅接受白名单中的特定设备的扫描请求和连接请求。(Value:0x03)

整个实现的代码如下:

/*  HCI Command Opcode group Field (OGF) */
#define HCI_GRP_HOST_CONT_BASEBAND_CMDS    (0x03 << 10)            /* 0x0C00 */
#define HCI_GRP_BLE_CMDS                   (0x08 << 10)

/*  HCI Command Opcode Command Field (OCF) */
#define HCI_RESET                       (0x0003 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
/* Advertising Commands. */
#define HCI_BLE_WRITE_ADV_ENABLE        (0x000A | HCI_GRP_BLE_CMDS)
#define HCI_BLE_WRITE_ADV_DATA          (0x0008 | HCI_GRP_BLE_CMDS)
#define HCI_BLE_WRITE_ADV_PARAMS        (0x0006 | HCI_GRP_BLE_CMDS)

/* HCI Command length. */
#define HCIC_PARAM_SIZE_WRITE_ADV_ENABLE        1
#define HCIC_PARAM_SIZE_BLE_WRITE_ADV_PARAMS    15
#define HCIC_PARAM_SIZE_BLE_WRITE_ADV_DATA      31

uint16_t make_cmd_ble_set_adv_param (uint8_t *buf, uint16_t adv_int_min, uint16_t adv_int_max,
                                     uint8_t adv_type, uint8_t addr_type_own,
                                     uint8_t addr_type_dir, bd_addr_t direct_bda,
                                     uint8_t channel_map, uint8_t adv_filter_policy)
{
    UINT8_TO_STREAM (buf, H4_TYPE_COMMAND);
    UINT16_TO_STREAM (buf, HCI_BLE_WRITE_ADV_PARAMS);
    UINT8_TO_STREAM  (buf, HCIC_PARAM_SIZE_BLE_WRITE_ADV_PARAMS );

    UINT16_TO_STREAM (buf, adv_int_min);
    UINT16_TO_STREAM (buf, adv_int_max);
    UINT8_TO_STREAM (buf, adv_type);
    UINT8_TO_STREAM (buf, addr_type_own);
    UINT8_TO_STREAM (buf, addr_type_dir);
    BDADDR_TO_STREAM (buf, direct_bda);
    UINT8_TO_STREAM (buf, channel_map);
    UINT8_TO_STREAM (buf, adv_filter_policy);
    return HCI_H4_CMD_PREAMBLE_SIZE   HCIC_PARAM_SIZE_BLE_WRITE_ADV_PARAMS;
}
static void hci_cmd_send_ble_set_adv_param(void)
{
    uint16_t adv_intv_min = 256; // 160ms
    uint16_t adv_intv_max = 256; // 160ms
    uint8_t adv_type = 0; // connectable undirected advertising (ADV_IND)
    uint8_t own_addr_type = 0; // Public Device Address
    uint8_t peer_addr_type = 0; // Public Device Address
    uint8_t peer_addr[6] = {0};
    uint8_t adv_chn_map = 0x07; // 37, 38, 39
    uint8_t adv_filter_policy = 0; // Process All Conn and Scan

    uint16_t sz = make_cmd_ble_set_adv_param(hci_cmd_buf,
                  adv_intv_min,
                  adv_intv_max,
                  adv_type,
                  own_addr_type,
                  peer_addr_type,
                  peer_addr,
                  adv_chn_map,
                  adv_filter_policy);
    esp_vhci_host_send_packet(hci_cmd_buf, sz);
}

3.5 hci set adv data命令

hci command的格式如下:

OGF=0x08,OCF=0x08

我们来看下这个command的格式:

Advertising_Data_Length:广播数据长度,最长是31个字节

Advertising_Data:广播数据

广播参数格式如下:

一个1byte的length,n byte的type,后面跟的是这个item的广播数据,符合L T V格式

L:length T:Type V:value

其中Type跟HCI EIR基本一样,在文档CSS_V9中,想详细看的可以看下

说不讲原理,又忍不住给你们讲解原理了,就此打住,想看广播数据的,可以看下我这篇文章:

低功耗蓝牙搜索广播的实现流流程介绍 /BLE scan flow ----- 蓝牙低功耗协议栈_Wireless_Link的博客-CSDN博客

在上述文章步骤6)解析BLE广播event的数据包 有广播数据类型,格式等

我们看下代码实现

/*  HCI Command Opcode group Field (OGF) */
#define HCI_GRP_HOST_CONT_BASEBAND_CMDS    (0x03 << 10)            /* 0x0C00 */
#define HCI_GRP_BLE_CMDS                   (0x08 << 10)

/*  HCI Command Opcode Command Field (OCF) */
#define HCI_RESET                       (0x0003 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
/* Advertising Commands. */
#define HCI_BLE_WRITE_ADV_ENABLE        (0x000A | HCI_GRP_BLE_CMDS)
#define HCI_BLE_WRITE_ADV_DATA          (0x0008 | HCI_GRP_BLE_CMDS)
#define HCI_BLE_WRITE_ADV_PARAMS        (0x0006 | HCI_GRP_BLE_CMDS)

/* HCI Command length. */
#define HCIC_PARAM_SIZE_WRITE_ADV_ENABLE        1
#define HCIC_PARAM_SIZE_BLE_WRITE_ADV_PARAMS    15
#define HCIC_PARAM_SIZE_BLE_WRITE_ADV_DATA      31
uint16_t make_cmd_ble_set_adv_enable (uint8_t *buf, uint8_t adv_enable)
{
    UINT8_TO_STREAM (buf, H4_TYPE_COMMAND);
    UINT16_TO_STREAM (buf, HCI_BLE_WRITE_ADV_ENABLE);
    UINT8_TO_STREAM  (buf, HCIC_PARAM_SIZE_WRITE_ADV_ENABLE);
    UINT8_TO_STREAM (buf, adv_enable);
    return HCI_H4_CMD_PREAMBLE_SIZE   HCIC_PARAM_SIZE_WRITE_ADV_ENABLE;
}
static void hci_cmd_send_ble_adv_start(void)
{
    uint16_t sz = make_cmd_ble_set_adv_enable (hci_cmd_buf, 1);
    esp_vhci_host_send_packet(hci_cmd_buf, sz);
}

3.6 hci send ble adv start命令

hci command的格式如下:

OGF=0x08,OCF=0x0a

我们来看下这个command的格式:

Advertising_Enable:停止或者关闭BLE广播

代码如下:

/*  HCI Command Opcode group Field (OGF) */
#define HCI_GRP_HOST_CONT_BASEBAND_CMDS    (0x03 << 10)            /* 0x0C00 */
#define HCI_GRP_BLE_CMDS                   (0x08 << 10)

/*  HCI Command Opcode Command Field (OCF) */
#define HCI_RESET                       (0x0003 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
/* Advertising Commands. */
#define HCI_BLE_WRITE_ADV_ENABLE        (0x000A | HCI_GRP_BLE_CMDS)
#define HCI_BLE_WRITE_ADV_DATA          (0x0008 | HCI_GRP_BLE_CMDS)
#define HCI_BLE_WRITE_ADV_PARAMS        (0x0006 | HCI_GRP_BLE_CMDS)

/* HCI Command length. */
#define HCIC_PARAM_SIZE_WRITE_ADV_ENABLE        1
#define HCIC_PARAM_SIZE_BLE_WRITE_ADV_PARAMS    15
#define HCIC_PARAM_SIZE_BLE_WRITE_ADV_DATA      31
uint16_t make_cmd_ble_set_adv_enable (uint8_t *buf, uint8_t adv_enable)
{
    UINT8_TO_STREAM (buf, H4_TYPE_COMMAND);
    UINT16_TO_STREAM (buf, HCI_BLE_WRITE_ADV_ENABLE);
    UINT8_TO_STREAM  (buf, HCIC_PARAM_SIZE_WRITE_ADV_ENABLE);
    UINT8_TO_STREAM (buf, adv_enable);
    return HCI_H4_CMD_PREAMBLE_SIZE   HCIC_PARAM_SIZE_WRITE_ADV_ENABLE;
}
static void hci_cmd_send_ble_adv_start(void)
{
    uint16_t sz = make_cmd_ble_set_adv_enable (hci_cmd_buf, 1);
    esp_vhci_host_send_packet(hci_cmd_buf, sz);
}

四.程序效果

整个代码运行效果就是我们可以搜索到我们的设备,但是不能连接哈,因为我们自己写的这部分代码不是完整的Host代码

专注于无线通信的蓬勃 朝气蓬勃——不积跬步 无以至千里, 不积小流 无以成江海
评论
  •  万万没想到!科幻电影中的人形机器人,正在一步步走进我们人类的日常生活中来了。1月17日,乐聚将第100台全尺寸人形机器人交付北汽越野车,再次吹响了人形机器人疯狂进厂打工的号角。无独有尔,银河通用机器人作为一家成立不到两年时间的创业公司,在短短一年多时间内推出革命性的第一代产品Galbot G1,这是一款轮式、双臂、身体可折叠的人形机器人,得到了美团战投、经纬创投、IDG资本等众多投资方的认可。作为一家成立仅仅只有两年多时间的企业,智元机器人也把机器人从梦想带进了现实。2024年8月1
    刘旷 2025-01-21 11:15 560浏览
  • 临近春节,各方社交及应酬也变得多起来了,甚至一月份就排满了各式约见。有的是关系好的专业朋友的周末“恳谈会”,基本是关于2025年经济预判的话题,以及如何稳定工作等话题;但更多的预约是来自几个客户老板及副总裁们的见面,他们为今年的经济预判与企业发展焦虑而来。在聊天过程中,我发现今年的聊天有个很有意思的“点”,挺多人尤其关心我到底是怎么成长成现在的多领域风格的,还能掌握一些经济趋势的分析能力,到底学过哪些专业、在企业管过哪些具体事情?单单就这个一个月内,我就重复了数次“为什么”,再辅以我上次写的:《
    牛言喵语 2025-01-22 17:10 83浏览
  • 嘿,咱来聊聊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 188浏览
  • 2024年是很平淡的一年,能保住饭碗就是万幸了,公司业绩不好,跳槽又不敢跳,还有一个原因就是老板对我们这些员工还是很好的,碍于人情也不能在公司困难时去雪上加霜。在工作其间遇到的大问题没有,小问题还是有不少,这里就举一两个来说一下。第一个就是,先看下下面的这个封装,你能猜出它的引脚间距是多少吗?这种排线座比较常规的是0.6mm间距(即排线是0.3mm间距)的,而这个规格也是我们用得最多的,所以我们按惯性思维来看的话,就会认为这个座子就是0.6mm间距的,这样往往就不会去细看规格书了,所以这次的运气
    wuliangu 2025-01-21 00:15 204浏览
  •  光伏及击穿,都可视之为 复合的逆过程,但是,复合、光伏与击穿,不单是进程的方向相反,偏置状态也不一样,复合的工况,是正偏,光伏是零偏,击穿与漂移则是反偏,光伏的能源是外来的,而击穿消耗的是结区自身和电源的能量,漂移的载流子是 客席载流子,须借外延层才能引入,客席载流子 不受反偏PN结的空乏区阻碍,能漂不能漂,只取决于反偏PN结是否处于外延层的「射程」范围,而穿通的成因,则是因耗尽层的过度扩张,致使跟 端子、外延层或其他空乏区 碰触,当耗尽层融通,耐压 (反向阻断能力) 即告彻底丧失,
    MrCU204 2025-01-17 11:30 188浏览
  • 高速先生成员--黄刚这不马上就要过年了嘛,高速先生就不打算给大家上难度了,整一篇简单但很实用的文章给大伙瞧瞧好了。相信这个标题一出来,尤其对于PCB设计工程师来说,心就立马凉了半截。他们辛辛苦苦进行PCB的过孔设计,高速先生居然说设计多大的过孔他们不关心!另外估计这时候就跳出很多“挑刺”的粉丝了哈,因为翻看很多以往的文章,高速先生都表达了过孔孔径对高速性能的影响是很大的哦!咋滴,今天居然说孔径不关心了?别,别急哈,听高速先生在这篇文章中娓娓道来。首先还是要对各位设计工程师的设计表示肯定,毕竟像我
    一博科技 2025-01-21 16:17 112浏览
  • 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 128浏览
  •     IPC-2581是基于ODB++标准、结合PCB行业特点而指定的PCB加工文件规范。    IPC-2581旨在替代CAM350格式,成为PCB加工行业的新的工业规范。    有一些免费软件,可以查看(不可修改)IPC-2581数据文件。这些软件典型用途是工艺校核。    1. Vu2581        出品:Downstream     
    电子知识打边炉 2025-01-22 11:12 88浏览
  • 现在为止,我们已经完成了Purple Pi OH主板的串口调试和部分配件的连接,接下来,让我们趁热打铁,完成剩余配件的连接!注:配件连接前请断开主板所有供电,避免敏感电路损坏!1.1 耳机接口主板有一路OTMP 标准四节耳机座J6,具备进行音频输出及录音功能,接入耳机后声音将优先从耳机输出,如下图所示:1.21.2 相机接口MIPI CSI 接口如上图所示,支持OV5648 和OV8858 摄像头模组。接入摄像头模组后,使用系统相机软件打开相机拍照和录像,如下图所示:1.3 以太网接口主板有一路
    Industio_触觉智能 2025-01-20 11:04 166浏览
  • 数字隔离芯片是一种实现电气隔离功能的集成电路,在工业自动化、汽车电子、光伏储能与电力通信等领域的电气系统中发挥着至关重要的作用。其不仅可令高、低压系统之间相互独立,提高低压系统的抗干扰能力,同时还可确保高、低压系统之间的安全交互,使系统稳定工作,并避免操作者遭受来自高压系统的电击伤害。典型数字隔离芯片的简化原理图值得一提的是,数字隔离芯片历经多年发展,其应用范围已十分广泛,凡涉及到在高、低压系统之间进行信号传输的场景中基本都需要应用到此种芯片。那么,电气工程师在进行电路设计时到底该如何评估选择一
    华普微HOPERF 2025-01-20 16:50 81浏览
  • 本文介绍瑞芯微开发板/主板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 173浏览
我要评论
0
点击右上角,分享到朋友圈 我知道啦
请使用浏览器分享功能 我知道啦