Added ML and neopixel examples

main
Alex Wulff 2022-06-27 13:45:04 -04:00
rodzic 1ebee8e2a3
commit 318cb25100
14 zmienionych plików z 299 dodań i 63 usunięć

5
.gitignore vendored
Wyświetl plik

@ -1 +1,4 @@
build/
build/
edge-impulse-sdk/
tflite-model/
model-parameters/

Plik binarny nie jest wyświetlany.

Plik binarny nie jest wyświetlany.

Wyświetl plik

@ -1,62 +0,0 @@
# This is a copy of <PICO_SDK_PATH>/external/pico_sdk_import.cmake
# This can be dropped into an external project to help locate this SDK
# It should be include()ed prior to project()
if (DEFINED ENV{PICO_SDK_PATH} AND (NOT PICO_SDK_PATH))
set(PICO_SDK_PATH $ENV{PICO_SDK_PATH})
message("Using PICO_SDK_PATH from environment ('${PICO_SDK_PATH}')")
endif ()
if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT} AND (NOT PICO_SDK_FETCH_FROM_GIT))
set(PICO_SDK_FETCH_FROM_GIT $ENV{PICO_SDK_FETCH_FROM_GIT})
message("Using PICO_SDK_FETCH_FROM_GIT from environment ('${PICO_SDK_FETCH_FROM_GIT}')")
endif ()
if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT_PATH} AND (NOT PICO_SDK_FETCH_FROM_GIT_PATH))
set(PICO_SDK_FETCH_FROM_GIT_PATH $ENV{PICO_SDK_FETCH_FROM_GIT_PATH})
message("Using PICO_SDK_FETCH_FROM_GIT_PATH from environment ('${PICO_SDK_FETCH_FROM_GIT_PATH}')")
endif ()
set(PICO_SDK_PATH "${PICO_SDK_PATH}" CACHE PATH "Path to the PICO SDK")
set(PICO_SDK_FETCH_FROM_GIT "${PICO_SDK_FETCH_FROM_GIT}" CACHE BOOL "Set to ON to fetch copy of PICO SDK from git if not otherwise locatable")
set(PICO_SDK_FETCH_FROM_GIT_PATH "${PICO_SDK_FETCH_FROM_GIT_PATH}" CACHE FILEPATH "location to download SDK")
if (NOT PICO_SDK_PATH)
if (PICO_SDK_FETCH_FROM_GIT)
include(FetchContent)
set(FETCHCONTENT_BASE_DIR_SAVE ${FETCHCONTENT_BASE_DIR})
if (PICO_SDK_FETCH_FROM_GIT_PATH)
get_filename_component(FETCHCONTENT_BASE_DIR "${PICO_SDK_FETCH_FROM_GIT_PATH}" REALPATH BASE_DIR "${CMAKE_SOURCE_DIR}")
endif ()
FetchContent_Declare(
pico_sdk
GIT_REPOSITORY https://github.com/raspberrypi/pico-sdk
GIT_TAG master
)
if (NOT pico_sdk)
message("Downloading PICO SDK")
FetchContent_Populate(pico_sdk)
set(PICO_SDK_PATH ${pico_sdk_SOURCE_DIR})
endif ()
set(FETCHCONTENT_BASE_DIR ${FETCHCONTENT_BASE_DIR_SAVE})
else ()
message(FATAL_ERROR
"PICO SDK location was not specified. Please set PICO_SDK_PATH or set PICO_SDK_FETCH_FROM_GIT to on to fetch from git."
)
endif ()
endif ()
get_filename_component(PICO_SDK_PATH "${PICO_SDK_PATH}" REALPATH BASE_DIR "${CMAKE_BINARY_DIR}")
if (NOT EXISTS ${PICO_SDK_PATH})
message(FATAL_ERROR "Directory '${PICO_SDK_PATH}' not found")
endif ()
set(PICO_SDK_INIT_CMAKE_FILE ${PICO_SDK_PATH}/pico_sdk_init.cmake)
if (NOT EXISTS ${PICO_SDK_INIT_CMAKE_FILE})
message(FATAL_ERROR "Directory '${PICO_SDK_PATH}' does not appear to contain the PICO SDK")
endif ()
set(PICO_SDK_PATH ${PICO_SDK_PATH} CACHE PATH "Path to the PICO SDK" FORCE)
include(${PICO_SDK_INIT_CMAKE_FILE})

BIN
pico-daq/.DS_Store vendored 100644

Plik binarny nie jest wyświetlany.

Wyświetl plik

@ -0,0 +1,23 @@
cmake_minimum_required(VERSION 3.12)
include(pico_sdk_import.cmake)
project(pico_daq)
pico_sdk_init()
add_executable(pico_daq
pico_daq.cpp
base64.cpp
)
pico_enable_stdio_usb(pico_daq 1)
pico_enable_stdio_uart(pico_daq 1)
pico_add_extra_outputs(pico_daq)
target_link_libraries(pico_daq
pico_stdlib
hardware_adc
hardware_dma
)

19
pico-daq/README.md 100644
Wyświetl plik

@ -0,0 +1,19 @@
# pico-daq
This program samples from the ADC, converts the sampled values to base64, and then dumps it out over Serial. You can then read in the base 64 values into a program to convert them to whatever you'd like.
## A note on the sampling
At 5 kHz w/ 16-bit samples (the default in the program) the Pico cannot write out data as fast as it reads it. Therefore, at the end of each sampling window, the program will pause ADC sampling as it finishes writing out the rest of the samples. This will lead to some jumps in the data. For my purposes of collecting audio for training a ML model this is fine. If this is not ok, try using 8-bit samples or turn down the sample rate until the LED on the Pico starts to flash.
## Logging Base64 Values
On macOS and Linux you can use the `screen` tool to save off the base64 values:
screen -L /dev/tty.usbmodem21301 115200
This command opens a serial console for the Pico and then will save the resulting text to the file `screenlog.0`, which you can then convert back to whatever format you'd like. Obviously you'd need to change `/dev/....` to the address of your Pico.
## Converting to WAV
I included a sample program to read in the base64 text values and convert it to WAV files that can be played on your computer. See `py/b64_16_to_wav.py`.

121
pico-daq/base64.cpp 100644
Wyświetl plik

@ -0,0 +1,121 @@
/*
base64.cpp and base64.h
Copyright (C) 2004-2008 René Nyffenegger
This source code is provided 'as-is', without any express or implied
warranty. In no event will the author be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this source code must not be misrepresented; you must not
claim that you wrote the original source code. If you use this source code
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original source code.
3. This notice may not be removed or altered from any source distribution.
René Nyffenegger rene.nyffenegger@adp-gmbh.ch
*/
#include "base64.h"
static const std::string base64_chars =
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz"
"0123456789+/";
static inline bool is_base64(unsigned char c) {
return (isalnum(c) || (c == '+') || (c == '/'));
}
std::string base64_encode(unsigned char const* bytes_to_encode, unsigned int in_len) {
std::string ret;
int i = 0;
int j = 0;
unsigned char char_array_3[3];
unsigned char char_array_4[4];
while (in_len--) {
char_array_3[i++] = *(bytes_to_encode++);
if (i == 3) {
char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
char_array_4[3] = char_array_3[2] & 0x3f;
for(i = 0; (i <4) ; i++)
ret += base64_chars[char_array_4[i]];
i = 0;
}
}
if (i)
{
for(j = i; j < 3; j++)
char_array_3[j] = '\0';
char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
char_array_4[3] = char_array_3[2] & 0x3f;
for (j = 0; (j < i + 1); j++)
ret += base64_chars[char_array_4[j]];
while((i++ < 3))
ret += '=';
}
return ret;
}
std::string base64_decode(std::string const& encoded_string) {
int in_len = encoded_string.size();
int i = 0;
int j = 0;
int in_ = 0;
unsigned char char_array_4[4], char_array_3[3];
std::string ret;
while (in_len-- && ( encoded_string[in_] != '=') && is_base64(encoded_string[in_])) {
char_array_4[i++] = encoded_string[in_]; in_++;
if (i ==4) {
for (i = 0; i <4; i++)
char_array_4[i] = base64_chars.find(char_array_4[i]);
char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];
for (i = 0; (i < 3); i++)
ret += char_array_3[i];
i = 0;
}
}
if (i) {
for (j = i; j <4; j++)
char_array_4[j] = 0;
for (j = 0; j <4; j++)
char_array_4[j] = base64_chars.find(char_array_4[j]);
char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];
for (j = 0; (j < i - 1); j++) ret += char_array_3[j];
}
return ret;
}

Wyświetl plik

@ -0,0 +1,3 @@
#include <string>
std::string base64_encode(unsigned char const* bytes_to_encode, unsigned int in_len);

Wyświetl plik

@ -0,0 +1,92 @@
// Sample from the ADC continuously at a particular sample rate
// and then outputs base64 bytes via Serial
// much of this code is from pico-examples/adc/dma_capture/dma_capture.c
// the rest is written by Alex Wulff (www.AlexWulff.com)
#include <stdio.h>
#include <cstring>
#include "pico/stdlib.h"
#include "hardware/adc.h"
#include "hardware/dma.h"
#include "base64.h"
// set this to determine sample rate
// 0 = 500,000 Hz
// 960 = 50,000 Hz
// 9600 = 5,000 Hz
#define CLOCK_DIV 9600
// Channel 0 is GPIO26
#define CAPTURE_CHANNEL 0
#define LED_PIN 25
#define NSAMP 20000
uint16_t capture_buf[NSAMP];
uint16_t sending_buf[NSAMP];
int main() {
stdio_init_all();
gpio_init(LED_PIN);
gpio_set_dir(LED_PIN, GPIO_OUT);
adc_gpio_init(26 + CAPTURE_CHANNEL);
adc_init();
adc_select_input(CAPTURE_CHANNEL);
adc_fifo_setup(
true, // Write each completed conversion to the sample FIFO
true, // Enable DMA data request (DREQ)
1, // DREQ (and IRQ) asserted when at least 1 sample present
false, // We won't see the ERR bit because of 8 bit reads; disable.
false // Don't shift each sample to 8 bits when pushing to FIFO
);
// set sample rate
adc_set_clkdiv(CLOCK_DIV);
sleep_ms(1000);
// Set up the DMA to start transferring data as soon as it appears in FIFO
uint dma_chan = dma_claim_unused_channel(true);
dma_channel_config cfg = dma_channel_get_default_config(dma_chan);
// Reading from constant address, writing to incrementing byte addresses
channel_config_set_transfer_data_size(&cfg, DMA_SIZE_16);
channel_config_set_read_increment(&cfg, false);
channel_config_set_write_increment(&cfg, true);
// Pace transfers based on availability of ADC samples
channel_config_set_dreq(&cfg, DREQ_ADC);
while (1) {
adc_fifo_drain();
adc_run(false);
dma_channel_configure(dma_chan, &cfg,
capture_buf, // dst
&adc_hw->fifo, // src
NSAMP, // transfer count
true // start immediately
);
// if the light does not flash, then there is some data loss.
// pico can't print the data out fast enough, so the capturing
// finishes before the data is done printing. This will result
// in the ADC not collecting for portions of the sampling
// run sampling routine
gpio_put(LED_PIN, 1);
adc_run(true);
// first transmission will be garbage since we haven't filled the buffer yet
std::string encoded =
base64_encode((unsigned char const *)sending_buf, NSAMP*2);
printf("%s", encoded.c_str());
gpio_put(LED_PIN, 0);
dma_channel_wait_for_finish_blocking(dma_chan);
memcpy(sending_buf, capture_buf, NSAMP*2);
}
}

Wyświetl plik

@ -0,0 +1,35 @@
from pydub import AudioSegment
import numpy as np
import base64
if __name__=="__main__":
infile = "/Users/alex/Desktop/pico/other-3"
outfile = "/Users/alex/Desktop/pico/other.wav"
f = open(infile, "r")
byte_data = bytearray()
vals = f.read(6000)
# Reading all at once didn't work for some reason
while vals:
byte_data.extend(base64.b64decode(vals))
vals = f.read(6000)
f.close()
# Enforce little endian
dt = np.dtype(np.uint16)
dt = dt.newbyteorder('<')
data = np.frombuffer(byte_data, dtype=dt)
data = data.astype(np.int32)
data = data-np.mean(data)
data = data.astype(np.int16)
audio = AudioSegment(
data.tobytes(),
sample_width=2,
frame_rate=5000,
channels=1
)
audio.export(outfile, format="wav")

1
pico-light-voice 160000

@ -0,0 +1 @@
Subproject commit 5a825884753207656080b091d87490348452670c

1
pico-voice-v1 160000

@ -0,0 +1 @@
Subproject commit 5a825884753207656080b091d87490348452670c