rpc
— rpc库¶
rpc
模块允许您将znzpi AI相机连接到另一个微控制器或计算机,并对znzpi AI相机执行远程python(或程序)调用。 如果您希望您的znzpi AI相机能够在另一个微控制器或计算机上执行远程程序(或python)调用,那么``rpc`` 模块也允许反向操作。
如何使用库¶
请在IDE的 Remote Control 下打开示例代码。
您需要编辑示例代码以选择要使用的界面并使用脚本使用的设置。
通常,为了让控制器设备使用 rpc
库,您将使用 rpc
库创建一个接口对象。例如:
interface = rpc.rpc_uart_master(baudrate=115200)
这将创建一个 UART 接口来与 rpc
从设备通信。
一旦创建了接口,你只需执行:
memory_view_object_result = interface.call("remote_function_or_method_name", bytes_object_argument)
并且 rpc
库将尝试在从属设备上执行该 "remote_function_or_method_name"
。 远程函数或方法将接收大小可达 2^32-1 字节的 bytes_object_argument
。 一旦远程方法完成执行,它将返回一个 memory_view_object_result
,它的大小也可以达到 2^32-1 字节。 因为参数和响应都是通用字节容器,所以你可以通过 rpc
库传递任何东西并接收任何类型的响应。 传递参数的一种简单方法是使用 struct.pack()
来创建参数,并使用 struct.unpack()
在另一侧接收参数。 对于响应,另一方可能会发送一个字符串对象或 json 字符串作为主节点可以解释的结果。
至于错误,如果您尝试执行不存在的函数或方法名称,则 rpc_master.call()
方法将返回一个空的 bytes()
对象。 如果 rpc
库无法与从通信, rpc
库将返回 None。
为了简单起见,rpc
库不维护主设备和从设备之间的连接。rpc_master.call()
方法封装了尝试连接到从设备,开始执行远程函数或方法,并获取结果。
现在,在从设备方面,您必须创建一个 rpc
接口来与主设备进行通信。 例如:
interface = rpc.rpc_uart_slave(baudrate=115200)
这将创建UART接口层来与 rpc
主机对话。
创建从接口后,您需要注册主接口对象可以调用的回调:
def remote_function_or_method_name(memoryview_object_argument):
<lots of code>
return bytes_object_result
interface.register_callback(remote_function_or_method_name)
您可以在slave上注册任意多的回调函数。 最后,一旦你完成了回调,你只需要执行:
interface.loop()
在slave上启动``rpc`` 库并开始监听master。请注意,``rpc_slave.loop()`` 方法不返回。 此外,为了使您的 slave 更健壮地抵抗错误, 您可能需要将``rpc_slave.loop()`` 与 try:
和``except:`` 包装起来,以应对回调方法可能抛出的任何异常。 rpc
库本身不会生成任何异常。 注意:传递大型数据结构(如 jpeg 图像)可能会耗尽znzpi AI相机 上的堆并生成 MemoryError
异常。
就是这样! rpc
库被设计成易于使用。
rpc类 - rpc虚拟类¶
rpc基类由 rpc_master
和 rpc_slave
类重新实现,以创建主从接口。它是一个纯虚拟类,不能直接使用。
构造函数¶
- class rpc.rpc¶
创建rpc对象。此构造函数不能直接使用。
方法¶
- get_bytes(buff, timeout_ms):
这个方法需要通过特定的接口类
rpc_master
和rpc_slave
来重新实现。 它应该填充buff
参数,该参数是来自接口的字节的bytearray
或memoryview
对象, 等于timeout_ms
毫秒内的buff
对象的长度。超时时,此方法应返回None
。 请注意,对于 master 和 slave 同步,此方法应尝试始终在至少timeout_ms
毫秒内完成而不是更快, 因为rpc_master
和rpc_slave
对象将自动增加timeout_ms
以进行同步。
- put_bytes(data, timeout_ms):
这个方法需要通过特定的接口类
rpc_master
和rpc_slave
来重新实现。 如果它完成得比超时快,那没问题。预计没有返回值。
- stream_reader(call_back, queue_depth=1, read_timeout_ms=5000):
这个方法是直接调用的。在主设备和从设备同步返回回调后,可能会调用
stream_reader
以尽快从主设备或从设备接收数据。call_back
将使用stream_writer
发送的bytes_or_memory_view argument
重复调用。call_back
不会返回任何东西。queue_depth
定义了stream_writer
在减慢和等待stream_reader
之前可能生成的数据帧数。 更高的queue_depth
值会导致更高的性能(在一定程度上),但需要stream_reader
能够在其接口层处理未完成的数据包。 如果你让queue_depth
大于 1,那么call_back
应该很快返回而不是阻塞。 最后,read_timeout_ms
定义了等待接收每个回调的bytes_or_memory_view
有效载荷的毫秒数。在任何错误
stream_reader
都会返回。主从设备可以在之后再次尝试设置流以继续。如果需要取消
stream_reader
,只需在call_back
中抛出一个异常并捕获它。 远程端将自动超时。
- stream_writer(call_back, write_timeout_ms=5000):
此方法旨在直接调用。在主设备和从设备同步返回
callback
后,可能会调用stream_writer
以尽可能快地从主设备或从设备发送数据。call_back
将被重复调用,并且应该返回一个bytes_or_memory_view
对象,该对象将被发送到stream_reader
。call_back
不应接受任何参数。最后,write_timeout_ms
定义了等待发送call_back
返回的bytes_or_memory_view
对象的毫秒数。在任何错误
stream_writer
都会返回。主从设备可以在之后再次尝试设置流以继续。如果需要取消
stream_writer
,只需在call_back
中抛出一个异常并捕获它。 远程端将自动超时。
rpc_master类 - rpc_master主虚拟类¶
rpc_master是一个纯虚拟类,不能直接使用。特定的接口类应该重新实现 rpc_master。
构造函数¶
- class rpc.rpc_master¶
创建rpc_master对象。此构造函数不能直接使用。
方法¶
- call(name, data=bytes(), send_timeout=1000, recv_timeout=1000):
在从设备上执行远程调用。
name
是要执行的远程函数或方法的字符串名称。data
是类似bytes
的对象,它将作为远程函数或方法的参数发送以执行。send_timeout
定义尝试连接到从属设备并让它执行远程功能或方法时要等待的毫秒数。 一旦主设备开始向从设备发送参数,send_timeout
就不再适用。库将允许发送参数最多需要 5 秒。recv_timeout
定义从服务器开始执行远程方法以接收响应后等待的毫秒数。 请注意,一旦 master 开始接收响应,recv_timeout
将不适用。库将允许接收响应最多需要 5 秒。注意,一个包含
data
副本的新数据包将在rpc
库内部创建。 如果试图传递非常大的数据,您可能会在znzpi AI相机上遇到内存问题。
rpc_slave类 - rpc_slave虚拟类¶
rpc_slave是一个纯虚拟类,不能直接使用。特定的接口类应该重新实现 rpc_slave。
构造函数¶
- class rpc.rpc_slave¶
创建rpc_slave对象。此构造函数不能直接使用。
方法¶
- register_callback(cb):
注册一个可由主设备执行的回调。 回调应该接受一个参数,该参数将是一个
memoryview
对象,并且它应该返回一个bytes()
之类的对象作为结果。 如果可能,回调应在 1 秒内返回。
- schedule_callback(cb):
执行
rpc_slave.loop()
后,就不可能在rpc
库之外执行长时间运行的操作。schedule_callback
允许您在完成回调后暂时退出rpc
库。 您应该在执行rpc
回调方法期间执行 schedule_callback 以注册一个新的非rpc
回调, 该回调将在您执行schedule_callback
的回调成功完成后立即执行。 函数或方法不应接受任何参数。在注册的回调返回后,必须在下一个父回调中再次注册。 在父回调发生任何错误时,注册的回调将不会被调用,必须重新注册。以下是如何使用它:def some_function_or_method_that_takes_a_long_time_to_execute(): <do stuff> def normal_rpc_call_back(data): <process data> interface.schedule_callback(some_function_or_method_that_takes_a_long_time_to_execute) return bytes(response) interface.register_callback(normal_rpc_call_back) interface.loop()
schedule_callback
特别允许您使用get_bytes
和put_bytes
方法在一个设备和另一个设备之间进行直通数据传输, 而没有限制在 rpc 库内部移动的数据大小的打包成本,而不会耗尽znzpi AI相机上的内存。
- setup_loop_callback(cb):
循环回调在
rpc_slave.loop()
的每次循环迭代中被调用。 与rpc.schedule_callback()
回调不同,此回调在注册一次后保持注册状态。 您可以使用循环回调来闪烁活动 LED 或类似的东西。 你不应该使用循环回调来执行任何阻塞代码,因为这会妨碍从主节点轮询通信。 此外,循环回调将以可变速率调用,具体取决于主设备尝试执行的回调的时间和内容。 鉴于此,循环回调不适用于任何需要以固定频率执行的方法。在znzpi AI相机上,如果您需要以固定频率执行某事,您应该在执行
rpc_slave.loop()
之前设置一个计时器, 并使用基于计时器中断的回调以固定频率执行某些功能或方法。请参阅如何编写中断处理程序以获取更多信息。 注意: Mutex 库与 rpc 库一起安装在您的 znzpi AI Cam 上。
- loop(recv_timeout=1000, send_timeout=1000):
在从设备上开始执行
rpc
库以接收数据。此方法不返回(除非通过回调异常)。 在执行此方法之前,您应该先注册所有回调。但是,可以在之前注册的正在执行的回调中注册新的回调。recv_timeout
定义在再次尝试之前等待从主设备接收命令的时间。send_timeout
定义了从设备在返回尝试接收之前等待主设备接收回调响应的时间。 在再次尝试接收之前将执行循环回调。
rpc_can_master类 - CAN主接口¶
通过 CAN 控制另一个 rpc
设备。
构造函数¶
- rpc_can_master(message_if=0x7FF, bit_rate=250000, sample_point=75, can_bus=2):
创建一个CAN
rpc
主设备 。这个接口可以到1 Mb/s。message_id - 在CAN总线(11位)上用于数据传输的CAN消息。
bit_rate - CAN 比特率.
sampling_point - Tseg1/Tseg2 比率. 一般是 75%. (50.0, 62.5, 75, 87.5, 等。)
can_bus - 可用CAN 总线数
注意:主从消息 ID 和比特率必须匹配。连接主机高那么从机也高,主机低到那么从机也低。CAN总线必须以 120ohms 终止。 在STM32上使用CAN2。
rpc_can_slave类 - CAN从接口¶
通过 CAN 被另一个 rpc
设备控制。
构造函数¶
- rpc_can_slave(message_id=0x7FF, bit_rate=250000, sample_point=75, can_bus=2):
创建一个CAN
rpc
slave 。这个接口可以到1 Mb/s。message_id - 在CAN总线(11位)上用于数据传输的CAN消息。
bit_rate - CAN 比特率.
sampling_point - Tseg1/Tseg2 比率. 一般是 75%. (50.0, 62.5, 75, 87.5, 等。)
can_bus - 可用CAN 总线数
注意:主从消息 ID 和比特率必须匹配。连接主机高那么从机也高,主机低到那么从机也低。CAN总线必须以 120ohms 终止。 在STM32上使用CAN2。
rpc_i2c_master类 - I2C主接口¶
通过I2C控制另一个 rpc
设备。
构造函数¶
- class rpc.rpc_i2c_master(slave_addr=0x12, rate=100000, i2c_bus=2)¶
创建一个I2C
rpc
主设备。这个接口可以到1 Mb/sslave_addr - I2C 地址
rate - I2C Bus Clock Frequency.
rate - I2C 总线时钟频率。
注意:主地址和从地址必须匹配。将 master scl 连接到 slave scl,将 master sda 连接到 slave sda。您必须使用外部上拉。 最后,两个设备必须共地。
rpc_i2c_slave类 - I2C从接口¶
通过I2C被另一个``rpc`` 装置控制。
构造函数¶
- class rpc.rpc_i2c_slave(slave_addr=0x12, i2c_bus=2)¶
创建一个I2C
rpc
slave。这个接口可以到1 Mb/s。slave_addr - I2C 地址
rate - I2C 总线时钟频率。
注意:主地址和从地址必须匹配。将 master scl 连接到 slave scl,将 master sda 连接到 slave sda。您必须使用外部上拉。 最后,两个设备必须共地。
rpc_spi_master类 - SPI主接口¶
通过SPI控制另一个 rpc 设备。
构造函数¶
- class rpc.rpc_spi_master(cs_pin='P3', freq=10000000, clk_polarity=1, clk_phase=0, spi_bus=2)¶
创建SPI
rpc
主服务器。这个接口可以到80mb /scs_pin - Slave 选择引脚
freq - SPI 总线时钟频率
clk_polarity - 空闲时钟电平(0或1)
clk_phase - 在时钟的第一(0)或第二(1)边采样数据。
spi_bus - 使用的SPI总线数
注意:主从设置必须匹配。将 CS、SCLK、MOSI、MISO 连接到 CS、SCLK、MOSI、MISO。 最后,两个设备必须共地。
class rpc_spi_slave - SPI Slave Interface¶
rpc_spi_slave类 - SPI从接口
- class rpc.rpc_spi_slave(cs_pin='P3', clk_polarity=1, clk_phase=0, spi_bus=2)¶
通过SPI被另一个 rpc 设备控制。
cs_pin - Slave 选择引脚
clk_polarity - 空闲时钟电平(0或1)
clk_phase - 在时钟的第一(0)或第二(1)边采样数据。
spi_bus - 使用的SPI总线数
注意:主从设置必须匹配。将 CS、SCLK、MOSI、MISO 连接到 CS、SCLK、MOSI、MISO。 最后,两个设备必须共地。
rpc_uart_master类 - UART主接口¶
在异步串行(UART)上控制另一个 rpc
设备。
- class rpc.rpc_uart_master(baudrate=115200, uart_port=3)¶
创建一个UART
rpc
master。这个接口可以移到7.5 Mb/s。baudrate - 串行波特率.
uart_port - 使用的UART端口
注意:主从波特率必须匹配。将主 tx 连接到从 rx,将主 rx 连接到从 tx。 最后,两个设备必须共地。
rpc_uart_slave类 - UART从接口¶
通过异步串行(UART)被另一个 rpc
设备控制。
- class rpc.rpc_uart_slave(baudrate=115200, uart_port=3)¶
创建一个UART
rpc
从设备。这个接口可以到7.5 Mb/s。baudrate - 串行波特率.
uart_port - 使用的UART端口
注意:主从波特率必须匹配。将主 tx 连接到从 rx,将主 rx 连接到从 tx。 最后,两个设备必须共地。
rpc_usb_vcp_master类 - USB VCP主接口¶
通过USB虚拟COM端口被另一个 rpc
设备控制。
- class rpc.rpc_usb_vcp_master¶
创建USB VCP rpc 主设备。
rpc_usb_vcp_slave类 - USB VCP从接口¶
通过USB虚拟COM端口被另一个 rpc
设备控制。
- class rpc.rpc_usb_vcp_slave¶
创建USB VCP rpc 从设备。这个接口可以超过12mb /s。
rpc_network_master类 - 网络主控接口¶
通过 rpc
控制另外一个网络设备
- class rpc.rpc_network_master(network_if, port=0x1DBA)¶
创建一个网络
rpc
主控network_if - 从
network.LAN()
,network.WLAN()
等创建的网络接口port - 通讯用的端口
rpc_network_slave类 - 网络从接口¶
被另外一个 rpc
网络设备控制。
- class rpc.rpc_network_slave(network_if, port=0x1DBA)¶
创建一个
rpc
网络从设备network_if - 从
network.LAN()
,network.WLAN()
等创建的网络接口port - 通讯用的端口