【轻量级开源ROS 的机器人设备(5)】--(2)拟议的框架——µROS节点

news2024/11/18 20:46:58

接上文:

【轻量级开源ROS 的机器人设备(5)】--(1)拟议的框架——µROS节点

四、开发工具

        为了方便用户应用程序的开发,一个代码生成器,一个 堆栈使用分析器和演示项目包含在框架中包裹。

4.1 代码生成器

        手工编写编组过程和主题/服务处理例程可以 需要很多时间,而且这是一个容易出错的任务。编组的产生 过程可以通过处理传递的消息描述符来自动化 与 ROS 包。此外,处理程序例程共享一个通用框架, 可以被利用和重用。既然如此,生成工具,urogen (作为 Python 2.7 脚本 urosgen.py 实现)被开发出来。

4.2 编译流程

        图 5.3 中描述的编译流程非常简单。该工具通过一个文件(清单 B.11 中的完整示例)进行配置,其中列出了主题/服务名称和类型,以及一些选项。一旦涉及的消息类型名称已知,该工具就会从已安装 ROS 包的相关 .msg 和 .srv 文件中加载它们的描述。最后,处理消息类型,从而产生编组和解组函数。为配置文件中列出的那些名称生成主题和服务处理程序存根。该工具还为 Doxygen 生成详细的自我文档(未在列表示例和大多数评论中报告)。

4.3 名称修改

        所有 ROS 名称都具有类似路径的结构,以 /(斜杠)作为分隔符。 C标识符不能包含它,因此通过将 / 替换为来破坏 ROS 名称__(双下划线)。主题和服务错位名称总是以 __ 开头,因为它们有一个隐含/开头。

4.4 消息

        通过调用 rosmsg show 从它的 .msg 文件加载消息类型,它删除注释并具有简洁的语法。其固有结构映射到 C 结构,其中损坏的名称以 msg__ (msg_name) 为前缀。原始类型被直接映射,而嵌套消息类型被声明分别地。为了符合C语言,结构体定义在拓扑顺序;这是可以做到的,因为 ROS 类型不能有循环依赖项。

struct msg__rosgraph_msgs__Log {
2 struct msg__std_msgs__Header header;
3 uint8_t level;
4 UrosString name;
5 UrosString msg;
6 UrosString file;
7 UrosString function;
8 uint32_t line;
9 UROS_VARARR(UrosString) topics;
10 };
11
12 #define msg__rosgraph_msgs__Log__DEBUG ((uint8_t)1)
13 #define msg__rosgraph_msgs__Log__INFO ((uint8_t)2)
14 #define msg__rosgraph_msgs__Log__WARN ((uint8_t)4)
15 #define msg__rosgraph_msgs__Log__ERROR ((uint8_t)8)
16 #define msg__rosgraph_msgs__Log__FATAL ((uint8_t)16)

Listing 5.1: Definition of the rosgraph_msgs/Log descriptor and its constant values

size_t length_msg__rosgraph_msgs__Log(
2 struct msg__rosgraph_msgs__Log *objp
3 ) {
4 size_t length = 0;
5 uint32_t i;
6
7 urosAssert(objp != NULL);
8
9 length += length_msg__std_msgs__Header(&objp->header);
10 length += sizeof(uint8_t);
11 length += sizeof(uint32_t) + objp->name.length;
12 length += sizeof(uint32_t) + objp->msg.length;
13 length += sizeof(uint32_t) + objp->file.length;
14 length += sizeof(uint32_t) + objp->function.length;
15 length += sizeof(uint32_t);
16 length += sizeof(uint32_t);
17 length += (size_t)objp->topics.length * sizeof(uint32_t);
18 for (i = 0; i < objp->topics.length; ++i) {
19 length += objp->topics.entriesp[i].length;
20 }
21
22 return length;
23 }

Listing 5.2: Stream length computation of a rosgraph_msgs/Log message

消息类型示例 rosgraph_msgs/Log 在清单 5.1 中。
代码生成器为以下操作创建函数:初始化,
清理、长度计算、编组和解组。
初始化函数(init_+msg_name,清单 5.3)设置初步的安全值。清理函数(clean_+msg_name,清单 5.4)
释放任何分配的字段,达到安全初始化状态。
长度计算函数(length_+msg_name,清单 5.2)计算
序列化消息的长度。
编组函数(send_+msg_name,清单 5.6)序列化消息内容并通过输出 TCPROS 流发送它们。反而,
解组函数(recv_+msg_name,清单 5.5)反序列化
从传入的 TCPROS 流中接收到消息

void init_msg__rosgraph_msgs__Log(
2 struct msg__rosgraph_msgs__Log *objp
3 ) {
4 uint32_t i;
5
6 urosAssert(objp != NULL);
7
8 init_msg__std_msgs__Header(&objp->header);
9 urosStringObjectInit(&objp->name);
10 urosStringObjectInit(&objp->msg);
11 urosStringObjectInit(&objp->file);
12 urosStringObjectInit(&objp->function);
13 urosTcpRosArrayObjectInit((UrosTcpRosArray *)&objp->topics);
14 for (i = 0; i < objp->topics.length; ++i) {
15 urosStringObjectInit(&objp->topics.entriesp[i]);
16 }
17 }

Listing 5.3: Initialization of a rosgraph_msgs/Log descriptor

1 void clean_msg__rosgraph_msgs__Log(
2 struct msg__rosgraph_msgs__Log *objp
3 ) {
4 uint32_t i;
5
6 if (objp == NULL) { return; }
7
8 clean_msg__std_msgs__Header(&objp->header);
9 urosStringClean(&objp->name);
10 urosStringClean(&objp->msg);
11 urosStringClean(&objp->file);
12 urosStringClean(&objp->function);
13 for (i = 0; i < objp->topics.length; ++i) {
14 urosStringClean(&objp->topics.entriesp[i]);
15 }
16 urosTcpRosArrayClean((UrosTcpRosArray *)&objp->topics);
17 }
Listing 5.4: Cleaning function of a rosgraph_msgs/Log descriptor
1 uros_err_t recv_msg__rosgraph_msgs__Log(
2 UrosTcpRosStatus *tcpstp,
3 struct msg__rosgraph_msgs__Log *objp
4 ) {
5 uint32_t i;
6
7 urosAssert(tcpstp != NULL);
8 urosAssert(urosConnIsValid(tcpstp->csp));
9 urosAssert(objp != NULL);
10 #define _CHKOK { if (tcpstp->err != UROS_OK) { goto _error; } }
11
12 recv_msg__std_msgs__Header(tcpstp, &objp->header); _CHKOK
13 urosTcpRosRecvRaw(tcpstp, objp->level); _CHKOK
14 urosTcpRosRecvString(tcpstp, &objp->name); _CHKOK
15 urosTcpRosRecvString(tcpstp, &objp->msg); _CHKOK
16 urosTcpRosRecvString(tcpstp, &objp->file); _CHKOK
17 urosTcpRosRecvString(tcpstp, &objp->function); _CHKOK
18 urosTcpRosRecvRaw(tcpstp, objp->line); _CHKOK
19 urosTcpRosArrayObjectInit((UrosTcpRosArray *)&objp->topics);
20 urosTcpRosRecvRaw(tcpstp, objp->topics.length); _CHKOK
21 objp->topics.entriesp = urosArrayNew(objp->topics.length,
22 UrosString);
23 if (objp->topics.entriesp == NULL) { tcpstp->err = UROS_ERR_NOMEM; goto _error; }
24 for (i = 0; i < objp->topics.length; ++i) {
25 urosTcpRosRecvString(tcpstp, &objp->topics.entriesp[i]); _CHKOK
26 }
27
28 return tcpstp->err = UROS_OK;
29 _error:
30 clean_msg__rosgraph_msgs__Log(objp);
31 return tcpstp->err;
32 #undef _CHKOK
33 }
Listing 5.5: Reception and unmarshaling of a rosgraph_msgs/Log message
1 uros_err_t send_msg__rosgraph_msgs__Log(
2 UrosTcpRosStatus *tcpstp,
3 struct msg__rosgraph_msgs__Log *objp
4 ) {
5 uint32_t i;
6
7 urosAssert(tcpstp != NULL);
8 urosAssert(urosConnIsValid(tcpstp->csp));
9 urosAssert(objp != NULL);
10 #define _CHKOK { if (tcpstp->err != UROS_OK) { return tcpstp->err; } }
11
12 send_msg__std_msgs__Header(tcpstp, &objp->header); _CHKOK
13 urosTcpRosSendRaw(tcpstp, objp->level); _CHKOK
14 urosTcpRosSendString(tcpstp, &objp->name); _CHKOK
15 urosTcpRosSendString(tcpstp, &objp->msg); _CHKOK
16 urosTcpRosSendString(tcpstp, &objp->file); _CHKOK
17 urosTcpRosSendString(tcpstp, &objp->function); _CHKOK
18 urosTcpRosSendRaw(tcpstp, objp->line); _CHKOK
19 urosTcpRosSendRaw(tcpstp, objp->topics.length); _CHKOK
20 for (i = 0; i < objp->topics.length; ++i) {
21 urosTcpRosSendString(tcpstp, &objp->topics.entriesp[i]); _CHKOK
22 }
23
24 return tcpstp->err = UROS_OK;
25 #undef _CHKOK
26 }
Listing 5.6: Marshaling and transmission of a rosgraph_msgs/Log message

4.5 服务讯息

        服务消息是一对普通的输入/输出消息,因此被拆分为输入结构(in_srv__ + 损坏的名称,in_name)和输出结构(out_srv__ + mangled name, out_name),如清单 5.7 所示。他们是
通过调用 rossrv show 从相关的 .srv 文件加载,类似于普通消息。
每个子消息都有专门的初始化(清单 5.9)、清理(清单 5.10)和长度计算(清单 5.8)函数,以及上面看到的赋值和前缀。
        只有输入消息有解组函数(recv_+in_name,清单 5.11),而只有输出消息具有编组功能(send_+out_name,清单 5.12)。

4.6 类型注册

        urosMsgTypesRegStaticTypes() 过程将所有消息类型注册到它们各自的静态寄存器(参见第 5.2.1 节),如清单 5.13 所示。

4.7 处理例程

        处理例程,除了服务调用的例程,应该在内部工作他们自己的线程。用户可以决定是否放置本地消息变量在堆栈或堆中,优化和协调内存管理;根据经验,小消息描述符放在堆栈上,大消息堆上的描述符。

4.8 主题发布者

        主题发布者例程,pub_tpc + mangled name,生成并向订阅者发送纯消息,直到断开连接。生成的模板可以在清单 5.14 中看到,其中消息描述符被分配到堆中。用户只需要移除假人循环语句,并填写 msgp 描述符字段。

4.9 主题订阅者

另一方面,主题订阅者例程 sub_tpc+ 损坏的名称,不断接收和处理消息,直到断开连接。

1 struct in_srv__turtlesim__Spawn {
2 float x;
3 float y;
4 float theta;
5 UrosString name;
6 };
7
8 struct out_srv__turtlesim__Spawn {
9 UrosString name;
10 };

Listing 5.7: Definition of the turtlesim/Spawn descriptors

1 size_t length_in_srv__turtlesim__Spawn(
2 struct in_srv__turtlesim__Spawn *objp
3 ) {
4 size_t length = 0;
5
6 urosAssert(objp != NULL);
7
8 length += sizeof(float);
9 length += sizeof(float);
10 length += sizeof(float);
11 length += sizeof(uint32_t) + objp->name.length;
12
13 return length;
14 }
15
16 size_t length_out_srv__turtlesim__Spawn(
17 struct out_srv__turtlesim__Spawn *objp
18 ) {
19 size_t length = 0;
20
21 urosAssert(objp != NULL);
22
23 length += sizeof(uint32_t) + objp->name.length;
24
25 return length;
26 }

Listing 5.8: Stream length computation of turtlesim/Spawn messages

如清单 5.15 所示,用户只需要处理收到的消息,msgp。
Service publishers 服务发布者,pub_srv + mangled name,接收请求消息(in_name),处理,然后发送响应如果成功则为消息 (out_name),如果不成功则为错误字符串。如果尝试仍然存在,则重复这些操作直到断开连接。
清单 5.16 是服务发布者生成的模板。这是一个工会消息接收和传输,因此用户必须为两者提供代码请求处理和响应生成。

4.10 服务调用

        服务调用例程 call_srv + 损坏的名称由客户端执行。它向发布者发送请求,然后接收响应或错误字符串。与在其主体内生成或处理消息的其他处理程序例程相反,服务调用例程仅用于通信;消息描述符也在外面分配。清单 5.17 中显示了生成的处理程序的示例。用户不需要做任何事情,但建议在收到响应之前释放请求描述符,以减少内存使用。

void init_in_srv__turtlesim__Spawn(
2 struct in_srv__turtlesim__Spawn *objp
3 ) {
4 urosAssert(objp != NULL);
5
6 urosStringObjectInit(&objp->name);
7 }
8
9 void init_out_srv__turtlesim__Spawn(
10 struct out_srv__turtlesim__Spawn *objp
11 ) {
12 urosAssert(objp != NULL);
13
14 urosStringObjectInit(&objp->name);
15 }
Listing 5.9: Initialization of turtlesim/Spawn descriptors
1 void clean_in_srv__turtlesim__Spawn(
2 struct in_srv__turtlesim__Spawn *objp
3 ) {
4 urosAssert(objp != NULL);
5
6 urosStringClean(&objp->name);
7 }
8
9 void clean_out_srv__turtlesim__Spawn(
10 struct out_srv__turtlesim__Spawn *objp
11 ) {
12 urosAssert(objp != NULL);
13
14 urosStringClean(&objp->name);
15 }
Listing 5.10: Cleaning function of turtlesim/Spawn descriptors
1 uros_err_t recv_in_srv__turtlesim__Spawn(
2 UrosTcpRosStatus *tcpstp,
3 struct in_srv__turtlesim__Spawn *objp
4 ) {
5 urosAssert(tcpstp != NULL);
6 urosAssert(urosConnIsValid(tcpstp->csp));
7 urosAssert(objp != NULL);
8 #define _CHKOK { if (tcpstp->err) { goto _error; } }
9
10 urosTcpRosRecvRaw(tcpstp, objp->x); _CHKOK
11 urosTcpRosRecvRaw(tcpstp, objp->y); _CHKOK
12 urosTcpRosRecvRaw(tcpstp, objp->theta); _CHKOK
13 urosTcpRosRecvString(tcpstp, &objp->name); _CHKOK
14
15 return tcpstp->err = UROS_OK;
16 _error:
17 clean_in_srv__turtlesim__Spawn(objp);
18 return tcpstp->err;
19 #undef _CHKOK
20 }
Listing 5.11: Reception and unmarshaling of a turtlesim/Spawn request message
1 uros_err_t send_out_srv__turtlesim__Spawn(
2 UrosTcpRosStatus *tcpstp,
3 struct out_srv__turtlesim__Spawn *objp
4 ) {
5 urosAssert(tcpstp != NULL);
6 urosAssert(urosConnIsValid(tcpstp->csp));
7 urosAssert(objp != NULL);
8 #define _CHKOK { if (tcpstp->err) { return tcpstp->err; } }
9
10 urosTcpRosSendString(tcpstp, &objp->name); _CHKOK
11
12 return tcpstp->err = UROS_OK;
13 #undef _CHKOK
14 }
Listing 5.12: Marshaling and transmission of a turtlesim/Spawn response message
1 void urosMsgTypesRegStaticTypes(void) {
2
3 urosRegisterStaticMsgTypeSZ("rosgraph_msgs/Log",
4 NULL, "acffd30cd6b6de30f120938c17c593fb");
5
6 urosRegisterStaticMsgTypeSZ("std_msgs/Header",
7 NULL, "2176decaecbce78abc3b96ef049fabed");
8
9 urosRegisterStaticSrvTypeSZ("turtlesim/Spawn",
10 NULL, "0b2d2e872a8e2887d5ed626f2bf2c561");
11 }
Listing 5.13: Registration of the static types used in the examples above
1 uros_err_t pub_tpc__rosout(UrosTcpRosStatus *tcpstp) {
2
3 UROS_TPC_INIT_H(msg__rosgraph_msgs__Log);
4
5 while (!urosTcpRosStatusCheckExit(tcpstp)) {
6 /* TODO: Generate the contents of the message.*/
7 urosThreadSleepSec(1); continue; /* TODO: Remove this dummy line.*/
8
9 UROS_MSG_SEND_LENGTH(msgp, msg__rosgraph_msgs__Log);
10 UROS_MSG_SEND_BODY(msgp, msg__rosgraph_msgs__Log);
11
12 clean_msg__rosgraph_msgs__Log(msgp);
13 }
14 tcpstp->err = UROS_OK;
15
16 _finally:
17 UROS_TPC_UNINIT_H(msg__rosgraph_msgs__Log);
18 return tcpstp->err;
19 }
Listing 5.14: Generated handler template for a common /rosout publisher

1 uros_err_t sub_tpc__rosout(UrosTcpRosStatus *tcpstp) {
2
3 UROS_TPC_INIT_H(msg__rosgraph_msgs__Log);
4
5 while (!urosTcpRosStatusCheckExit(tcpstp)) {
6 UROS_MSG_RECV_LENGTH();
7 UROS_MSG_RECV_BODY(msgp, msg__rosgraph_msgs__Log);
8
9 /* TODO: Process the received message.*/
10
11 clean_msg__rosgraph_msgs__Log(msgp);
12 }
13 tcpstp->err = UROS_OK;
14
15 _finally:
16 UROS_TPC_UNINIT_H(msg__rosgraph_msgs__Log);
17 return tcpstp->err;
18 }
Listing 5.15: Generated handler template for a /rosout subscriber
1 uros_err_t pub_srv__reconfigure(UrosTcpRosStatus *tcpstp) {
2
3 UROS_SRV_INIT_HISO(in_srv__dynamic_reconfigure__Reconfigure,
4 out_srv__dynamic_reconfigure__Reconfigure);
5
6 do {
7 UROS_MSG_RECV_LENGTH();
8 UROS_MSG_RECV_BODY(inmsgp, in_srv__dynamic_reconfigure__Reconfigure);
9
10 /* TODO: Process the request message.*/
11 tcpstp->err = UROS_OK;
12 urosStringClean(&tcpstp->errstr);
13 okByte = 1;
14
15 clean_in_srv__dynamic_reconfigure__Reconfigure(inmsgp);
16
17 /* TODO: Generate the contents of the response message.*/
18
19 UROS_SRV_SEND_OKBYTE_ERRSTR();
20 UROS_MSG_SEND_LENGTH(&outmsg, out_srv__dynamic_reconfigure__Reconfigure);
21 UROS_MSG_SEND_BODY(&outmsg, out_srv__dynamic_reconfigure__Reconfigure);
22
23 clean_out_srv__dynamic_reconfigure__Reconfigure(&outmsg);
24 } while (tcpstp->topicp->flags.persistent &&
25 !urosTcpRosStatusCheckExit(tcpstp));
26 tcpstp->err = UROS_OK;
27
28 _finally:
29 UROS_SRV_UNINIT_HISO(in_srv__dynamic_reconfigure__Reconfigure,
30 out_srv__dynamic_reconfigure__Reconfigure);
31 return tcpstp->err;
32 }
Listing 5.16: Generated handler template for a service publisher
1 uros_err_t call_srv__reconfigure(
2 UrosTcpRosStatus *tcpstp,
3 struct in_srv__dynamic_reconfigure__Reconfigure *inmsgp,
4 struct out_srv__dynamic_reconfigure__Reconfigure *outmsgp
5 ) {
6
7 UROS_SRVCALL_INIT(in_srv__dynamic_reconfigure__Reconfigure,
8 out_srv__dynamic_reconfigure__Reconfigure);
9
10 UROS_MSG_SEND_LENGTH(inmsgp, in_srv__dynamic_reconfigure__Reconfigure);
11 UROS_MSG_SEND_BODY(inmsgp, in_srv__dynamic_reconfigure__Reconfigure);
12
13 /* TODO: Dispose the contents of the request message.*/
14
15 UROS_SRV_RECV_OKBYTE();
16 UROS_MSG_RECV_LENGTH();
17 UROS_MSG_RECV_BODY(outmsgp, out_srv__dynamic_reconfigure__Reconfigure);
18
19 tcpstp->err = UROS_OK;
20 _finally:
21 return tcpstp->err;
22 }
Listing 5.17: Generated handler template for a client service call

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

截止12.17 bitahub踩坑,mask无数次更改,lama代码的那些痛,羊了个羊

前面那篇跑出了STCN&#xff0c;倒是STCN熟悉了很多了 对bitahub&#xff0c;需要注意一个问题 要进ssh请用debug卡&#xff01;&#xff01;&#xff01;&#xff01; 要进ssh请用debug卡&#xff01;&#xff01;&#xff01;&#xff01; 要进ssh请用debug卡&#xff01;&…

数据库文档展示工具

实用工具&#xff1a;数据库文档展示工具 简介 数据库文档展示工具&#xff08;database doc&#xff09;&#xff0c;又叫数据库注释浏览工具&#xff0c;是一个简单的数据库展示各个字段注释的开源工具。在日常开发工作中&#xff0c;您有否这样的体验&#xff1f; 想给前…

干货 | 数字经济创新创业——数字技术创造新经济

下文整理自清华大学大数据能力提升项目能力提升模块课程“Innovation & Entrepreneurship for Digital Economy”&#xff08;数字经济创新创业课程)的精彩内容。主讲嘉宾&#xff1a;Kris Singh: CEO at SRII, Palo Alto, CaliforniaVisiting Professor of Tsinghua Unive…

Elasticsearch 多索引搜索 多条件筛选 去除重复数据

Elasticsearch 多索引搜索 多条件筛选先看结构 分别是索引media_data_es,live_room_essearch_type :dfs_query_then_fetch 不重复复合查询 复合查询就是把一些简单查询组合在一起实现更复杂的查询需求&#xff0c;除此之外&#xff0c;复合查询还可以控制另外一个查询的行为。 …

Spring MVC介绍

Spring MVC 简介什么是Spring MVC了解 MVCMVC 和Spring MVC的联系如何创建一个Spring Web项目在Spring Web 项目中&#xff0c;如何连接Http请求Controller注解可以用其他类注解代替吗连接其他类型的请求如何获取请求中的数据获取单个请求参数获取多个请求参数获取对象获取表单…

高通平台开发系列讲解(DSI篇)DSI层在拨号中的调用逻辑

沉淀、分享、成长,让自己和他人都能有所收获!😄 📢DSI层在拨号中起到的是承上启下的作用。 拨号初始化: 通过mcm_data_init_srv接口调用dsi_init_ex接口,而dsi_init_ex接口进一步通过依次调用dsi_init_cb_func来初始化注册回调、dsi_init_cb_data来初始化数据回调及dsi…

XXL-Job分布式任务调度框架-- 介绍和服务搭建1

一 xxl-job介绍 1.1 xxl-job介绍 xxl-job是轻量级的分布式任务调度框架&#xff0c;目标是开发迅速、简单、清理、易扩展; 老版本是依赖quartz的定时任务触发&#xff0c;在v2.1.0版本开始 移除quartz依 。 分布式任务调度平台XXL-JOB/ 分布式任务调度平台XXL-JOB 二 xxl-…

Prometheus之集成Flink

目录1. 基本介绍2. 拷贝Flink jar包3. 修改Flink的配置文件flink-conf.yaml4. 重启Flink集群5. 验证是否集成成功1. 基本介绍 Flink提供的Metrics可以在Flink内部收集一些指标&#xff0c;通过这些指标让开发人员更 好地查看作业或集群的状态 2. 拷贝Flink jar包 在Flink集群…

[附源码]Node.js计算机毕业设计互联网在线笔记管理系统Express

项目运行 环境配置&#xff1a; Node.js最新版 Vscode Mysql5.7 HBuilderXNavicat11Vue。 项目技术&#xff1a; Express框架 Node.js Vue 等等组成&#xff0c;B/S模式 Vscode管理前后端分离等等。 环境需要 1.运行环境&#xff1a;最好是Nodejs最新版&#xff0c;我…

【C++】list的介绍和使用

​&#x1f320; 作者&#xff1a;阿亮joy. &#x1f386;专栏&#xff1a;《吃透西嘎嘎》 &#x1f387; 座右铭&#xff1a;每个优秀的人都有一段沉默的时光&#xff0c;那段时光是付出了很多努力却得不到结果的日子&#xff0c;我们把它叫做扎根 目录&#x1f449;list 的介…

操作系统原理和接口

这个阶段的课程讲授操作系统的原理和Linux系统给应用层提供的C编程接口。操作系统通过系统调用提供的抽象层是一切中间层和应用软件的根本。 课程建设思路-传统误区 长久以来这个阶段的课程是按照《UNIX环境高级编程》这本书进行讲解的。这个环节的课程甚至曾因此被称为"高…

新能源电动汽车充电桩收费平台

安科瑞 华楠 一、业务模式 平台客户 两种合作方式 1&#xff09;数据托管方式 安科瑞指导用户完成充电桩的安装&#xff0c;用户的充电桩将数据上传至安科瑞充电桩收费运营云平台&#xff0c;委托安科瑞管理&#xff0c;按规定/约定收取托管费用。 2&#xff09;用户自建平…

D-028 DDR3硬件电路设计

DDR3硬件电路设计1 简介2 电路设计3 设计要点1 简介 RAM&#xff08;Random Access Memory&#xff09;是随机存储器&#xff0c;存储单元中的内容可以按需任意去除或者存入&#xff0c;并且存取的速度与存储单元的位置无关。这种存储器在断电时&#xff0c;将丢失其存储的内容…

@Pointcut 的 12 种用法

这里写自定义目录标题欢迎使用Markdown编辑器新的改变功能快捷键合理的创建标题&#xff0c;有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants创建一个自定义列表如何创建一个注…

数据结构---鸡尾酒排序

鸡尾酒排序是基于冒泡排序的一种升级排序法&#xff08;双向冒泡排序&#xff09;冒泡排序&#xff1a;每一轮都是从左到右来比较元素&#xff0c;进行单向的位置交换的。鸡尾酒排序的元素比较和交换过程是双向的。解决的问题如下&#xff1a;从小到大排序{2,3,4,5,6,7,8,1} 如…

微服务框架 SpringCloud微服务架构 多级缓存 48 多级缓存 48.9 Nginx 本地缓存

微服务框架 【SpringCloudRabbitMQDockerRedis搜索分布式&#xff0c;系统详解springcloud微服务技术栈课程|黑马程序员Java微服务】 多级缓存 文章目录微服务框架多级缓存48 多级缓存48.9 Nginx 本地缓存48.9.1 Nginx本地缓存需求48.9.2 Nginx 本地缓存48 多级缓存 48.9 Ng…

LCHub:伙伴云荣获21世纪商业模式高峰论坛 低代码平台明星企业

12月13日,由南方财经全媒体集团指导,《21世纪商业评论》、《21世纪经济报道》联合主办的“21 世纪商业模式高峰论坛(2022)”在上海绿地万豪酒店举行。 大会公布了21 世纪商业模式竞争力研究榜单,伙伴云凭借在低/无代码领域的技术创新,领先的商业模式和多维度专业服务能力,…

java设计模式之建造者模式(Builder Pattern)

目的&#xff1a;将产品与产品的创建过程解耦 。他是按照相应的步骤来构建产品 下面看一下UML序列图 对于序列图的一个解释 下面来上一个标准代码 Product.java package com.pxx;public class Product {private String shape;private int height;private String color;publ…

OAuth2四种授权模式

授权码模式 授权码模式&#xff08;Authorization Code&#xff09; 是功能最完整、流程最严密、最安全并且使用最广泛的一种OAuth2授权模式。同时也是最复杂的一种授权模式&#xff0c;它的特点就是通过客户端的后台服务器&#xff0c;与服务提供商的认证服务器进行互动。其具…

SpringMVC学习笔记 | SpringMVC从入门到源码分析

一、SpringMVC导学 二、SpringMVC简介 MVC M&#xff1a;模型 Model 指工程中的JavaBean 一类称为实体类Bean&#xff1a;专门存储业务数据的&#xff0c;如 Student、User 等一类称为业务处理 Bean&#xff1a;指 Service 或 Dao 对象&#xff0c;专门用于处理业务逻辑和数据访…