CANopen for Python

系列文章目录


前言

        该软件包支持与 CANopen 节点网络交互。

        注意 这里的大部分文档都是从 CANopen 维基百科页面上直接盗用的。
        本文档正在编写中。欢迎反馈和修改!

        CANopen 是用于自动化领域嵌入式系统的通信协议和设备配置文件规范。根据 OSI 模型,CANopen 实现了网络层以上(包括网络层)的各层。CANopen 标准包括一个寻址方案、几个小型通信协议和一个由设备配置文件定义的应用层。通信协议支持网络管理、设备监控和节点之间的通信,包括一个用于报文分段/解分段的简单传输层。

        最简单的安装方法是使用 pip:

pip install canopen
  • 网络和节点
  • 对象字典
  • 网络管理 (NMT)
  • 服务数据对象 (SDO)
  • 进程数据对象 (PDO)
  • 同步对象 (SYNC)
  • 紧急对象 (EMCY)
  • 时间戳对象(TIME)
  • 层设置服务 (LSS)
  • 与现有代码集成
  • 设备配置文件 

 


一、网络和节点

        canopen.Network 表示连接到同一条 CAN 总线的节点集合。它处理报文的发送和接收,并将报文发送到它所知道的节点。

        每个节点都使用 canopen.RemoteNode 或 canopen.LocalNode 类来表示。它通常与一个对象字典相关联,每个服务都有自己的属性,由该节点所有。

1.1 示例

        为每条 CAN 总线创建一个网络:

import canopennetwork = canopen.Network()

        默认情况下,该库使用 python-can 进行实际通信。有关如何配置特定接口的详细信息,请参阅其文档。

        调用 connect() 方法启动通信,可选择提供传递给 can.BusABC 构造函数的参数:

network.connect(channel='can0', bustype='socketcan')
# network.connect(bustype='kvaser', channel=0, bitrate=250000)
# network.connect(bustype='pcan', channel='PCAN_USBBUS1', bitrate=250000)
# network.connect(bustype='ixxat', channel=0, bitrate=250000)
# network.connect(bustype='nican', channel='CAN0', bitrate=250000)

        使用 add_node() 方法向网络中添加节点:

node = network.add_node(6, '/path/to/object_dictionary.eds')local_node = canopen.LocalNode(1, '/path/to/master_dictionary.eds')
network.add_node(local_node)

        节点也可以使用作为 Python 字典的网络对象来访问:

for node_id in network:print(network[node_id])

        要自动检测网络上存在哪些节点,可以使用扫描仪属性:

# This will attempt to read an SDO from nodes 1 - 127
network.scanner.search()
# We may need to wait a short while here to allow all nodes to respond
time.sleep(0.05)
for node_id in network.scanner.nodes:print(f"Found node {node_id}!")

        最后,确保完成后断开连接:

network.disconnect()

二、对象字典

        CANopen 设备必须有一个对象字典,用于配置和与设备通信。对象字典中的条目定义如下

  • 索引,对象在字典中的 16 位地址
  • 对象类型,如数组、记录或简单变量
  • 名称,描述条目的字符串
  • 类型,给出变量的数据类型(或数组中所有变量的数据类型)
  • 属性,提供该条目访问权限的信息,可以是读/写(rw)、只读(ro)或只写(wo)。

        标准中定义了布尔值、整数和浮点数等对象字典值的基本数据类型,以及字符串、数组和记录等复合数据类型。复合数据类型可使用 8 位索引进行子索引;数组或记录的子索引 0 中的值表示数据结构中的元素个数,其类型为 UNSIGNED8。

2.1 支持的格式

        目前支持用于指定节点对象字典的文件格式有

  • EDS (类似 INI 文件的标准化格式)
  • DCF(与 EDS 格式相同,但指定了比特率和节点 ID)
  • EPF(Inmotion Technologies 使用的专有 XML 格式)

2.2 示例

        对象字典文件通常在创建节点时提供。下面是一个打印出整个对象字典的示例:

node = network.add_node(6, 'od.eds')
for obj in node.object_dictionary.values():print(f'0x{obj.index:X}: {obj.name}')if isinstance(obj, canopen.objectdictionary.ODRecord):for subobj in obj.values():print(f'  {subobj.subindex}: {subobj.name}')

        您可以使用索引/子索引或名称访问对象:

device_name_obj = node.object_dictionary['ManufacturerDeviceName']
vendor_id_obj = node.object_dictionary[0x1018][1]
actual_speed = node.object_dictionary['ApplicationStatus.ActualSpeed']
command_all = node.object_dictionary['ApplicationCommands.CommandAll']

三、网络管理 (NMT)

        NMT 协议用于发出状态机更改命令(如启动和停止设备)、检测远程设备启动和错误状况。

        模块控制协议用于 NMT 主站改变设备状态。该协议的 CAN 帧 COB-ID 始终为 0,即功能代码为 0,节点 ID 为 0,这意味着网络中的每个节点都将处理该报文。命令的实际节点 ID 在报文的数据部分(第二个字节)给出。节点 ID 也可以是 0,这意味着总线上的所有设备都应进入指定状态。

        心跳协议用于监控网络中的节点并验证它们是否存活。心跳生成器(通常是从属设备)会定期发送带有二进制功能代码 1110 及其节点 ID(COB-ID = 0x700 + 节点 ID)的报文。帧的数据部分包含一个表示节点状态的字节。心跳用户会读取这些报文。

        CANopen 设备需要在启动过程中自动从 "初始化 "状态过渡到 "预运行 "状态。转换完成后,会向总线发送一条心跳报文。这就是启动协议。

3.1 示例

        使用 canopen.Node.nmt 属性访问 NMT 功能。可使用 state 属性改变状态:

node.nmt.state = 'OPERATIONAL'
# Same as sending NMT start
node.nmt.send_command(0x1)

        您还可以通过广播信息同时改变所有节点的状态:

network.nmt.state = 'OPERATIONAL'

        如果节点发送心跳信息,状态属性就会自动更新为当前状态:

# Send NMT start to all nodes
network.send_message(0x0, [0x1, 0])
node.nmt.wait_for_heartbeat()
assert node.nmt.state == 'OPERATIONAL'

四、服务数据对象 (SDO)

        SDO 协议用于设置和读取远程设备对象字典中的值。访问对象字典的设备是 SDO 服务器,访问远程设备的设备是 SDO 客户端。通信始终由 SDO 客户端发起。在 CANopen 术语中,通信是从 SDO 服务器开始的,因此从对象字典中读取数据是 SDO 上传,而写入字典条目则是 SDO 下载。

        由于对象字典值可能大于 CAN 帧的 8 字节限制,因此 SDO 协议实现了对较长报文的分割和解分割。实际上,有两个这样的协议: SDO 下载/上传和 SDO 块下载/上传。SDO 数据块传输是新增加的标准,可以传输大量数据,协议开销略低。

        客户机到服务器和服务器到客户机的各自 SDO 传输信息的 COB-ID 可在对象字典中设置。最多可在对象字典中设置 128 个 SDO 服务器,地址为 0x1200 - 0x127F。同样,设备的 SDO 客户端连接也可通过 0x1280 - 0x12FF 的变量进行配置。不过,预定义的连接集定义了一个 SDO 通道,即使在启动后(预运行状态)也可使用该通道配置设备。该通道的 COB-ID 为 0x600 + 节点 ID(用于接收)和 0x580 + 节点 ID(用于发送)。

4.1 示例

        可以使用 .sdo 成员访问 SDO 对象,其工作方式类似于 Python 字典。索引可以用名称或编号来标识。有两种方法来标识子索引,一种是使用索引和子索引作为单独的参数,另一种是使用点来组合语法。下面的代码只创建对象,还没有发送或接收信息:

# Complex records
command_all = node.sdo['ApplicationCommands']['CommandAll']
command_all = node.sdo['ApplicationCommands.CommandAll']
actual_speed = node.sdo['ApplicationStatus']['ActualSpeed']
control_mode = node.sdo['ApplicationSetupParameters']['RequestedControlMode']# Simple variables
device_type = node.sdo[0x1000]# Arrays
error_log = node.sdo[0x1003]

        要实际读取或写入变量,请使用 .raw、.phys、.desc 或 .bits 属性:

print(f"The device type is 0x{device_type.raw:X}")# Using value descriptions instead of integers (if supported by OD)
control_mode.desc = 'Speed Mode'# Set individual bit
command_all.bits[3] = 1# Read and write physical values scaled by a factor (if supported by OD)
print(f"The actual speed is {actual_speed.phys} rpm")# Iterate over arrays or records
for error in error_log.values():print(f"Error 0x{error.raw:X} was found in the log")

        也可以读写不在对象字典中的变量,但只能使用原始字节:

device_type_data = node.sdo.upload(0x1000, 0)
node.sdo.download(0x1017, 0, b'\x00\x00')

        变量可以作为可读或可写文件对象打开,这在处理大量数据时非常有用:

# Open the Store EDS variable as a file like object
with node.sdo[0x1021].open('r', encoding='ascii') as infile,open('out.eds', 'w', encoding='ascii') as outfile:# Iteratively read lines from node and write to fileoutfile.writelines(infile)

        大多数接受文件对象的应用程序接口应该也能接受这一点。

        如果服务器支持数据块传输,它就能有效地传输大量数据。这可以通过文件对象接口实现:

FIRMWARE_PATH = '/path/to/firmware.bin'
FILESIZE = os.path.getsize(FIRMWARE_PATH)with open(FIRMWARE_PATH, 'rb') as infile,node.sdo['Firmware'].open('wb', size=FILESIZE, block_transfer=True) as outfile:# Iteratively transfer data without having to read all into memorywhile True:data = infile.read(1024)if not data:breakoutfile.write(data)

警告 区块转移仍处于试验阶段!

 

五、过程数据对象 (PDO)

        过程数据对象协议用于处理各节点之间的实时数据。每个 PDO 最多可从设备或向设备传输 8 字节(64 位)数据。一个 PDO 可包含多个对象字典条目,一个 PDO 中的对象可通过映射和参数对象字典条目进行配置。

        PDO 有两种:发送 PDO 和接收 PDO(TPDO 和 RPDO)。前者用于接收来自设备的数据,后者用于接收前往设备的数据;也就是说,使用 RPDO 可以向设备发送数据,使用 TPDO 可以从设备读取数据。在预定义的连接集中,有四(4)个 TPDO 和四(4)个 RPDO 的标识符。可配置 512 个 PDO。

        PDO 可以同步或非同步发送。同步 PDO 在 SYNC 信息后发送,而异步信息则在内部或外部触发后发送。例如,您可以通过发送带有 RTR 标志的空 TPDO(如果设备配置为接受 TPDO 请求),请求设备发送包含所需数据的 TPDO。

        例如,通过 RPDO,您可以同时启动两个设备。您只需将同一个 RPDO 映射到两个或多个不同的设备中,并确保这些 RPDO 映射的 COB-ID 相同。

5.1 示例

        一个 canopen.RemoteNode 具有 canopen.RemoteNode.rpdo 和 canopen.RemoteNode.tpdo 属性,可用于使用 PDO 与节点交互。这些属性可以用子索引来指定使用哪个映射(第一个映射从 1 开始,而不是 0):

# Read current PDO configuration
node.tpdo.read()
node.rpdo.read()# Do some changes to TPDO4 and RPDO4
node.tpdo[4].clear()
node.tpdo[4].add_variable('Application Status', 'Status All')
node.tpdo[4].add_variable('Application Status', 'Actual Speed')
node.tpdo[4].trans_type = 254
node.tpdo[4].event_timer = 10
node.tpdo[4].enabled = Truenode.rpdo[4].clear()
node.rpdo[4].add_variable('Application Commands', 'Command All')
node.rpdo[4].add_variable('Application Commands', 'Command Speed')
node.rpdo[4].enabled = True# Save new configuration (node must be in pre-operational)
node.nmt.state = 'PRE-OPERATIONAL'
node.tpdo.save()
node.rpdo.save()# Start RPDO4 with an interval of 100 ms
node.rpdo[4]['Application Commands.Command Speed'].phys = 1000
node.rpdo[4].start(0.1)
node.nmt.state = 'OPERATIONAL'# Read 50 values of speed and save to a file
with open('output.txt', 'w') as f:for i in range(50):node.tpdo[4].wait_for_reception()speed = node.tpdo['Application Status.Actual Speed'].physf.write(f'{speed}\n')# Using a callback to asynchronously receive values
# Do not do any blocking operations here!
def print_speed(message):print(f'{message.name} received')for var in message:print(f'{var.name} = {var.raw}')node.tpdo[4].add_callback(print_speed)
time.sleep(5)# Stop transmission of RxPDO
node.rpdo[4].stop()

六、同步对象 (SYNC)

        同步生产者(Sync-Producer)为同步消费者(Sync-Consumer)提供同步信号。同步消费者收到信号后,就开始执行同步任务。

        一般来说,同步 PDO 信息传输时间的固定和同步对象传输的周期性保证了传感器设备可以安排对过程变量进行采样,执行器设备可以以协调的方式执行动作。

        同步对象的标识符位于索引 1005h。

6.1 示例

        使用 canopen.Network.sync 属性启动和停止 SYNC 消息:

# Transmit every 10 ms
network.sync.start(0.01)network.sync.stop()

七、紧急对象 (EMCY)

        紧急信息由设备内部发生致命错误时触发,以高优先级从相关应用设备传输到其他设备。因此,它们适用于中断类型的错误警报。每个 "错误事件 "只能发送一次紧急报文,即紧急报文不得重复发送。只要设备没有发生新的错误,就不能再发送紧急报文。通过 CANopen 通信配置文件定义的紧急错误代码、错误寄存器和设备配置文件中指定的设备特定附加信息。

7.1 示例

        要列出某个节点当前激活的紧急事件,可以使用 .active 属性,该属性是         canopen.emcy.EmcyError 对象的列表:

active_codes = [emcy.code for emcy in node.emcy.active]
all_codes = [emcy.code for emcy in node.emcy.log]

        canopen.emcy.EmcyError 对象实际上是异常,因此如果您需要,可以很容易地引发异常:

if node.emcy.active:raise node.emcy.active[-1]

八、时间戳对象(TIME)

        通常,时间戳对象表示午夜后以毫秒为单位的绝对时间和自 1984 年 1 月 1 日以来的天数。这是一个长度为 48(6 字节)的位序列。

九、层设置服务 (LSS)

        LSS 协议用于更改 CANOpen 目标设备(从站)的节点 ID 和波特率。要更改这些值,主站应首先设置配置状态。然后修改节点 ID 和波特率。从等待状态切换到配置状态有两种选择。一种是一次性切换所有从属设备,另一种是只切换一个从属设备。前者可用于设置所有从属设备的波特率。后者可用于逐个更改节点 ID。

        完成设置后,应将数值保存到非易失性存储器中。最后,可以切换到 LSS 等待状态。

        注意 某些方法和常量名称有所更改:

send_switch_mode_global() ==> send_switch_state_global()
network.lss.CONFIGURATION_MODE ==> network.lss.CONFIGURATION_STATE
network.lss.NORMAL_MODE ==> network.lss.WAITING_STATE

        您仍可使用旧名称,但请使用新名称。

        注意 从 v0.8.0 开始支持 Fastscan。未实施 LSS 识别从属服务。


9.1 示例

        将所有从属设备切换到 CONFIGURATION(配置)状态。信息无响应。

network.lss.send_switch_state_global(network.lss.CONFIGURATION_STATE)

        如果只想切换一个从属设备,也可以使用 4 个 ID 调用此方法:

vendorId = 0x00000022
productCode = 0x12345678
revisionNumber = 0x0000555
serialNumber = 0x00abcdef
ret_bool = network.lss.send_switch_state_selective(vendorId, productCode,revisionNumber, serialNumber)

        或者,可以运行 fastscan 程序

ret_bool, lss_id_list = network.lss.fast_scan()

        一旦其中一个传感器进入 "配置 "状态,就可以读取 LSS 从站的当前节点 ID:

node_id = network.lss.inquire_node_id()

        更改节点 ID 和波特率:

network.lss.configure_node_id(node_id+1)
network.lss.configure_bit_timing(2)

        这是将比特定时的参数索引转换为波特率的表格。

idx

Baud rate

0

1 MBit/sec

1

800 kBit/sec

2

500 kBit/sec

3

250 kBit/sec

4

125 kBit/sec

5

100 kBit/sec

6

50 kBit/sec

7

20 kBit/sec

8

10 kBit/sec

         保存配置:

network.lss.store_configuration()

        最后,可以将从属设备的状态从 "配置 "状态切换到 "等待 "状态:

network.lss.send_switch_state_global(network.lss.WAITING_STATE)

十、与现有代码集成

        有时,您需要将该库与某些现有代码库结合使用,或者您有 Python-can 不支持的 CAN 驱动程序。本章将介绍一些使用案例。

10.1 重新使用总线

        如果您需要与本库之外的 CAN 总线进行交互,并希望使用相同的 python-can 总线实例,您需要告诉网络使用哪条总线,并将 canopen.network.MessageListener 添加到现有的 can.Notifier 中。

        下面是一个简短的示例:

import canopen
import can# A Bus instance created outside
bus = can.interface.Bus()network = canopen.Network()
# Associate the bus with the network
network.bus = bus# Add your list of can.Listener with the network's
listeners = [can.Printer()] + network.listeners
# Start the notifier
notifier = can.Notifier(bus, listeners, 0.5)

10.2 使用自定义后端

        如果 python-can 软件包不支持您的 CAN 接口,您就需要创建 canopen.Network 的子类,并提供自己的消息发送方式。您还需要在后台线程中向 canopen.Network.notify() 发送接收到的消息。

        下面是一个示例:

import canopenclass CustomNetwork(canopen.Network):def connect(self, *args, **kwargs):# Optionally use this to start communication with CANpassdef disconnect(self):# Optionally use this to stop communincationpassdef send_message(self, can_id, data, remote=False):# Send the message with the 11-bit can_id and data which might be# a bytearray or list of integers.# if remote is True then it should be sent as an RTR.passnetwork = CustomNetwork()# Should be done in a thread but here we notify the network for
# demonstration purposes only
network.notify(0x701, bytearray([0x05]), time.time())

十一、设备配置文件

        在包括 DS301 应用层在内的标准 CANopen 功能基础上,还可以为某些应用提供专门的附加配置文件。

11.1 用于运动控制器和驱动器的 CiA 402 CANopen 设备配置文件

        该设备配置文件具有用于控制驱动器行为的控制状态机。因此,需要使用 BaseNode402 类实例化一个节点

        使用 BaseNode402 创建一个节点:

import canopen
from canopen.profiles.p402 import BaseNode402some_node = BaseNode402(3, 'someprofile.eds')
network = canopen.Network()
network.add_node(some_node)

11.2 电源状态机

        PowerStateMachine 类提供了控制该状态机状态的方法。静态方法 on_PDO1_callback() 被添加到 TPDO1 回调中。

        通过向寄存器 0x6040 写入特定值(称为 "控制字"),可以控制状态变化。当前状态可通过读取寄存器 0x6041(称为 "Statusword")来读取。只有在 NmtMaster 的 "运行 "状态下才能更改状态。

        需要正确设置映射了控制字和状态字的 PDO,这是大多数 DS402 兼容驱动器的默认配置。要使状态机实现可以访问它们,请运行 BaseNode402.setup_402_state_machine() 方法。请注意,该设置例程默认会读取当前的 PDO 配置,从而导致一些 SDO 流量。这仅在 NmtMaster 的 "OPERATIONAL(运行)"或 "PRE-OPERATIONAL(预运行)"状态下有效:

# run the setup routine for TPDO1 and it's callback
some_node.setup_402_state_machine()

        写入 Controlword 并读取 Statusword:

# command to go to 'READY TO SWITCH ON' from 'NOT READY TO SWITCH ON' or 'SWITCHED ON'
some_node.sdo[0x6040].raw = 0x06# Read the state of the Statusword
some_node.sdo[0x6041].raw

        在运行过程中,状态可能会变为控制字无法命令的状态,例如 "故障 "状态。因此,BaseNode402 类(与 NmtMaster 类似)会自动监控由 TPDO 发送的状态字的状态变化。然后,TPDO 上的可用回调将提取信息并在 BaseNode402.state 属性中反映状态变化。

        与 NmtMaster 类类似,BaseNode402 类状态属性的状态可以通过字符串读取和设置(命令):

# command a state (an SDO message will be called)
some_node.state = 'SWITCHED ON'
# read the current state
some_node.state

 

        可用状态:

  • 未准备好开启
  • 已禁用
  • 准备开启
  • 已开启
  • 已启用操作
  • 故障
  • 故障反应激活
  • 快速停止激活

        可用命令

  • 禁用开关
  • 禁用电压
  • 准备开启
  • 已开启
  • 启用操作
  • 快速停止激活

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

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

相关文章

【Java】解决Java报错:ConcurrentModificationException

文章目录 引言1. 错误详解2. 常见的出错场景2.1 遍历过程中修改集合2.2 使用 Iterator 进行删除操作 3. 解决方案3.1 使用 Iterator 的 remove 方法3.2 使用 CopyOnWriteArrayList3.3 使用 synchronized 块 4. 预防措施4.1 使用线程安全的集合类4.2 使用合适的遍历和修改方法4.…

如何在没有密码的情况下解锁iPhone

通常,您可以使用密码、FaceID 或 Touch ID 轻松解锁 iPhone。但是,有时您可能会忘记密码、iPhone 已停用或您的二手手机已锁定。在这种情况下,您必须绕过 iPhone 密码才能访问您的设备。在本文中,我们将向您介绍 5 种经过测试的方…

【多模态/CV】图像数据增强数据分析和处理

note 多模态大模型训练前,图片数据处理的常见操作:分辨率调整、网格畸变、水平翻转、分辨率调整、随机crop、换颜色、多张图片拼接、相似图片检测并去重等 一、分辨率调整 from PIL import Image def resize_image(original_image_path, save_image_p…

mysql 8 linux7,8安装教程

选择自己对应的linux版本 cat /etc/os-release //查看自己linux系统版本 1.mysql下载地址 MySQL :: Download MySQL Community Server (Archived Versions) 拉到下面找到 选择自己linux指定的版本,否则会很麻烦 cat /etc/os-release //查看系统版本 2.查…

50etf期权怎么开户?期权懂有几种方式?

今天带你了解50etf期权怎么开户?期权懂有几种方式?50ETF期权开户可以通过证券公司、期权交易平台或期权交易应用进行。投资者需填写开户申请表格,提供身份证明和其他资料,完成开户手续。 50etf期权怎么开户? 满足资金…

欢乐钓鱼大师辅助:哪家云手机自动钓鱼更好操作!

在探索《欢乐钓鱼大师》的世界时,我们不得不提到一个强大的游戏辅助工具——VMOS云手机。通过VMOS云手机,你可以轻松实现自动钓鱼,让游戏体验更加便捷高效。 什么是VMOS云手机? VMOS云手机是一款基于虚拟机技术的云端工具&#…

ubuntu20.04中设置包含ros节点的文件自启动

若文件里包含了ros话题的发布和接收,那么设置自启动时,应该首先将roscore设置为自启动。 首先确保roscore有一个systemd服务文件。如果还没有,需要在/etc/systemd/system/下创建一个。例如,一个基本的roscore.service文件可能如下…

安徽代理记账公司的专业服务和创新理念

在当今竞争激烈的市场环境中,为了提升企业的运营效率,许多企业开始寻找专业的代理记账公司进行财务管理和记账,本文将介绍一家名为安徽代理记账公司的专业服务和创新理念。 安徽代理记账公司是一家专注于为企业提供全方位会计服务的公司&…

SwiftUI中Mask修饰符的理解与使用

Mask是一种用于控制图形元素可见性的图形技术&#xff0c;使用给定视图的alpha通道掩码该视图。在SwiftUI中&#xff0c;它类似于创建一个只显示视图的特定部分的模板。 Mask修饰符的定义&#xff1a; func mask<Mask>(alignment: Alignment .center,ViewBuilder _ ma…

大屏可视化建设方案(word)

1.系统概述 1.1.需求分析 1.2.重难点分析 1.3.重难点解决措施 2.系统架构设计 2.1.系统架构图 2.2.关键技术 2.3.接口及要求 3.系统功能设计 3.1.功能清单列表 3.2.数据源管理 3.3.数据集管理 3.4.视图管理 3.5.仪表盘管理 3.6.移动端设计 3.1.系统权限设计 3.…

9.1 Go 接口的定义

&#x1f49d;&#x1f49d;&#x1f49d;欢迎莅临我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:「stormsha的主页」…

算法训练营day03--203.移除链表元素+707.设计链表+206.反转链表

一、203.移除链表元素 题目链接&#xff1a;https://leetcode.cn/problems/remove-linked-list-elements/ 文章讲解&#xff1a;https://programmercarl.com/0203.%E7%A7%BB%E9%99%A4%E9%93%BE%E8%A1%A8%E5%85%83%E7%B4%A0.html 视频讲解&#xff1a;https://www.bilibili.com…

Python报错:IndentationError: unexpected indent问题的解决办法及原因

解决Python报错&#xff1a;IndentationError: unexpected indent问题的解决办法及原因 Python是一种注重可读性的编程语言&#xff0c;它使用缩进来定义代码块。如果你遇到了IndentationError: unexpected indent的错误&#xff0c;这意味着Python解释器在代码中遇到了意外的缩…

阿里云(域名解析) certbot 证书配置

1、安装 certbot ubuntu 系统&#xff1a; sudo apt install certbot 2、申请certbot 域名证书&#xff0c;如申请二级域名aa.example.com 的ssl证书&#xff0c;同时需要让 bb.aa.example.com 也可以使用此证书 1、命令&#xff1a;sudo certbot certonly -d “域名” -d “…

使用亮数据代理IP爬取PubMed文章链接和邮箱地址

&#x1f482; 个人网站:【 摸鱼游戏】【神级代码资源网站】【工具大全】&#x1f91f; 一站式轻松构建小程序、Web网站、移动应用&#xff1a;&#x1f449;注册地址&#x1f91f; 基于Web端打造的&#xff1a;&#x1f449;轻量化工具创作平台&#x1f485; 想寻找共同学习交…

排查互联网敏感信息,对信息泄露说“不”

前言 01 近几年&#xff0c;随着我国对网络安全的重视&#xff0c;贴近实战的攻防演练活动越发丰富&#xff0c;各单位的网络安全建设也逐步从“事后补救”升级为“事前防控”。在演练中&#xff0c;进攻方会在指定时间内对防守方发动网络攻击&#xff0c;检测出防守方存在的…

04 架构核心技术之分布式消息队列

本课时的主题是分布式消息队列&#xff0c;分布式消息队列的知识结构如下图。 本课时主要介绍以下内容。 同步架构和异步架构的区别。异步架构的主要组成部分&#xff1a;消息生产者、消息消费者、分布式消息队列。异步架构的两种主要模型&#xff1a;点对点模型和发布订阅模型…

【讯为Linux驱动开发】5.并发与竞争

并发&#xff1a;一个CPU在一个时间片只能执行一个任务&#xff0c;切换速度很快。 并行&#xff1a;双核CPU&#xff0c;真正的同时执行两个任务 并行就是并发的理想情况&#xff0c;统称并发。 【问】Linux在什么情况下产生并发&#xff1f; 1.中断中修改公共资源 2.抢占…

【静夜思】小时候的回忆

为什么大家都会对自己童年时期的评价很高&#xff1f;甚至是一些模糊都快到想不起来的记忆&#xff1f; 博主是00后&#xff0c;那时候小学的我非常喜欢看动画片&#xff0c;像经典的喜羊羊、熊出没、胡图图等等&#xff0c;太多了。等上了高中后&#xff0c;博主也成为了一名…

全光网络与传统网络架构的对比分析

随着信息技术的飞速发展&#xff0c;网络已经成为我们日常生活中不可或缺的一部分。在这个信息爆炸的时代&#xff0c;全光网络和传统网络架构作为两种主流的网络技术&#xff0c;各有其特点和适用范围。本文将对这两种网络架构进行详细的对比分析&#xff0c;帮助读者更好地了…