博客 页面 23

一句话

看到一句话,有理

kivy学习资料

Kivy官方文档中文翻译(基于Kivy1.9.1)
http://www.kancloud.cn/gthank/kivydoc/127813
https://github.com/cycleuser/Kivy-CN

kivy-interactive-applications-in-python-translate (这个布局讲的比较详细)
https://lord19871207.gitbooks.io/kivy-interactive-applications-in-python-translate/content/index.html

Kivy指南(这个例子多)
https://muxuezi.github.io/posts/kivy-perface.html
csdn(这个没怎么看)
http://blog.csdn.net/column/details/kivy-on-android.html
buildozer 文档(用于生成apk等安装包)
http://buildozer.readthedocs.io/en/latest/quickstart.html
当然英语好的还是看官方
kivy.org

kivy显示中文

qpython-kivy中文显示笔记


https://www.douban.com/group/topic/38428188/
http://blog.csdn.net/aphero/article/details/52139255

————————————————————————————————————————————————
打包环境下载地址 http://pan.baidu.com/s/1gfgeOT1

这里对这个打包apk的环境做下说明,以前那个版本的环境没有写说明结果发现确实不妥,还是交待下应该交待的东西(~ ̄▽ ̄)~

运行环境推荐vbox 4.3.12,当然其他版本的vbox也是可以的。 系统Ubuntu 16.04,装了xfce桌面,运行起来比较快,如果你的主机配置不错的话可以注销用户切换到unity。 打包环境已经包含了增强工具,支持共享文件夹,调整分辨率。 这个环境使用buildozer进行打包,现在的buildozer已经默认使用sdl2进行打包了。

用户名 kivydev 密码 kivydev 用户名 root 密码 root

系统已经有一个测试打包的目录/home/kivydev/kivy,这个目录下的accordion是从官方的example中复制过来的,更名为main.py,注意凡是要打包的程序,入口代码所在的脚本名必须为main.py。

打包命令 在打包前必须把测试打包项目accordion目录下的.buildozer复制到你的项目目录下。

buildozer init
#生成buildozer.spec配置文件,这个配置文件包括各种apk的配置,这里我对原始的bulldozer.spec配置文件做了修改(原始spec文件位于/usr/local/lib/python2.7/dist-packages/buildozer/default.spec/default.spec)修改的内容有:
注释掉ln16,默认包含项目目录下的所有文件
ln39,增加python2,没有这项打包时会出现找不到hostPython错误。
ln180,改为2
ln183,改为0
buildozer android_new debug #生成debug版本apk

buildozer android_new release #生成release版本apk
如果有其他错误或者完善建议欢迎issue

清华科技大讲堂——硬件开发平台对嵌入式开发的影响

本视频为陈吕洲在第六届全国高等学校计算机硬件课程教学论坛上的报告。
介绍当今全球流行的硬件开发平台(Arduino、mbed、linux等)及硬件厂家支持策略(ARM、intel等),探讨硬件开发平台对当今硬件开发工作的影响及国内外高等院校嵌入式教育模式的变革。

陈吕洲
成都墨之坊科技有限公司CEO,Arduino中文社区(arduino.cn)创始人

视频:https://www.bilibili.com/video/av10809442/

网站logo

重新设计了网站的logo

使用Genuino 101进行机器学习

#include "CurieIMU.h"
#include "CuriePME.h"

const unsigned int buttonPin = 4;
const unsigned int trainingReps = 4;
const unsigned int classification = 3;
const unsigned int len = 128;

void training()
{
    unsigned int currentClassification = 0;
    while ( currentClassification < classification ) {
        currentClassification++;

        unsigned int currentTraining = 0;
        while( currentTraining < trainingReps ) {
            currentTraining++;
            // 获取传感器数据
            byte data[128] = readVectorFromIMU(vector);
            // 使用该数据进行训练
            CuriePME.learn(vector, 128, currentClassification);
        }






    }

    unsigned int currentTraining = 0;
    while (i < repeat) {
        byte vector[vectorNumBytes];

        if (i) Serial.println("And again...");

        readVectorFromIMU(vector);
        CuriePME.learn(vector, vectorNumBytes, letter - upperStart);

        Serial.println("Got it!");
        delay(1000);
        ++i;
    }
}


/* Sample rate for accelerometer */
const unsigned int sampleRateHZ = 200;

/* No. of bytes that one neuron can hold */
const unsigned int vectorNumBytes = 128;

/* Number of processed samples (1 sample == accel x, y, z)
 * that can fit inside a neuron */
const unsigned int samplesPerVector = (vectorNumBytes / 3);


const unsigned int sensorBufSize = 2048;
const int IMULow = -32768;
const int IMUHigh = 32767;

void setup()
{
    Serial.begin(9600);
    while(!Serial);
    pinMode(buttonPin, INPUT);
    CurieIMU.begin();
    CuriePME.begin();
    CurieIMU.setAccelerometerRate(sampleRateHZ);
    CurieIMU.setAccelerometerRange(2);
    // 进入训练状态
    trainLetters();
    Serial.println("Training complete. Now, draw some letters (remember to ");
    Serial.println("hold the button) and see if the PME can classify them.");
}

void loop ()
{
    // 进入识别状态
    byte vector[vectorNumBytes];
    unsigned int category;
    char letter;

    /* Record IMU data while button is being held, and
     * convert it to a suitable vector */
    readVectorFromIMU(vector);

    /* Use the PME to classify the vector, i.e. return a category
     * from 1-26, representing a letter from A-Z */
    category = CuriePME.classify(vector, vectorNumBytes);

    if (category == CuriePME.noMatch) {
        Serial.println("Don't recognise that one-- try again.");
    } else {
        letter = category + upperStart;
        Serial.println(letter);
    }
}

/* Simple "moving average" filter, removes low noise and other small
 * anomalies, with the effect of smoothing out the data stream. */
byte getAverageSample(byte samples[], unsigned int num, unsigned int pos,
                   unsigned int step)
{
    unsigned int ret;
    unsigned int size = step * 2;

    if (pos < (step * 3) || pos > (num * 3) - (step * 3)) {
        ret = samples[pos];
    } else {
        ret = 0;
        pos -= (step * 3);
        for (unsigned int i = 0; i < size; ++i) {
            ret += samples[pos - (3 * i)];
        }

        ret /= size;
    }

    return (byte)ret;
}

/* We need to compress the stream of raw accelerometer data into 128 bytes, so
 * it will fit into a neuron, while preserving as much of the original pattern
 * as possible. Assuming there will typically be 1-2 seconds worth of
 * accelerometer data at 200Hz, we will need to throw away over 90% of it to
 * meet that goal!
 *
 * This is done in 2 ways:
 *
 * 1. Each sample consists of 3 signed 16-bit values (one each for X, Y and Z).
 *    Map each 16 bit value to a range of 0-255 and pack it into a byte,
 *    cutting sample size in half.
 *
 * 2. Undersample. If we are sampling at 200Hz and the button is held for 1.2
 *    seconds, then we'll have ~240 samples. Since we know now that each
 *    sample, once compressed, will occupy 3 of our neuron's 128 bytes
 *    (see #1), then we know we can only fit 42 of those 240 samples into a
 *    single neuron (128 / 3 = 42.666). So if we take (for example) every 5th
 *    sample until we have 42, then we should cover most of the sample window
 *    and have some semblance of the original pattern. */
void undersample(byte samples[], int numSamples, byte vector[])
{
    unsigned int vi = 0;
    unsigned int si = 0;
    unsigned int step = numSamples / samplesPerVector;
    unsigned int remainder = numSamples - (step * samplesPerVector);

    /* Centre sample window */
    samples += (remainder / 2) * 3;
    for (unsigned int i = 0; i < samplesPerVector; ++i) {
        for (unsigned int j = 0; j < 3; ++j) {
            vector[vi + j] = getAverageSample(samples, numSamples, si + j, step);
        }

        si += (step * 3);
        vi += 3;
    }
}

void readVectorFromIMU(byte vector[])
{
    byte accel[sensorBufSize];
    int raw[3];

    unsigned int samples = 0;
    unsigned int i = 0;

    /* Wait until button is pressed */
    while (digitalRead(buttonPin) == LOW);

    /* While button is being held... */
    while (digitalRead(buttonPin) == HIGH) {
        if (CurieIMU.accelDataReady()) {

            CurieIMU.readAccelerometer(raw[0], raw[1], raw[2]);
            accel[i] = (byte) map(raw[0], IMULow, IMUHigh, 0, 255);
            accel[i + 1] = (byte) map(raw[1], IMULow, IMUHigh, 0, 255);
            accel[i + 2] = (byte) map(raw[2], IMULow, IMUHigh, 0, 255);
            i += 3;
            ++samples;
            /* If there's not enough room left in the buffers
            * for the next read, then we're done */
            if (i + 3 > sensorBufSize) {
                break;
            }
        }
    }

    undersample(accel, samples, vector);
}

void trainLetter(char letter, unsigned int repeat)
{
    unsigned int i = 0;

    while (i < repeat) {
        byte vector[vectorNumBytes];

        if (i) Serial.println("And again...");

        readVectorFromIMU(vector);
        CuriePME.learn(vector, vectorNumBytes, letter - upperStart);

        Serial.println("Got it!");
        delay(1000);
        ++i;
    }
}

void trainLetters()
{
    for (char i = trainingStart; i <= trainingEnd; ++i) {
        Serial.print("Hold down the button and draw the letter '");
        Serial.print(String(i) + "' in the air. Release the button as soon ");
        Serial.println("as you are done.");

        trainLetter(i, trainingReps);
        Serial.println("OK, finished with this letter.");
        delay(2000);
    }
}


 

python调用android API

kivy提供了两种方法调用android API——plyer和jnius

plyer 封装了jnius(android)、Pyobjus(ios)和一些桌面系统的API

jnius更为底层,直接调用java api

从这里看,为了更好的跨平台,我们应该尽量使用plyer,但可能api会少一些,一些特定的地方还是要使用jnius去操作。

plyer资料:

https://github.com/kivy/plyer

https://plyer.readthedocs.io

plyer当前版本的api支持情况:

可惜并不支持android蓝牙,所以要操作蓝牙还是得用jnius

以下是网上找到的操作蓝牙代码,先贴着后面再研究

要通过python控制android蓝牙,需先通过Pyjnius去控制android java api…….

蛋疼蛋疼蛋疼,不想写java就是这样~

来自网上的示例:

'''
Bluetooth/Pyjnius example
=========================
This was used to send some bytes to an arduino via bluetooth.
The app must have BLUETOOTH and BLUETOOTH_ADMIN permissions (well, i didn't
tested without BLUETOOTH_ADMIN, maybe it works.)
Connect your device to your phone, via the bluetooth menu. After the
pairing is done, you'll be able to use it in the app.
'''

from jnius import autoclass

BluetoothAdapter = autoclass('android.bluetooth.BluetoothAdapter')
BluetoothDevice = autoclass('android.bluetooth.BluetoothDevice')
BluetoothSocket = autoclass('android.bluetooth.BluetoothSocket')
UUID = autoclass('java.util.UUID')

def get_socket_stream(name):
    paired_devices = BluetoothAdapter.getDefaultAdapter().getBondedDevices().toArray()
    socket = None
    for device in paired_devices:
        if device.getName() == name:
            socket = device.createRfcommSocketToServiceRecord(
                UUID.fromString("00001101-0000-1000-8000-00805F9B34FB"))
            recv_stream = socket.getInputStream()
            send_stream = socket.getOutputStream()
            break
    socket.connect()
    return recv_stream, send_stream

if __name__ == '__main__':
    recv_stream, send_stream = get_socket_stream('linvor')
    send_stream.write('hello\n')
    send_stream.flush()

 

# Same as before, with a kivy-based UI

'''
Bluetooth/Pyjnius example
=========================
This was used to send some bytes to an arduino via bluetooth.
The app must have BLUETOOTH and BLUETOOTH_ADMIN permissions (well, i didn't
tested without BLUETOOTH_ADMIN, maybe it works.)
Connect your device to your phone, via the bluetooth menu. After the
pairing is done, you'll be able to use it in the app.
'''

from jnius import autoclass

BluetoothAdapter = autoclass('android.bluetooth.BluetoothAdapter')
BluetoothDevice = autoclass('android.bluetooth.BluetoothDevice')
BluetoothSocket = autoclass('android.bluetooth.BluetoothSocket')
UUID = autoclass('java.util.UUID')

def get_socket_stream(name):
    paired_devices = BluetoothAdapter.getDefaultAdapter().getBondedDevices().toArray()
    socket = None
    for device in paired_devices:
        if device.getName() == name:
            socket = device.createRfcommSocketToServiceRecord(
                UUID.fromString("00001101-0000-1000-8000-00805F9B34FB"))
            recv_stream = socket.getInputStream()
            send_stream = socket.getOutputStream()
            break
    socket.connect()
    return recv_stream, send_stream

if __name__ == '__main__':
    kv = '''
BoxLayout:
    Button:
        text: '0'
        on_release: app.reset([b1, b2, b3, b4, b5])
    ToggleButton:
        id: b1
        text: '1'
        on_release: app.send(self.text)
    ToggleButton:
        id: b2
        text: '2'
        on_release: app.send(self.text)
    ToggleButton:
        id: b3
        text: '3'
        on_release: app.send(self.text)
    ToggleButton:
        id: b4
        text: '4'
        on_release: app.send(self.text)
    ToggleButton:
        id: b5
        text: '5'
        on_release: app.send(self.text)
    '''
    from kivy.lang import Builder
    from kivy.app import App

    class Bluetooth(App):
        def build(self):
            self.recv_stream, self.send_stream = get_socket_stream('linvor')
            return Builder.load_string(kv)

        def send(self, cmd):
            self.send_stream.write('{}\n'.format(cmd))
            self.send_stream.flush()

        def reset(self, btns):
            for btn in btns:
                btn.state = 'normal'
            self.send('0\n')

    Bluetooth().run()

 

 

所以说现阶段,使用python开发android程序,非但不会方便,还会有各种问题。唯一的好处只是python看着舒服点。

把kivy程序打包成windows应用

安装PyInstaller 用于打包

pip install --upgrade pyinstaller

打包命令:

python -m PyInstaller –name touchtracer examples-path\demo\touchtracer\main.py

如果要添加个图标的话,家个–icon参数

python -m PyInstaller –name touchtracer –icon examples-path\demo\touchtracer\icon.ico examples-path\demo\touchtracer\main.py

更多的参数选项见PyInstaller手册

权限不够

实际操作时提示 IOError: [Errno 13] Permission denied

 

使用kivy进行android开发

官方的一些资料:

 

官方资料的顺序怪怪的,粗看了一遍后,我决定先尝试打包APK。

打包APK

最最最讨厌的事情就是配置环境,各种软件要编译,各种依赖要安装,浪费青春。

还好,kivy提供了kivy android虚拟机。环境配置好了,直接用就行。

幸好不是坑爹的AWS,中间断了几次,但继续仍然可以下载,google云盘速度还是蛮快的。

下载并解压后,virtual box直接运行即可。

Buildozer

虚拟机上已经安装Buildozer,没做过android开发,不知道开发环境是否方便。但这个工具看起来挺方便的。

基本就两步,第一步,进入项目文件夹,进行初始化:

buildozer init

第二步,插上你的android手机,运行以下语句:

buildozer android debug deploy run

然后程序就会自动部署到手机上运行。太特么简单了!

kivy UI设计

要做kivy的UI设计还是蛮麻烦的,一大堆代码下来也搞不清楚自己写的啥了,和当初做wxpython一样痛苦。

但发现kivy还提供了一个UI设计器:

https://github.com/kivy/kivy-designer

先把项目下载到本地

然后同样要装依赖

pip install -Ur requirements.txt

还要刚才装好的kivy-garden装个文件浏览器

garden install filebrowser

然后便可以运行kivy-designer了

cd kivy-designer
python -m designer

 

python kivy安装与基础

安装

windows下安装方法:

python -m pip install docutils pygments pypiwin32 kivy.deps.sdl2 kivy.deps.glew
python -m pip install kivy

kivy.deps.gstreamer用不到的话可以不用安装

依赖

kivy构建在很多库之上,但永不到就不用装。这里可以按照官方建议装上Cython金额Pygame,以备后用。(但我没管)

pip install cython
pip install hg+http://bitbucket.org/pygame/pygame
pip install kivy

创建应用

创建个示例程序试试

import kivy
kivy.require('1.0.6') # replace with your current kivy version !

from kivy.app import App
from kivy.uix.label import Label


class MyApp(App):

    def build(self):
        return Label(text='Hello world')


if __name__ == '__main__':
    MyApp().run()

运行效果如下:

显示鼠标

kivy应用默认不显示鼠标!好坑爹的设定。

需要在./kivy/config.ini中将show_cursor = 0 改为 show_cursor = 1

 

发现的教程:http://blog.csdn.net/column/details/kivy-on-android.html