Rock Pi 4C Plus 软件更新失败的话,按照下面操作一下。
操作步骤
sudo apt-get install -y wget
export DISTRO=focal-stable
wget -O - apt.radxa.com/$DISTRO/public.key | sudo apt-key add -
sudo apt-get update
这样以来,应该可以解决问题。
sudo apt-get install -y wget
export DISTRO=focal-stable
wget -O - apt.radxa.com/$DISTRO/public.key | sudo apt-key add -
sudo apt-get update
这样以来,应该可以解决问题。
最近,在朋友群里被安利了一款单片机,合宙的Air780E模组, 我简单查询了一下,看到这个模块还比较有意思,可以做为4G模块用,9.9元的价格还包邮真是让我白嫖了一把。下面就是我认识这开发板的过程的记录。 首先我们先了解一下这个模组。
Air780E 是合宙通信推出的 LTE Cat.1 bis通信模块,采用移芯EC618平台,支持4G全网通, 好像挺牛逼的样子,但是得备个卡。
乍一看还是蛮简单的,资料这里很全https://doc.openluat.com/wiki/37?wiki_page_id=4454
继续尝试中,估计是塞进去的电话卡不行,一直无法联网,等待新的物联网卡到了再继续折腾。
HDMI-CEC 是一种特殊协议,专为电视通过 HDMI 电缆与其他设备进行通信而设计。该协议允许电视控制另一个设备,同时还允许该设备控制电视。
大多数现代电视都支持此协议,但通常必须在电视设置中启用。搜索您的电视型号应该可以帮助您找到此设置的名称。
使用 HDMI-CEC 协议,您可以使用 Raspberry Pi 以各种不同的方式控制电视,例如关闭和打开电视或更改音量。
cec-client 是我们将在 Raspberry Pi 上使用的软件包,用于通过 HDMI-CEC 协议控制设备。
1.我们的首要任务是更新 Raspberry Pi 上的软件包列表以及升级当前安装的软件包。
我们可以通过运行以下两个命令来完成此任务。
sudo apt update
sudo apt -y upgrade
sudo apt install cec-utils -y
第一个是使用echo和管道(|)。将命令直接传递给cec-client软件,而无需启动它。
此外,我们在软件中同时使用-s和-d选项cec-client。
该-s选项告诉软件我们将发出一个命令。软件将启动,发出命令然后立即退出。
该-d 1选项设置软件的调试级别。通过将其设置为1,cec-client软件将只显示错误。
echo 'scan' | cec-client -s -d 1
2.通过此命令,您应该会看到您的 Raspberry Pi 现在可以访问的设备列表。
您需要识别要与之交互的设备。通常,“ os string:”和“ vendor:”字段将帮助您识别要与之交互的设备。
识别出正确的设备后,记下“ address:”或设备编号。
输出有可能类似下面的内容:
opening a connection to the CEC adapter...
requesting CEC bus information ...
CEC bus information
===================
device #0: TV
address: 0.0.0.0
active source: no
vendor: Sony
osd string: TV
CEC version: 1.4
power status: standby
language: eng
device #1: Recorder 1
address: 1.0.0.0
active source: no
vendor: Pulse Eight
osd string: CECTester
CEC version: 1.4
power status: on
language: eng
device #4: Playback 1
address: 3.0.0.0
active source: no
vendor: Sony
osd string: PlayStation 4
CEC version: 1.3a
power status: standby
language: ???
请注意,device #1: Recorder 1此示例中的“ ”是 Raspberry Pi 自己的 CEC 连接,因此我们可以放心地忽略它。
3.例如,如果我们想控制我们的“索尼电视”,我们可以看到设备号是“ 0”,设备的地址是“ 0.0.0.0”。
获得设备编号或设备地址后,您就可以开始向其发送命令了。
echo 'on <DEVICEADDRESS>' | cec-client -s -d 1
echo 'standby <DEVICEADDRESS>' | cec-client -s -d 1
使用此命令相对简单。
要将我们的索尼电视置于待机状态,我们需要做的就是发送“ standby”,然后发送我们的设备地址“ 0.0.0.0”。
echo 'standby 0.0.0.0 | cec-client -s -d 1
echo 'pow <DEVICEADDRESS>' | cec-client -s -d 1
echo 'pow 0.0.0.0' | cec-client -s -d 1
如果您的设备处于待机状态,您将在终端中看到类似于我们下面的内容。
opening a connection to the CEC adapter...
power status: standby
echo 'h' | cec-client -s -d 1
该命令的作用是检索cec-client软件知道如何处理的可用命令。
从这个命令中,你应该得到一个命令列表,如下所示。
================================================================================
Available commands:
[tx] {bytes} transfer bytes over the CEC line.
[txn] {bytes} transfer bytes but don't wait for transmission ACK.
[on] {address} power on the device with the given logical address.
[standby] {address} put the device with the given address in standby mode.
[la] {logical address} change the logical address of the CEC adapter.
[p] {device} {port} change the HDMI port number of the CEC adapter.
[pa] {physical address} change the physical address of the CEC adapter.
[as] make the CEC adapter the active source.
[is] mark the CEC adapter as inactive source.
[osd] {addr} {string} set OSD message on the specified device.
[ver] {addr} get the CEC version of the specified device.
[ven] {addr} get the vendor ID of the specified device.
[lang] {addr} get the menu language of the specified device.
[pow] {addr} get the power status of the specified device.
[name] {addr} get the OSD name of the specified device.
[poll] {addr} poll the specified device.
[lad] lists active devices on the bus
[ad] {addr} checks whether the specified device is active.
[at] {type} checks whether the specified device type is active.
[sp] {addr} makes the specified physical address active.
[spl] {addr} makes the specified logical address active.
[volup] send a volume up command to the amp if present
[voldown] send a volume down command to the amp if present
[mute] send a mute/unmute command to the amp if present
[self] show the list of addresses controlled by libCEC
[scan] scan the CEC bus and display device info
[mon] {1|0} enable or disable CEC bus monitoring.
[log] {1 - 31} change the log level. see cectypes.h for values.
[ping] send a ping command to the CEC adapter.
[bl] to let the adapter enter the bootloader, to upgrade
the flash rom.
[r] reconnect to the CEC adapter.
[h] or [help] show this help.
[q] or [quit] to quit the CEC test client and switch off all
connected CEC devices.
=======================================================================
至此,您现在应该已经学会了如何cec-client在您的 Raspberry Pi 上使用来控制支持该HDMI-CEC协议的设备。
之前用arduino-cli 配置ESP32-C3,编写代码和编译烧录都没有问题, 只是在使用arduino-cli monitor -p /dev/ttyACM0 没有输出, 查了一圈发现是因为USB CDC Onboot 没有开启, 然后各种搜索完全没有结果,直到我直接去github官方下面开了issue,一小时内就解决了我的问题,这个老哥厉害了。
下面是引用它的引文:
Custom board options such as "**USB CDC On Boot**" are set via the FQBN you pass to `arduino-cli` commands via the `--fqbn` flag.
The format of the FQBN is like this:
<vendor ID>:<architecture>:<board ID>[:<menu ID>=<option ID>[,<menu ID>=<option ID>]...]
You can learn all the available menu IDs and option IDs for a given board by running [the following command](https://arduino.github.io/arduino-cli/latest/commands/arduino-cli_board_details/):
arduino-cli board details --fqbn <FQBN>
(where `<FQBN>` is replaced by the fully qualified board name of the board you are using)
For example if you are using the "**ESP32C3 Dev Module**" board (FQBN: `esp32:esp32:esp32c3`):
$ ./arduino-cli board details -b esp32:esp32:esp32c3
Board name: ESP32C3 Dev Module
FQBN: esp32:esp32:esp32c3
Board version: 2.0.4
Package name: esp32
Package maintainer: Espressif Systems
Package URL: https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json
Package website: https://github.com/espressif/arduino-esp32
Package online help: http://esp32.com
Platform name: esp32
Platform category: ESP32
Platform architecture: esp32
Platform URL: https://github.com/espressif/arduino-esp32/releases/download/2.0.4/esp32-2.0.4.zip
Platform file name: esp32-2.0.4.zip
Platform size (bytes): 259715595
Platform checksum: SHA-256:832609d6f4cd0edf4e471f02e30b7f0e1c86fdd1b950990ef40431e656237214
Required tool: esp32:riscv32-esp-elf-gcc gcc8_4_0-esp-2021r2-patch3
Required tool: esp32:xtensa-esp32-elf-gcc gcc8_4_0-esp-2021r2-patch3
Required tool: esp32:xtensa-esp32s2-elf-gcc gcc8_4_0-esp-2021r2-patch3
Required tool: esp32:xtensa-esp32s3-elf-gcc gcc8_4_0-esp-2021r2-patch3
Required tool:
尝试使用
arduino-cli board details -b esp32:esp32:esp32c3
然后我突然明白了怎么用了。
<vendor ID>:<architecture>:<board ID>[:<menu ID>=<option ID>[,<menu ID>=<option ID>]...]
这个结构就是我烧录时候需要遵循的。
通过查询找到了USB CDC Onboot的配置是esp32:esp32:esp32c3:USBOnBoot=cdc
menuID: USBOnBoot
optionID: cdc
于是直接烧录:
arduino-cli compile -b esp32:esp32:esp32c3:USBOnBoot=cdc -p /dev/ttyACM0 --upload
烧录完成直接执行:
arduino-cli monitor -p /dev/ttyACM0
顺利看到输出,就非常奈斯。。
希望对你有帮助哈!
自从使用Raspberry Pi Pico以后,就觉得MicroPython真的太方便了。各种应用想实现就分分钟搞定。
这里面不得不说OLED屏幕中0.96inch的存在,真是小巧又可爱。
在刷新OLED的屏幕时,常用到ssd1306的库,那都是底层,最重要的还是使用framebuf库的功能。
其中,我最喜欢就是用bytearray去做为输入的buf。
例如我就常常:
from machine import Pin, ADC, I2C
from time import sleep
import framebuf
from ssd1306 import SSD1306_I2C
WIDTH = 128
HEIGHT = 64
buf = bytearray(b'') # 这里定义buf。 后面讲这里的buf怎么实现。
fb = framebuf.FrameBuffer(buf, framebuf.MONO_VLSB)
bus = I2C(1, scl=Pin(15), sda=Pin(14), freq=2000000)
oled = SSD1306_I2C(WIDTH, HEIGHT, bus)
while True:
oled.fill(0)
oled.show()
sleep(0.01)
oled.blit(fb, 0, 0)
oled.show()
sleep(0.5)
from io import BytesIO
from PIL import Image
import sys
if len(sys.argv) > 1:
path_to_image = str(sys.argv[1])
x = int(sys.argv[2])
y = int(sys.argv[3])
im = Image.open(path_to_image).convert('1')
im_resize = im.resize((x,y))
buf = BytesIO()
im_resize.save(buf, 'ppm')
byte_im = buf.getvalue()
temp = len(str(x) + ' ' + str(y)) + 4
print(byte_im[temp::])
else:
print("please specify the location of image i.e img2bytearray.py /path/to/image width heigh")
然后执行这个代码并提供图片的位置,这样就将图片生成了一段bytearray数组,拷贝到buf的位置。
红框部分的内容复制到bytearray的位置。上传到pico,就搞定了。
非常简单。
下面内容就是不同的角度的算法。
Pitch angle
should be the angle between X and Z axis which will be
atan2(accelZ,accelX)*180/PI
Roll angle
should be the angle between Y and Z axis which will be
atan2(accelZ,accelY)*180/PI
And to find yaw
it should be the angle between X and VectorY+Z which will be
atan2(sqrt(accelY*accelY+accelZ*accelZ),accelX)*180/PI
# This program will let you test your ESC and brushless motor.
# Make sure your battery is not connected if you are going to calibrate it at first.
# Since you are testing your motor, I hope you don't have your propeller attached to it otherwise you are in trouble my friend...?
# This program is made by AGT @instructable.com. DO NOT REPUBLISH THIS PROGRAM... actually the program itself is harmful pssst Its not, its safe.
import os #importing os library so as to communicate with the system
import time #importing time library to make Rpi wait because its too impatient
os.system ("sudo pigpiod") #Launching GPIO library
time.sleep(1) # As i said it is too impatient and so if this delay is removed you will get an error
import pigpio #importing GPIO library
ESC=4 #Connect the ESC in this GPIO pin
pi = pigpio.pi();
pi.set_servo_pulsewidth(ESC, 0)
max_value = 2000 #change this if your ESC's max value is different or leave it be
min_value = 700 #change this if your ESC's min value is different or leave it be
print "For first time launch, select calibrate"
print "Type the exact word for the function you want"
print "calibrate OR manual OR control OR arm OR stop"
def manual_drive(): #You will use this function to program your ESC if required
print "You have selected manual option so give a value between 0 and you max value"
while True:
inp = raw_input()
if inp == "stop":
stop()
break
elif inp == "control":
control()
break
elif inp == "arm":
arm()
break
else:
pi.set_servo_pulsewidth(ESC,inp)
def calibrate(): #This is the auto calibration procedure of a normal ESC
pi.set_servo_pulsewidth(ESC, 0)
print("Disconnect the battery and press Enter")
inp = raw_input()
if inp == '':
pi.set_servo_pulsewidth(ESC, max_value)
print("Connect the battery NOW.. you will here two beeps, then wait for a gradual falling tone then press Enter")
inp = raw_input()
if inp == '':
pi.set_servo_pulsewidth(ESC, min_value)
print "Wierd eh! Special tone"
time.sleep(7)
print "Wait for it ...."
time.sleep (5)
print "Im working on it, DONT WORRY JUST WAIT....."
pi.set_servo_pulsewidth(ESC, 0)
time.sleep(2)
print "Arming ESC now..."
pi.set_servo_pulsewidth(ESC, min_value)
time.sleep(1)
print "See.... uhhhhh"
control() # You can change this to any other function you want
def control():
print "I'm Starting the motor, I hope its calibrated and armed, if not restart by giving 'x'"
time.sleep(1)
speed = 1500 # change your speed if you want to.... it should be between 700 - 2000
print "Controls - a to decrease speed & d to increase speed OR q to decrease a lot of speed & e to increase a lot of speed"
while True:
pi.set_servo_pulsewidth(ESC, speed)
inp = raw_input()
if inp == "q":
speed -= 100 # decrementing the speed like hell
print "speed = %d" % speed
elif inp == "e":
speed += 100 # incrementing the speed like hell
print "speed = %d" % speed
elif inp == "d":
speed += 10 # incrementing the speed
print "speed = %d" % speed
elif inp == "a":
speed -= 10 # decrementing the speed
print "speed = %d" % speed
elif inp == "stop":
stop() #going for the stop function
break
elif inp == "manual":
manual_drive()
break
elif inp == "arm":
arm()
break
else:
print "WHAT DID I SAID!! Press a,q,d or e"
def arm(): #This is the arming procedure of an ESC
print "Connect the battery and press Enter"
inp = raw_input()
if inp == '':
pi.set_servo_pulsewidth(ESC, 0)
time.sleep(1)
pi.set_servo_pulsewidth(ESC, max_value)
time.sleep(1)
pi.set_servo_pulsewidth(ESC, min_value)
time.sleep(1)
control()
def stop(): #This will stop every action your Pi is performing for ESC ofcourse.
pi.set_servo_pulsewidth(ESC, 0)
pi.stop()
#This is the start of the program actually, to start the function it needs to be initialized before calling... stupid python.
inp = raw_input()
if inp == "manual":
manual_drive()
elif inp == "calibrate":
calibrate()
elif inp == "arm":
arm()
elif inp == "control":
control()
elif inp == "stop":
stop()
else :
print "Thank You for not following the things I'm saying... now you gotta restart the program STUPID!!"
今天 rockets 问我, 是否能够将二维码里面的色块用 0 和 1 表示出来.
我脑海里分析了一下,不知道是不是可以用 opencv 实现,就打开电脑尝试了一下,似乎是可以的.
思路, 首先通过 qrcode 生成一个图片,然后保存一下,通过opencv 导入图片,然后再判断 10x10 大小的块中是否全是白色,如果是白色,就写一个 1
,如果是黑色,就写个 0. 然后遍历整个图片的 shape.
import qrcode
import cv2
import numpy as np
url = 'https://www.dfrobot.com/product-2480.html'
file_name = 'qrcode.png'
def generate_image(url):
qr = qrcode.QRCode()
qr.add_data(url)
qr.make(fit=False)
img = qr.make_image(fill_color="black", back_color="white")
img.save(file_name)
generate_image(url)
img1 = cv2.imread(file_name)
scale_percent = 80
width = int(img1.shape[1] * scale_percent / 100)
height = int(img1.shape[0] * scale_percent / 100)
dim = (width, height)
resized_img = cv2.resize(img1, dim, interpolation=cv2.INTER_AREA)
# gray_img1 = cv2.cvtColor(img1, cv2.COLOR_BGR2GRAY)
for i in range(0, int(resized_img.shape[0]), 10):
for j in range(0, int(resized_img.shape[1]), 10):
if np.mean(resized_img[i:i+10, j:j+10]) == 255:
cv2.putText(resized_img, '0', (i, j), cv2.FONT_HERSHEY_SIMPLEX, .2, (255, 0, 0))
else:
cv2.putText(resized_img, '1', (i, j), cv2.FONT_HERSHEY_SIMPLEX, .2, (255, 0, 0))
cv2.imshow('resized_img', resized_img)
cv2.waitKey(0)
np.mean(图片数组) == 255的判断部分,可以判断图片是不是白色.
import qrcode
import cv2
import numpy as np
# 定义生成 qrcode 的 url 链接和生成的文件名
url = 'https://www.dfrobot.com/product-2480.html'
file_name = 'qrcode.png'
def generate_image(url):
""""
生成二维码并保存
"""
qr = qrcode.QRCode()
qr.add_data(url)
qr.make(fit=False)
img = qr.make_image(fill_color="black", back_color="white")
img.save(file_name)
def process_image(filename):
"""
:param filename: 放入生成的二维码
:return: 显示图
"""
img1 = cv2.imread(file_name)
scale_percent = 80
width = int(img1.shape[1] * scale_percent / 100)
height = int(img1.shape[0] * scale_percent / 100)
dim = (width, height)
resized_img = cv2.resize(img1, dim, interpolation=cv2.INTER_AREA)
for i in range(0, int(resized_img.shape[0]), 10):
for j in range(0, int(resized_img.shape[1]), 10):
if np.mean(resized_img[i:i+5, j:j+5]) == 255:
cv2.putText(resized_img, '0', (i+5, j+5), cv2.FONT_HERSHEY_SIMPLEX, .2, (255, 0, 0))
else:
cv2.putText(resized_img, '1', (i+5, j+5), cv2.FONT_HERSHEY_SIMPLEX, .2, (255, 0, 0))
cv2.imshow('resized_img', resized_img)
cv2.waitKey(0)
if __name__ == "__main__":
generate_image(url)
process_image(file_name)
继续优化试试看.
import qrcode
import cv2
import numpy as np
# 定义生成 qrcode 的 url 链接和生成的文件名
url = 'https://www.dfrobot.com/product-2480.html'
file_name = 'qrcode.png'
def generate_image(url):
""""
生成二维码并保存
"""
qr = qrcode.QRCode()
qr.add_data(url)
qr.make(fit=False)
img = qr.make_image(fill_color="black", back_color="white")
img.save(file_name)
def process_image(filename):
"""
:param filename: 放入生成的二维码
:return: 显示图
"""
img1 = cv2.imread(file_name)
scale_percent = 200
width = int(img1.shape[1] * scale_percent / 100)
height = int(img1.shape[0] * scale_percent / 100)
dim = (width, height)
resized_img = cv2.resize(img1, dim, interpolation=cv2.INTER_AREA)
resized_img = cv2.cvtColor(resized_img, cv2.COLOR_BGR2GRAY)
for i in range(0, int(resized_img.shape[0]), 10):
for j in range(0, int(resized_img.shape[1]), 10):
if np.mean(resized_img[i:i+3, j:j+3]) == 255:
cv2.putText(resized_img, '1', (i + 5, j + 5), cv2.FONT_HERSHEY_SIMPLEX, .2, (0, 0, 255))
else:
cv2.putText(resized_img, '0', (i + 5, j + 5), cv2.FONT_HERSHEY_SIMPLEX, .2, (255, 0, 0))
cv2.imshow('img', resized_img)
cv2.waitKey(0)
if __name__ == "__main__":
generate_image(url)
process_image(file_name)
树莓派在运行桌面环境的时候,长时间不操作就会自动黑屏,是电源管理的一个节能的功能,有时候挺烦人,可以关闭它。
在终端中输入:
sudo xset s off
sudo xset -dpms
sudo xset s noblank
sudo raspi-config
命令xserver-command=X -s 0 -dpms
保存后退出重启系统。
屡试不爽!
pi@raspberrypi:~ $ sudo apt-get update
Get:1 http://archive.raspberrypi.org/debian buster InRelease [32.6 kB]
Get:2 http://raspbian.raspberrypi.org/raspbian buster InRelease [15.0 kB]
Reading package lists... Done
E: Repository 'http://raspbian.raspberrypi.org/raspbian buster InRelease' changed its 'Suite' value from 'stable' to 'oldstable'
N: This must be accepted explicitly before updates for this repository can be applied. See apt-secure(8) manpage for details.
E: Repository 'http://archive.raspberrypi.org/debian buster InRelease' changed its 'Suite' value from 'testing' to 'oldstable'
N: This must be accepted explicitly before updates for this repository can be applied. See apt-secure(8) manpage for details.
sudo apt-get -y update --allow-releaseinfo-change
Get:1 http://archive.raspberrypi.org/debian buster InRelease [32.6 kB]
Get:2 http://raspbian.raspberrypi.org/raspbian buster InRelease [15.0 kB]
Get:3 http://raspbian.raspberrypi.org/raspbian buster/contrib Sources [78.5 kB]
Get:4 http://archive.raspberrypi.org/debian buster/main armhf Packages [393 kB]
Get:5 http://raspbian.raspberrypi.org/raspbian buster/main Sources [11.4 MB]
Ign:5 http://raspbian.raspberrypi.org/raspbian buster/main Sources
Get:6 http://raspbian.raspberrypi.org/raspbian buster/non-free Sources [139 kB]
Get:7 http://raspbian.raspberrypi.org/raspbian buster/rpi Sources [1,132 B]
Get:8 http://raspbian.raspberrypi.org/raspbian buster/main armhf Packages [13.0 MB]
21% [8 Packages 443 kB/13.0 MB 3%]
顺利解决~
今天实现了对物体检测并控制舵机运动的应用。
舵机使用了pca9685控制,因此备份一下pac9685舵机控制板的驱动:
import time
import math
class PWM:
_mode_adr = 0x00
_base_adr_low = 0x08
_base_adr_high = 0x09
_prescale_adr = 0xFE
def __init__(self, bus, address = 0x40):
'''
Creates an instance of the PWM chip at given i2c address.
@param bus: the SMBus instance to access the i2c port(0 or 1).
@param address: the address of the i2c chip (default: 0x40).
'''
self.bus = bus
self.address = address
self._writeByte(self._mode_adr, 0x00)
def setFreq(self, freq):
'''
Sets the PWM frequency. The value is stored in the device.
@param freq: the frequency in Hz (approx.)
'''
prescaleValue = 25000000.0 # 25MHz
prescaleValue /= 4096.0 # 12-bit
prescaleValue /= float(freq)
prescaleValue -= 1.0
prescale = math.floor(prescaleValue + 0.5)
oldmode = self._readByte(self._mode_adr)
if oldmode == None:
return
newmode = (oldmode & 0x7F) | 0x10
self._writeByte(self._mode_adr, newmode)
self._writeByte(self._prescale_adr, int(math.floor(prescale)))
self._writeByte(self._mode_adr, oldmode)
time.sleep(0.005)
self._writeByte(self._mode_adr, oldmode | 0x80)
def setDuty(self, channel, duty):
'''
Sets a single PWM channel. The value is stored in the device.
@param channel: one of the channels 0..15
@param duty: the duty cycle 0..100
'''
data = int(duty * 4096 /100) # 0..4096 (included)
self._writeByte(self._base_adr_low + 4 * channel, data & 0xFF)
self._writeByte(self._base_adr_high + 4 * channel, data >> 8)
def _writeByte(self, reg, value):
try:
self.bus.write_byte_data(self.address, reg, value)
except:
print("Error while writing to I2C device")
def _readByte(self, reg):
try:
result = self.bus.read_byte_data(self.address, reg)
return result
except:
print("Error while Reading from I2C device")
return None
import time
from smbus2 import SMBus
from pca9685 import PWM
freq = 50
addr = 0x40
channels = [0, 1, 2]
a = 12.5
b = 2
bus = SMBus(1)
pwm = PWM(bus, addr)
pwm.setFreq(freq)
def setPos(channel, pos):
duty = a / 180 * pos + b
pwm.setDuty(channel, duty)
time.sleep(0.1)
while True:
try:
for pos in range(60, 120, 2):
setPos(channels[0], pos)
time.sleep(0.1)
for pos in range(60, 120, 3):
setPos(channels[1], pos)
time.sleep(0.5)
for pos in range(0, 90, 3):
setPos(channels[2], pos)
time.sleep(0.01)
except KeyboardInterrupt:
for i in channels:
setPos(i, 0)
break
import cv2
import time
import numpy as np
from pca9685 import PWM
from smbus2 import SMBus
freq = 50
addr = 0x40
ch1 = 0
ch2 = 1
bus = SMBus(1)
pwm = PWM(bus, addr)
pwm.setFreq(freq)
def setPos(channel, position):
pwm.setDuty(channel, position)
time.sleep(0.01)
def posMap(x, in_min, in_max, out_min, out_max):
return int((x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min)
cap = cv2.VideoCapture(0)
cap.set(3, 320)
cap.set(4, 160)
ret, frame = cap.read()
cx = int(frame.shape[1] / 2)
center = int(frame.shape[1] / 2)
pos = 90
while True:
ret, frame = cap.read()
frame = cv2.flip(frame, 1)
hsv_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
ly = np.array([51, 0, 0])
hy = np.array([180, 255, 255])
mask = cv2.inRange(hsv_frame, ly, hy)
contours, hir = cv2.findContours(mask, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
contours = sorted(contours, key=lambda x: cv2.contourArea(x), reverse=True)
# cv2.drawContours(frame, contours[1], -1, (0, 0, 255), 2)
for cnt in contours[1:]:
(x, y, w, h) = cv2.boundingRect(cnt)
cv2.rectangle(frame, (x, y), (x+w, y+h), (255, 255,0), 2)
cx = int((x + x + w)/ 2)
# cv2.drawContours(frame, cnt, -1, (0, 0, 255), 2)
cv2.line(frame, (cx, 0), (cx, frame.shape[0]), (0, 0, 255), 1)
if cx < center:
pos -= 1.5
elif cx > center:
pos += 1.5
# pos = posMap(pos, 1, 480, 60, 120)
setPos(ch1, pos)
break
# mask = cv2.cvtColor(mask, cv2.COLOR_GRAY2BGR)
# hstack = np.hstack([mask, frame])
cv2.imshow('frame', frame)
if cv2.waitKey(1) & 0xFF == 27:
break
cap.release()
cv2.destroyAllWindows()
setPos(ch1, 0)
就是控制dutyCycle,频率肯定要50hz,一般的多级可能需要a, b函数作为微调。根据自己的舵机微调a和b的值。
可以尝试 a 设置8.5, b设置2
由于测试用到,收藏一下,备用:
-------------- Python --------------
def _map(x, in_min, in_max, out_min, out_max):
return int((x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min)
y = _map(25, 1, 50, 50, 1)
print(y)
登陆树莓派CM4, 如果发现wlan0找不到,无法初始化,就这样执行以下命令:
cd /lib/firmware/brcm
cp brcmfmac43455-sdio.raspberrypi,4-model-b.txt brcmfmac43455-sdio.raspberrypi,4-compute-module.txt
reboot
然后尝试改一下wifi-country的信息。
iw reg get
iw reg set CN
iw reg get
lsmod |grep brcmfmac
接着尝试用
iw dev
wifi status
看看状态。
uci show wireless
这里需要启用radio0, 并且把AP模式改成STA模式。
uci set wireless.radio0.disabled='0'
uci set wireless.default_radio0.mode='sta'
uci set wireless.default_radio0.network='wan'
uci show wireless
在最近发现windows11 预览版arm64位系统发布后,可以通过一个cmd的脚本生成需要的镜像,但是也会产生一个非常大容量的目录: MountUUP,应该是通过UUPtoISO生成的临时文件,非常巨大,包含了很多cab的包还有一些wim的东西,在执行删除的时候总是提示你需要trustinstaller的权限,无法删除,会占用大量磁盘,实际上是因为它挂载了一个镜像文件install.wim, 我想要删除它清空磁盘空间,找了一圈,发现可以通过先取消挂载然后再删除就顺利干掉了。
下面是一段网上查到的资料原文。
The following DISM command will look for stale mountpoints on all drives and (attempt to) unmount them:
DISM.exe /cleanup-wim
Or, you can do it manually:
DISM.exe /Unmount-WIM /mountdir=C:\MountUUP /discard
管理员打开cmd窗口,执行上述命令后删除相应目录即可。问题解决。