Windows系统区域设置

起因

就是因为安装了ESP-IDF的环境发现编码是GBK,操作系统还不能直接改。我这暴脾气嘿!

解决方法:

打开终端:
chcp # 查看编码格式
chcp 65001 # 切换编码为UTF-8
chcp 936 # 切换回GBK
chcp 437 # 切美国英文

问题解决

系统不同版本也不一样,坑多多。

为OLED显示图片生成Bytearray

OLED 0.96

缘起

自从使用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)

buf的实现方法

  1. 打开windows的绘图板,生成一个128x64的画布
    然后自己随便画个图像并保存。
  2. 然后打开pycharm编写如下代码:

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,就搞定了。
非常简单。

树莓派控制Hobbywing 电调控制无刷电机

树莓派4B + ESC (Hobbywing) + SKYwalker 2212 无刷电机

测试步骤

  1. 搭建电路
  2. 校准电调
  3. 驱动电机ESC.py 测试代码:
# 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!!"

如何利用 opencv 简单解释二维码的组成

起因

今天 rockets 问我, 是否能够将二维码里面的色块用 0 和 1 表示出来.

分析

我脑海里分析了一下,不知道是不是可以用 opencv 实现,就打开电脑尝试了一下,似乎是可以的.
思路, 首先通过 qrcode 生成一个图片,然后保存一下,通过opencv 导入图片,然后再判断 10x10 大小的块中是否全是白色,如果是白色,就写一个 1
,如果是黑色,就写个 0. 然后遍历整个图片的 shape.

Talk is cheap, show me the code


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)

输出结果:

树莓派摄像头-追踪

今天实现了对物体检测并控制舵机运动的应用。
舵机使用了pca9685控制,因此备份一下pac9685舵机控制板的驱动:

PCA9685.py

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

OpenCV 通过颜色检测并控制:

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

树莓派安装windows11 预览版遇到的问题总结

在最近发现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窗口,执行上述命令后删除相应目录即可。问题解决。

Ubuntu 上安装 Cacti 现在这么简单了么?

前言

最近讲监控, 又将很久以前的东西重新拾起来, 尝试在我的小 mac 上的虚拟机里面进行各种安装测试.

安装 SNMP

我以前的印象中,安装 snmp 需要用的软件包的名字是: net-snmp,但是在 ubuntu 上我发现,就直接安装snmp 和 snmpd 好像就行了.

   sudo apt-get -y install snmp snmpd 

安装 cacti

我之前的经验是需要安装一套 LAMP 架构.先.
但是发现 ubuntu 上面已经让我可以变得非常懒了, 直接一条命令就都给你安装上来了.

sudo apt-get -y install cacti

顺手更新了一把系统.

疑惑

官方网站上说 cacti 账户和密码默认是 admin,但是好像不行.真是折腾.
后来用了账户 admin,密码用的数据库的密码才正常登陆.

Mac OS 上虚拟机无法联网的临时修复方法记录

事情的起因

由于要上课,因此安装 centos8.3.2011一个短命的系统,但是网卡不好用.

实际的电脑信息

我电脑是:

然后我的 parallel 的虚拟机网卡不好用, 尝试联网各种失败,开机无法联网,CentOS 也不好用.

解决方法:

于是搜了半天, 尝试了半天,终于找到一个看似能用的方法:
->关闭所有VMS和Parallels Desktop-

打开终端并键入:sudo -b /Applications/Parallels\Desktop.app/Contents/MacOS/prl_client_app

总结:

Parallels将打开,也许您需要打开您的VM再次...网络将正常工作...
这是一个临时解决方案,而官方的并行支持不起作用..

Linux内核编译如果出问题了怎么办?

如果出问题了

如果您遇到的问题似乎是由于内核错误引起的,请检查文件维护者以查看是否有特定人员与您遇到麻烦的内核部分相关联。如果没有列出有任何人,那么第二个最好的办法是将它们邮寄给(torvalds@linux-foundation.org),以及可能的其他任何有关的邮件列表或新闻组。

在所有错误报告中,请告诉您您在操作的是什么内核,如何复制问题以及您的设置是什么(使用常识)。如果问题是新问题,请告诉他,如果问题是旧问题,请在首次发现问题时告诉他,他才是Linux内核最大的BOSS。

例如:
如果该错误导致显示如下消息:

unable to handle kernel paging request at address C0000010
Oops: 0002
EIP:   0010:XXXXXXXX
eax: xxxxxxxx   ebx: xxxxxxxx   ecx: xxxxxxxx   edx: xxxxxxxx
esi: xxxxxxxx   edi: xxxxxxxx   ebp: xxxxxxxx
ds: xxxx  es: xxxx  fs: xxxx  gs: xxxx
Pid: xx, process nr: xx
xx xx xx xx xx xx xx xx xx xx

或屏幕上或系统日志中的类似内核调试信息,请准确复制。转储对您来说似乎令人难以理解,但是它确实包含有助于调试问题的信息。转储上方的文本也很重要:它说明了为什么内核转储代码的原因(在上面的示例中,这是由于内核指针错误引起的)。有关寻找转储的更多信息,请参见“错误查找”

如果使用CONFIG_KALLSYMS编译内核,则可以按原样发送转储,否则,您将不得不使用该ksymoops程序来理解转储(但通常首选使用CONFIG_KALLSYMS进行编译)。可以从https://www.kernel.org/pub/linux/utils/kernel/ksymoops/下载该实用程序 。另外,您可以手动进行转储查找:

在上面的调试转储中,如果您可以查找EIP值的含义,那么它将大有帮助。这样的十六进制值对我或其他人没有太大帮助:它将取决于您的特定内核设置。您应该做的是从EIP行中获取十六进制值(忽略0010:),然后在内核名称列表中查找该值,以查看哪个内核函数包含有问题的地址。

要找出内核函数名称,您需要找到与表现出该症状的内核相关的系统二进制文件。这是文件“ linux/vmlinux”。要提取名称列表并将其与内核崩溃时的EIP匹配,请执行以下操作:

nm vmlinux | sort | less

这将为您提供按升序排序的内核地址列表,从中可以轻松找到包含违规地址的函数。请注意,内核调试消息给出的地址不一定与功能地址完全匹配(实际上,这不太可能),因此您不能只是“ grep”列表:但是,列表将为您提供每个内核函数的起始点,因此,通过查找起始地址比您要查找的起始地址低的函数,然后查找具有较高地址的函数,可以找到所需的起始地址。实际上,在问题报告中包括一些“上下文”可能是个好主意,在有趣的地方加上几行即可。

如果由于某种原因您不能执行上述操作(您有预编译的内核映像或类似文件),请尽可能多地告诉他有关您的设置的信息。有关详细信息,请阅读“报告问题”。

另外,您可以在运行的内核上使用gdb。(只读;即,您不能更改值或设置断点。)为此,首先使用-g编译内核;适当地编辑arch/x86/Makefile,然后执行。您还需要启用CONFIG_PROC_FS(通过)。

make cleanmake config

使用新内核重新引导后,请执行。现在,您可以使用所有常用的gdb命令。查找系统崩溃点的命令是。(用EIP值替换XXXes。)

gdb vmlinux /proc/kcorel *0xXXXXXXXX

当前,对非运行内核进行gdb操作失败,因为gdb(错误地)无视了为其编译内核的起始偏移量。

MySQL 小结

1. 备份数据库中的表。

1.1 选择备份路径,执行备份。

退出mysql客户端并切换到D盘,d:

mysqldump -u root -p employee > myemployee.sql

注: employee 是数据库名, myemployee.sql 是备份文件名
确认成功后,尝试删除数据库

2. 删除数据库

mysql -u root -p 
mysql> drop database 数据库名;
mysql> drop database employee;

3. 尝试恢复数据库。

3.1 先创建数据库

mysql -u root -p 
passwd: xxxxxx
mysql> create database employee;
mysql> exit
d:\> mysql -u root -p employee < myemployee.sql   还原数据库中的表
password: xxxxxx
d:\> mysql -u root -p 
password: xxxxxx
mysql> show databases;     显示数据库
mysql> use employee;     打开数据库
mysql> desc employee_tbl;   描述表结构
mysql> show tables;  显示表名

3.2 一条命令执行查询的方法:

D:\>mysql -u root -pzypxxx -e "use employee; select coalesce(name,'总数:'), SUM(signin) as sigin_total from employee_tbl group by name with rollup;"

4. 额外创建一个表user_into

mysql> use employee;
mysql> create table user_info (
-> `id`  int(11) NOT NULL, 
-> `name` varchar(10) NOT NULL DEFAULT '',
-> `age`  int(3) NOT NULL,
-> `sex`  varchar(2) NOT NULL,
-> `salary`  float(9,2) NOT NULL,
-> PRIMARY KEY(`id`));
mysql> insert into user_info values 
-> ('1', '小明', 23, '男', 5200.22),
-> ('2', '小王', 24, '男', 5300.22),
-> ('3', '小美', 26, '女', 6200.32);

5. 更新表结构

mysql>alter table user_info add column `Addr`  varchar(100) NOT NULL after `salary`;
mysql>update  user_info set Addr='奉贤紫屿培训学校' where name='小明';

6. 联合查询连接功能

mysql> select a.name, a.age, a.salary, b.signin from user_info a inner join employee_tbl b  on a.name=b.name;

7. 总结

  • 库操作: 增删改查
    增:create database 数据库名字;
    删:drop database 数据库名字;
    改: use 数据库名字; 打开数据库
    查:show databases;
  • 表操作: 增删改查
    增:create table 表名(字段名 字段类型 字段属性, 字段名2.....);

    create table aa (`id` int(10)  NOT NULL Auto_increment, `name` varchar(20) NOT NULL);

    删:drop table aa;
    改:alter table aa ADD COLUMN addr varchar(10) NOT NULL AFTER name;

    alter table  aa MODIFY COLUMN `salary` float(9,2);
    alter table  aa DEL COLUMN `addr`;
    改记录
    update  aa set salary=5300.33 where name='小明';

    查:desc aa; 查表结构
    查记录: select 字段1, 字段2 .... 字段N FROM 表名;

               select * from aa; 
               select * from aa where  id=1; 
               select * from aa order by id desc; 
               select * from aa order by id asc;
               select * from aa group by name;
               select name,  count(*) from aa group by name;
               select coalesce(name, "总数:"),  SUM(signin) from aa group by name with rollup;

    8.数据表的备份和还原

    8.1 备份数据库:

    mysqldump -u root -p 数据库名字  >  备份文件.sql

    8.2 还原数据表:

    mysql -u root -p -e "create database bbs;"
    mysql -u root -p bbs < 备份文件.sql

mysql -u root -p -e "create database bbs"
mysql -u root -p bbs < 备份文件.sql

ESP32测试脚本

ESP32 测试脚本

Micropython

from machine import Pin
from time import sleep

leds = [13, 12, 14, 27, 26, 25, 33, 32, 23, 22, 21, 19, 18, 5, 16, 17, 4, 0, 2, 15 ]
try:
    while True:
        for i in range(len(leds)):
            print(leds[i])
            i = Pin(leds[i], Pin.OUT)
            i.on()
except KeyboardInterrupt:
    print("\nCtrl-C pressed.")

KiCAD 第一弹: 小白入门级

KiCAD

缘起

自从安装了 KiCAD 以后,突然发现这是一个非常棒的开源软件,好多的资源可以用,内心激动的迫不及待的想做出一个 PCB 板.手头还有一片 ATmega328P-AU 的 arduino 芯片,赶紧搜索了一下 arduino 的最小系统原理图,照猫画虎来了一遍.其实还是有多小细节要注意的.

其实发现还是有 arduino Uno 的一个器件的.还需要慢慢摸索.这次的硬核马拉松我觉得我要败了..

发现

树莓派上竟然也可以跑 kicad, 而且安装极其简单,简单的不像话....

sudo apt-get update 
sudo apt-get -y install kicad
kicad &

就好了.就打开了,第一次可能有点儿卡顿,但是一旦跑起来那种丝般柔顺的感觉真的很舒服~
突然就爱上了这个软件.虽然相比 AD 可能还有很大差距,但是毕竟是开源软件,还有那么多用户,github 也是人气满满.强烈推荐大家尝试一下..
我发现我需要学习的东西太多了,我一直感觉自己是一个小白一样的存在, 看了很多资料还是前面看完后面就不记得了....
哎,人到中年不如狗系列啊!
好了,不吐槽了.还是要有满满的正能量才可以, 继续啃啃技术材料吧~
我是骑驴玩儿漂移,一个胖胖的爱玩儿树莓派或者是喜欢嘚瑟的胖纸!

抗击疫情宅家充电系列-树莓派编程基础

抗击疫情宅家充电系列

今天受邀在电子森林,哦,应该是硬禾学堂做了树莓派的入门级讲解,昨天也做了一个硬件讲解的直播,使用的软件是小鹅通,感觉还不错,有兴趣的朋友可以尝试一下.

下面是直播的地址:

第一天内容