c/c++和lua的交互使用分享

羽林君 2021-12-12 22:56

前言:

嵌入式开发过程中,我们会使用一些脚本工具辅助我们的工作,例如shel或者python、lua等,今天给大家分享一下,我在工作中用到的lua脚本交互使用。

作者:良知犹存

转载授权以及围观:欢迎关注微信公众号:羽林君

或者添加作者个人微信:become_me


情节介绍:

工作中, 因为我们的传感器需要出厂标定,所以我们需要有一个配置文件进行保存我们的传感器参数,这个文件支持读取和修改,实现这个功能有很多种方式,常规就是使用一个普通文件进行读写。

但是我考虑到,我们数据的复杂性,以及文件注释的描述,我选择了xml文件进行数据的保存,但是xml文件操作的库我又不想去自己写也不想去外部添加使用,本来就是一个小功能,没必要再去新增额外链接,使用别的xml操作库,所以我就盯上了我们激光slam建图算法里面用到的lua脚本,这个lua脚本的包本身以及在内核里面添加并在其他进程使用了,我只需要在我这边编译选项加 -llua动态链过去就可以多个进程一起使用了。

除了方便,也考虑到lua是一个轻量级的脚本,支持交互调用,比如说我们可以通过代码内部执行调用lua脚本函数,也可以在lua执行代码注册进去的函数。这个比shell和python有很多优势,shell只能在它脚本生成的终端去执行以及python也是类似,无法进行双方的函数交互调用。而lua可以交互调用,所以很方便。

lua介绍

Lua ,是巴西里约热内卢天主教大学里的一个研究小组于 1993 年开发的。是一种轻量小巧的脚本语言,用标准C语言编写并以源代码形式开放, 其设计目的是为了嵌入应用程序中,从而为应用程序提供灵活的扩展和定制功能。其设计目的是为了嵌入应用程序中,从而为应用程序提供灵活的扩展和定制功能。

Lua 特性

轻量级: 它用标准C语言编写并以源代码形式开放,编译后仅仅一百余K,可以很方便的嵌入别的程序里。可扩展: Lua提供了非常易于使用的扩展接口和机制:由宿主语言(通常是C或C++)提供这些功能,Lua可以使用它们,就像是本来就内置的功能一样。

支持面向过程(procedure-oriented)编程和函数式编程(functional programming);自动内存管理;只提供了一种通用类型的表(table),用它可以实现数组,哈希表,集合,对象;语言内置模式匹配;闭包(closure);函数也可以看做一个值;提供多线程(协同进程,并非操作系统所支持的线程)支持;通过闭包和table可以很方便地支持面向对象编程所需要的一些关键机制,比如数据抽象,虚函数,继承和重载等。

Lua 应用场景

游戏开发、独立应用脚本、Web 应用脚本、扩展和数据库插件如:MySQL Proxy 和 MySQL WorkBench、安全系统,如入侵检测系统。

lua交互原理基础知识

lua和c++是通过一个虚拟栈来交互的。c++调用lua实际上是:由c++先把数据放入栈中,由lua去栈中取数据,然后返回数据对应的值到栈顶,再由栈顶返回c++。lua调c++也一样:先编写自己的c模块,然后注册函数到lua解释器中,然后由lua去调用这个模块的函数。

因为在我们设备上本来就有lua库,所以我开发时候直接就在CMakeLists.txt文件里面增加了 -llua,但是最开始在自己pc验证的时候,本机是没有相应的lua包的,还是下载了官网lua的源码进行编译之后,放到我的电脑指定目录进行操作验证的。

  1. lua源码下载

去官网 http://www.lua.org/download.html  下载

make

make install

编译好的文件放到了以下三个目录

  • /usr/local/bin  解释器目录
  • /usr/local/include 头文件目录
  • /usr/local/lib 动态链接库目录

在后面我们进行本机测试代码时候,就可以加上绝对目录,进行头文件搜索和动态库链接了。

下面是我的一个demo测试的Makefile文件内容,其中就用了头文件目录动态链接库目录

OBJS = test_cpp_lua.o 
CFLAGS = -Wall -g -std=c++11
CC = gcc
CPP = g++
INCLUDES +=-I /usr/local/include 
LIBS +=  -L /usr/local/lib   -llua -ldl
#LIBS =   -ldl -llua

target:${OBJS}
# g++  -o target test_cpp_lua.o  -llua -ldl 
 @echo "-- start " ${CC} ${CFLAGS} ${OBJS}  -o $@  ${INCLUDES}  ${LIBS}
 $(CPP) ${CFLAGS} ${OBJS}  -o $@  ${INCLUDES}  ${LIBS}

clean:
 -rm -f *.o core *.core target

.cpp.o:
#%.o:%.cpp
 ${CPP} ${CFLAGS} ${INCLUDES} -c  $<

注意:我在编译时候还用了-ldl ,是因为程序中使用dlopendlsymdlclosedlerror 显示加载动态库,需要设置链接选项 -ldl

加载动态链接库,首先为共享库分配物理内存,然后在进程对应的页表项中建立虚拟页和物理页面之间的映射。

Lua是一种嵌入式脚本语言,即Lua不是可以单独运行的程序,在实际应用中,主要存在两种应用形式。第一种形式是,C/C++作为主程序,调用Lua代码,此时可以将Lua看做“可扩展的语言”,我们将这种应用称为“应用程序代码”。第二种形式是Lua具有控制权,而C/C++代码则作为Lua的“库代码”。在这两种形式中,都是通过Lua提供的C API完成两种语言之间的通信的。

接下来我给大家分别介绍两者调用的用法,以及补充到我自己实际使用xml文件的读写的操作demo。本文没有过多描述lua脚本语言的使用操作,仅仅做一些实际调用过程中的应用分享。

C/C++代码调用 lua变量和函数

首先我们最常用的就是进行脚本的调用,来个最常见的调用机制,在代码里面执行调用脚本里面函数或者获得脚本文件里面的一些设置信息。

这lua脚本里面的代码部分:

debug_enbale = "enable"

angle_table = {
roll_offset = 0.05 ,
pitch_offset = 0.0,
yaw_offset = 0.0,
}

for i,v in ipairs(angle_table) do
        print(i,v)
 end

这个里面定义了一个字符串变量 debug_enbale ,和一个 lua的table angle_table,最后还有一个进行table遍历的for循环流程控制代码。这样在执行lua脚本时候就可以打印对应table里面变量信息

在lua中,lua堆栈就是一个struct,堆栈索引的方式可是是正数也可以是负数,区别是:正数索引1永远表示栈底,负数索引-1永远表示栈顶。所以我们在使用过程中会看到push_x 和 to_x这样的函数,就是进行堆栈的操作。

这部分是常规的使用,我在里面分别获取了number数据和string数据,放到我的执行代码的运行变量中去。

#include "lua.hpp"
#include 
int main(int argc,char ** argv)
{
    lua_State *pLua = luaL_newstate();
    if(!pLua)
    {
        LOG(Info,  "Failed to open Lua!");
        return false;
    }
    luaL_openlibs(pLua);
    
    int bRet = luaL_loadfile(pLua, lua_path.c_str());
    if (bRet)
    {
        LOG(Info, "load .lua file failed" );
        return false;
    }
   // 执行lua文件
    bRet = lua_pcall(pLua, 0, 0, 0);
    if (bRet)
    {
        LOG(Info,  "call .lua file failed" );
        return false;
    }
    
    lua_getglobal(pLua, "debug_enbale"); 
    std::string str = lua_tostring(pLua, -1);//获得lua脚本debug_enbale位置的数据
    LOG(Info,  "debug_enbale=" << str);
    

    auto get_float_data_from_lua = [&](const char * table_name,const char * value_name) -> float{
           lua_getglobal(pLua, table_name);
           lua_getfield(pLua, -1, value_name);
           return lua_tonumber(pLua, -1);
    };
    roll_offset = get_float_data_from_lua("angle_table","roll_offset");
    pitch_offset = get_float_data_from_lua("angle_table","pitch_offset");
    yaw_offset = get_float_data_from_lua("angle_table","yaw_offset");

    LOG(Info,  "angle_table:" 
        << roll_offset <<" "
        << pitch_offset <<" "
        << yaw_offset );  
    lua_close(pLua);
        
}

重要函数描述

1.因为工程是cpp,所以添加lua.hpp,如果是C工程,可以直接包含lua.h。

2.lua_State *pLua = luaL_newstate(); Lua库中没有定义任何全局变量,而是将所有的状态都保存在动态结构lua_State中,后面所有的C API都需要该指针作为第一个参数。3.luaL_openlibs函数是用于打开Lua中的所有标准库,如io库、string库等。

4.luaL_loadfile实际调用了lua_load函数来加载lua文件。

5.lua_pcall函数会将程序块从栈中弹出,并在保护模式下运行该程序块。执行成功返回0,否则将错误信息压入栈中。6.lua_getglobal调用这个宏的时候,都会将Lua代码中与之相应的全局变量值压入栈中

7.lua_tostring函数中的-1,表示栈顶的索引值,栈底的索引值为1,以此类推。该函数将返回栈顶的字符串信息

7.lua_getfield把堆栈中指定索引-1为栈顶 angle_table中的value_name的具体值push到堆栈。

8.lua_tonumber 把栈顶中数据以数值形式返回

9.lua_close用于释放状态指针所引用的资源。

其中,使用有数据区分的函数lua_tonumber和lua_tostring两种函数,lua_tonumber返回包括整形和浮点型。

这样我就获得了lua脚本里面我写好的数据,用来配合我代码执行。

lua变量 调用C/C++代码函数

引用文章《Step By Step(Lua调用C函数)》 Lua可以调用C函数的能力将极大的提高Lua的可扩展性和可用性。对于有些和操作系统相关的功能,或者是对效率要求较高的模块,我们完全可以通过C函数来实现,之后再通过Lua调用指定的C函数。对于那些可被Lua调用的C函数而言,其接口必须遵循Lua要求的形式,即typedef int (lua_CFunction)(lua_State L)。简单说明一下,该函数类型仅仅包含一个表示Lua环境的指针作为其唯一的参数,实现者可以通过该指针进一步获取Lua代码中实际传入的参数。返回值是整型,表示该C函数将返回给Lua代码的返回值数量,如果没有返回值,则return 0即可。需要说明的是,C函数无法直接将真正的返回值返回给Lua代码,而是通过虚拟栈来传递Lua代码和C函数之间的调用参数和返回值的。这里我们将介绍两种Lua调用C函数的规则。

Lua调用C函数有两种方式

1、程序主体在C中运行,C函数注册到Lua中。C调用Lua,Lua调用C注册的函数,C得到函数的执行结果。

2、程序主体在Lua中运行,C函数作为库函数供Lua使用。第一种方式看起来很罗嗦,也很奇怪。既然程序主体运行在C中,而且最终使用的也是C中定义的函数,那么为何要将函数注册给Lua,然后再通过Lua调用函数呢?

所以相比于第一种方式,第二种方式使用的更加普遍。

关于这部分代码我也只是在我电脑上跑了几个范例,大家也可以去网上自己去查找相关例子,我自己在设备上并没有使用到这个部分,后续我有使用可以再写这部分应用给大家分享。

lua进行xml文件的操作

这个部分是因为之前的功能做了一些修正,原因是我们需要的传感器参数放置的文件可以被修改,如果使用lua脚本里面写入参数,那么参数相当与定死了,我们后续是无法使用lua脚本修改里面本身的数据的,所以后来我就使用xml文件放置我的传感器参数,使用lua脚本进行读写。

xml是一个常用来写一些我们不定数据配置文件的格式,lua也有luaxml,工具包,但是我为了不新增额外库实现,所以使用了lua里面I/O库(lua用于读取和处理文件的库)读写的方法进行读写xml文件。

大家也可以用xml一个lua其他工具进行使用,会更加方便,下面分享一个官方给的链接:http://lua-users.org/wiki/LuaXml

里面分为四种不同方法的xml读写工具:

  • 工具包;
  • 仅限 Lua 的 XML 解析器;
  • 包含 C 代码和绑定的 XML 解析器;
  • 用于处理基于 XML 的协议(例如 XML-RPC 和 SOAP)的模块。

lua脚本中读写xml函数

function get_value_from_xml(path,element_name)
 xml_file=path        
 element=element_name    

 head="<"..element..">"     
 tail="..element..">"    

 file = io.open(xml_file, "r");  --打开xml文件
 data = file:read("*all");     --读取文件的全部内容到data变量中
 file:close();                 --关闭xml文件

 --获取起始tag与关闭tag之间的内容到value中
 _,_,value=string.find(data, head.."(.-)"..tail)

 --输出value的值到标准输出
 -- print(value)
 return value

end
function set_value_to_xml(path,element_name,set_value)
 xml_file=path   
 element=element_name    
 new_value=set_value  

 head="<"..element..">"    --根据元素名生成起始tag,即
 tail="..element..">"   --根据元素名生成关闭tag,即


 file = io.open(xml_file, "r"); --打开xml文件
 data = file:read("*all");      --读取文件的全部内容到data变量中
 file:close();                  --关闭xml文件


 --将element之前的内容,element的值,element之后的内容,分别保存在pre,old_value,follow中
 _,_,pre,old_value,follow=string.find(data, "(.*)("..head..".-"..tail..")(.*)")


 file = io.open(xml_file, "w");      --打开xml文件
 file:write(pre..head..new_value..tail..follow); --拼装出新的文件内容,并写入
 file:close();                       --关闭xml文件
end

上面主要是利用了 string.find 它的三个参数和三个返回值。string.find 功能是从字符串中找到特定的内容。

第一个参数是目标字符串(所有的内容,比如data),第二个参数是想要找的字符串(比如 item 之间的内容),第三个参数是从第几个字符开始找起(我让它成为一个不断变化的值)。

第一个返回值是找到的字符串( item 之间的内容)的首字符位置(一个数字),第二个返回值是找到的字符串( item 之间的内容)的尾字符位置(一个数字),第三个是找到的字符串( item 之间的内容)。

所以代码就是靠每次循环的第三个返回值来获取内容。

cpp代码:

#include "lua.hpp"
#include 
int main(int argc,char ** argv)
{
   lua_State *pLua = luaL_newstate();
    if(!pLua)
    {
        LOG(Info,  "Failed to open Lua!");
        return false;
    }
    luaL_openlibs(pLua);
    
    int bRet = luaL_loadfile(pLua, lua_path.c_str());
    if (bRet)
    {
        LOG(Info, "load .lua file failed" );
        return false;
    }
   // 执行lua文件
    bRet = lua_pcall(pLua, 0, 0, 0);
    if (bRet)
    {
        LOG(Info,  "call .lua file failed" );
        return false;
    }

    auto lua_func_call_wirte = [&](const char * func_name, const char * key_name,float &value){
        lua_getglobal(pLua, func_name);
        lua_pushstring(pLua ,surface_xml_used_path.c_str());  
        lua_pushstring(pLua ,key_name);  
        lua_pushnumber(pLua ,value);  
        bRet = lua_pcall(pLua, 3, 1, 0);//三个参数 一个返回值
        if (bRet)
        {
            const char* pErrorMsg = lua_tostring(pLua, -1);
            LOG(Info, "lua_pcall - ErrorMsg:"  << pErrorMsg );
            // lua_close(pLua);
            return false;
        }
        
        if (lua_isnumber(pLua, -1))
        {
            value = lua_tonumber(pLua, -1);
            LOG(Info,  "surface_config " << value);
            return true;
        }     
        return false;
    };  
      float roll_offset = 0.5,pitch_offset = 0.2,yaw_offset=0.6;

    lua_func_call_wirte("set_value_to_xml"," roll_offset", roll_offset);
    lua_func_call_wirte("set_value_to_xml"," pitch_offset", pitch_offset);
    lua_func_call_wirte("set_value_to_xml"," yaw_offset", yaw_offset);
    
    
    
  auto lua_func_call_number = [&](const char * func_name, const char * key_name,float &value){
        lua_getglobal(pLua, func_name);
        lua_pushstring(pLua ,surface_xml_used_path.c_str());  
        lua_pushstring(pLua ,key_name);  
        bRet = lua_pcall(pLua, 2, 1, 0);//两个参数 一个返回值
        if (bRet)
        {
            const char* pErrorMsg = lua_tostring(pLua, -1);
            LOG(Info, "lua_pcall - ErrorMsg:"  << pErrorMsg );
            // lua_close(pLua);
            return false;
        }
        
        if (lua_isnumber(pLua, -1))
        {
            value = lua_tonumber(pLua, -1);
            LOG(Info,  "config " << value);
            return true;
        }     
        return false;
    };  

    auto lua_func_call_string = [&](const char * func_name, const char * key_name,std::string &value){
        lua_getglobal(pLua, func_name);
        lua_pushstring(pLua ,surface_xml_used_path.c_str());  
        lua_pushstring(pLua ,key_name);  
        bRet = lua_pcall(pLua, 2, 1, 0);
        if (bRet)
        {
            const char* pErrorMsg = lua_tostring(pLua, -1);
            ZY_LOG("robotctl",  kInfo, "lua_pcall - ErrorMsg:"  << pErrorMsg );
            lua_close(pLua);
            return false;
        }
        
        if (lua_isstring(pLua, -1))
        {
            value = lua_tostring(pLua, -1);
            LOG(Info,  "config " << value.c_str() );
            return true;
        }     
        return false;
  
    };
    std::string  temp_from_lua;
    lua_func_call_string("get_value_from_xml","debug_enable",temp_from_lua);
    LOG(Info,  "debug_enbale =" << temp_from_lua);


    lua_func_call_number("get_value_from_xml","down_roll_offset",roll_offset);
    lua_func_call_number("get_value_from_xml","down_pitch_offset",pitch_offset);
    lua_func_call_number("get_value_from_xml","down_yaw_offset",yaw_offset);

    
    LOG(Info,  "ngle_table:" 
        << roll_offset <<" "
        << pitch_offset <<" "
        << yaw_offset );   
    lua_close(pLua);

}

看到这块大家可能会问我,为什么不直接使用linux下直接做一个文件进行读写配置数据呢,我的想法是,纯文件不好进行注释,因为我的配置参数有些很长,我想把它尽可能让别人看懂,所以我写了一些注释进去,xml很符合我的要求,此外lua脚本也一些脚本使用过程中,很好的可以辅助我本身的代码执行,所以我就考虑把一些整体差不多执行的功能操作可以集成到一起,统一接口去执行。所以最后选择了lua+xml,技术有很多种实现思路,但是我们需要衡量一下哪些部分的技术可以让平台可以重复利用的多一些。

结语

这就是我分享我在工作中使用lua脚本的操作,如果大家有更好的想法和需求,也欢迎大家加我好友交流分享哈。


作者:良知犹存,白天努力工作,晚上原创公号号主。公众号内容除了技术还有些人生感悟,一个认真输出内容的职场老司机,也是一个技术之外丰富生活的人,摄影、音乐 and 篮球。关注我,与我一起同行。

                              ‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧  END  ‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧

推荐阅读

【1】在球场上我向人民币玩家低了头

【2】Linux开发coredump文件分析实战分享

【3】CPU中的程序是怎么运行起来的 必读

【4】cartographer环境建立以及建图测试

【5】设计模式之简单工厂模式、工厂模式、抽象工厂模式的对比

本公众号全部原创干货已整理成一个目录,回复[ 资源 ]即可获得。


羽林君 某嵌入式程序猿分享技术、生活、人生云云文字。如有诗云:去年今日此门中,人面桃花相映红。人面不知何处去,桃花依旧笑春风。
评论
  • 起源与基础20 世纪 60 年代:可编程逻辑设备(PLD)的概念出现,一种被称为 “重构能力” 的芯片的可编程性吸引了许多工程师和学者。20 世纪 70 年代:最早的可编程逻辑器件 PLD 诞生,其输出结构是可编程的逻辑宏单元,它的硬件结构设计可由软件完成,设计比纯硬件的数字电路更灵活,但结构简单,只能实现小规模电路。诞生与发展20 世纪 80 年代中期:为弥补 PLD 只能设计小规模电路的缺陷,复杂可编程逻辑器件 CPLD 被推出,它具有更复杂的结构,能够实现较大规模的电路设计。1988 年:
    Jeffreyzhang123 2024-12-27 10:41 68浏览
  • 采购与分销是企业运营中至关重要的环节,直接影响到企业的成本控制、客户满意度和市场竞争力。以下从多个方面介绍如何优化采购与分销:采购环节优化供应商管理供应商评估与选择:建立一套全面、科学的供应商评估体系,除了考虑价格因素,还要综合评估供应商的产品质量、交货期、信誉、研发能力、售后服务等。通过多维度评估,选择那些能够提供优质产品和服务,且与企业战略目标相契合的供应商。建立长期合作关系:与优质供应商建立长期稳定的合作关系,这种合作模式可以带来诸多好处。双方可以在信任的基础上进行深度沟通与协作,共同开展
    Jeffreyzhang123 2024-12-27 17:43 78浏览
  • 在当今竞争激烈的商业世界中,供应链管理已成为企业生存与发展的核心竞争力之一。它就像一条无形的纽带,将供应商、制造商、分销商、零售商直至最终消费者紧密相连,确保产品和服务能够高效、顺畅地流转。今天,就让我们一同深入探索供应链管理的奥秘。供应链管理是什么简单来说,供应链管理是对从原材料采购、生产制造、产品配送直至销售给最终用户这一整个过程中,涉及的物流、信息流和资金流进行计划、协调、控制和优化的管理活动。它不仅仅是对各个环节的简单串联,更是一种通过整合资源、优化流程,实现整体效益最大化的管理理念和方
    Jeffreyzhang123 2024-12-27 17:27 85浏览
  • 一、引言无人机,作为近年来迅速崛起的新兴技术产物,正以前所未有的速度改变着众多行业的运作模式,从民用领域的航拍、物流,到工业领域的测绘、巡检,再到军事领域的侦察、打击等,无人机的身影无处不在。为了深入了解无人机的现状,本次调研综合了市场数据、行业报告、用户反馈等多方面信息,全面剖析无人机的发展态势。二、市场规模与增长趋势随着技术的不断进步和成本的逐渐降低,无人机市场呈现出爆发式增长。近年来,全球无人机市场规模持续扩大,预计在未来几年内仍将保持较高的增长率。从应用领域来看,消费级无人机市场依然占据
    Jeffreyzhang123 2024-12-27 17:29 100浏览
  • 在当今这个数字化的时代,电子设备无处不在,从我们手中的智能手机、随身携带的笔记本电脑,到复杂的工业控制系统、先进的医疗设备,它们的正常运行都离不开一个关键的 “幕后英雄”—— 印刷电路板(Printed Circuit Board,简称 PCB)。PCB 作为电子设备中不可或缺的重要部件,默默地承载着电子元件之间的连接与信号传输,是整个电子世界的基石。揭开 PCB 的神秘面纱PCB,简单来说,就是一块由绝缘材料制成的板子,上面通过印刷、蚀刻等工艺形成了导电线路和焊盘,用于固定和连接各种电子元件。
    Jeffreyzhang123 2024-12-27 17:21 68浏览
  • 引言工程师作为推动科技进步和社会发展的核心力量,在各个领域发挥着关键作用。为深入了解工程师的职场现状,本次调研涵盖了不同行业、不同经验水平的工程师群体,通过问卷调查、访谈等方式,收集了大量一手数据,旨在全面呈现工程师的职场生态。1. 工程师群体基本信息行业分布:调研结果显示,工程师群体广泛分布于多个行业,其中制造业占比最高,达到 90%,其次是信息技术、电子通信、能源等行业。不同行业的工程师在工作内容、技术要求和职业发展路径上存在一定差异。年龄与经验:工程师群体以中青年为主,30 - 45 岁年
    Jeffreyzhang123 2024-12-27 17:39 86浏览
  • 在科技飞速发展的今天,医疗电子作为一个融合了医学与电子技术的交叉领域,正以前所未有的速度改变着我们的医疗模式和健康生活。它宛如一颗璀璨的明珠,在医疗领域绽放出耀眼的光芒,为人类的健康福祉带来了诸多惊喜与变革。医疗电子的神奇应用医疗电子的应用范围极为广泛,深入到医疗的各个环节。在诊断方面,各种先进的医学成像设备堪称医生的 “火眼金睛”。X 光、CT、MRI 等成像技术,能够清晰地呈现人体内部的结构和病变情况,帮助医生准确地发现疾病。以 CT 为例,它通过对人体进行断层扫描,能够提供比传统 X 光更
    Jeffreyzhang123 2024-12-27 15:46 78浏览
  • 在当今这个科技飞速发展的时代,物联网(IoT)已经不再是一个陌生的概念,它正以一种前所未有的速度改变着我们的生活和工作方式,像一股无形的力量,将世界紧密地连接在一起,引领我们步入一个全新的智能时代。物联网是什么简单来说,物联网就是通过感知设备、网络传输、数据处理等技术手段,实现物与物、人与物之间的互联互通和智能化管理。想象一下,你的家里所有的电器都能 “听懂” 你的指令,根据你的习惯自动调节;工厂里的设备能够实时监测自身状态,提前预警故障;城市的交通系统可以根据实时路况自动优化信号灯,减少拥堵…
    Jeffreyzhang123 2024-12-27 17:18 68浏览
  • 一、前言 回首2024,对于我而言,是充满挑战与收获的一年。在这一年里,我积极参与了论坛的众多活动,不仅拓宽了我的认知边界(有些东西不是你做不到,而是你想不到),还让我在实践中收获了宝贵的经验和。同时,多种多样的论坛活动让我们全方面的接受新东西,连接新知识,多种类型的的活动交织了你我的2024。在这里说一说对过去一年的活动经历,进行一次年终总结,并谈谈我的收获和感受,以及对2025年的展望。二、活动足迹(一)快速体验:机智云Gokit2.0开发板初体验 机智云Gokit2.0开发板的体验活动让大
    无言的朝圣 2024-12-27 14:50 60浏览
  • 在科技飞速发展的今天,汽车不再仅仅是一种交通工具,更是一个融合了先进技术的移动智能空间。汽车电子作为汽车产业与电子技术深度融合的产物,正以前所未有的速度推动着汽车行业的变革,为我们带来更加智能、安全、舒适的出行体验。汽车电子的发展历程汽车电子的发展可以追溯到上世纪中叶。早期,汽车电子主要应用于发动机点火系统和简单的电子仪表,功能相对单一。随着半导体技术的不断进步,集成电路被广泛应用于汽车领域,使得汽车电子系统的性能得到了显著提升。从电子燃油喷射系统到防抱死制动系统(ABS),从安全气囊到车载导航
    Jeffreyzhang123 2024-12-27 11:53 93浏览
  • 在当今科技飞速发展的时代,工业电子作为现代制造业的中流砥柱,正以前所未有的速度推动着各个行业的变革与进步。从汽车制造到航空航天,从智能家居到工业自动化,工业电子的身影无处不在,为我们的生活和生产带来了巨大的改变。工业电子的崛起与发展工业电子的发展历程可谓是一部波澜壮阔的科技进化史。追溯到上世纪中叶,电子技术开始逐渐应用于工业领域,最初主要是简单的电子控制装置,用于提高生产过程的自动化程度。随着半导体技术、计算机技术和通信技术的不断突破,工业电子迎来了爆发式的增长。集成电路的发明使得电子设备的体积
    Jeffreyzhang123 2024-12-27 15:40 88浏览
我要评论
0
点击右上角,分享到朋友圈 我知道啦
请使用浏览器分享功能 我知道啦