[M] Rename project
This commit is contained in:
@@ -0,0 +1,7 @@
|
||||
.pio
|
||||
CMakeListsPrivate.txt
|
||||
cmake-build-*/
|
||||
.idea
|
||||
|
||||
.DS_Store
|
||||
._*
|
||||
@@ -0,0 +1,33 @@
|
||||
# !!! WARNING !!! AUTO-GENERATED FILE, PLEASE DO NOT MODIFY IT AND USE
|
||||
# https://docs.platformio.org/page/projectconf/section_env_build.html#build-flags
|
||||
#
|
||||
# If you need to override existing CMake configuration or add extra,
|
||||
# please create `CMakeListsUser.txt` in the root of project.
|
||||
# The `CMakeListsUser.txt` will not be overwritten by PlatformIO.
|
||||
|
||||
cmake_minimum_required(VERSION 3.13)
|
||||
set(CMAKE_SYSTEM_NAME Generic)
|
||||
set(CMAKE_C_COMPILER_WORKS 1)
|
||||
set(CMAKE_CXX_COMPILER_WORKS 1)
|
||||
|
||||
project("untitled" C CXX)
|
||||
|
||||
include(CMakeListsPrivate.txt)
|
||||
|
||||
if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/CMakeListsUser.txt)
|
||||
include(CMakeListsUser.txt)
|
||||
endif()
|
||||
|
||||
add_custom_target(
|
||||
Production ALL
|
||||
COMMAND platformio -c clion run "$<$<NOT:$<CONFIG:All>>:-e${CMAKE_BUILD_TYPE}>"
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
)
|
||||
|
||||
add_custom_target(
|
||||
Debug ALL
|
||||
COMMAND platformio -c clion debug "$<$<NOT:$<CONFIG:All>>:-e${CMAKE_BUILD_TYPE}>"
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
)
|
||||
|
||||
add_executable(Z_DUMMY_TARGET ${SRC_LIST})
|
||||
@@ -0,0 +1,43 @@
|
||||
# Taiko-stick / 太鼓槌
|
||||
|
||||
A pair of drumsticks that can be used to play Taiko no Tatsujin on any surface.
|
||||
|
||||
一对可以在任何表面上打太鼓达人的鼓槌.
|
||||
|
||||
## 1. Build / 制作
|
||||
|
||||
### Materials Required / 材料
|
||||
|
||||
* 2x Thick-enough drumsticks
|
||||
(The one I used: [taobao link](https://item.taobao.com/item.htm?id=665108049486))
|
||||
* 2x Piezo sensors (压电/蜂鸣陶瓷片)
|
||||
* 2x 1MΩ resistors
|
||||
* 1x Arduino Nano
|
||||
(or any other dev board, just change the platformio config)
|
||||
* Many wires
|
||||
|
||||
### Tools Required / 工具
|
||||
|
||||
* Either a breadboard, SPL2 solder-less connectors, or a soldering kit
|
||||
* A computer
|
||||
|
||||
### Connections / 连接
|
||||
|
||||

|
||||
|
||||
## 2. Run / 运行
|
||||
|
||||
### Flash Firmware / 烧录固件
|
||||
|
||||
1. Install PlatformIO Core ([Guide](https://platformio.org/install/cli))
|
||||
2. Connect the Arduino Nano to your computer
|
||||
3. Upload firmware using `platformio run --target upload`
|
||||
|
||||
### Run Backend / 运行后端
|
||||
|
||||
I'm too lazy to write a HID device driver, so I'm using a python script to read the serial output from the Arduino and send keystrokes to the computer.
|
||||
|
||||
1. Install Python 3.11+ ([Guide](https://www.python.org/downloads/))
|
||||
2. Install dependencies using `pip install -r requirements.txt`
|
||||
3. Run `python reader.py`
|
||||
4. Use `Ctrl+C` to exit.
|
||||
@@ -0,0 +1,69 @@
|
||||
"""
|
||||
This script reads the Arduino's serial output and convert it to keyboard input.
|
||||
|
||||
Requirements: pip install pyserial keyboard matplotlib
|
||||
"""
|
||||
import time
|
||||
|
||||
import keyboard
|
||||
import serial.tools.list_ports
|
||||
|
||||
TAIKO_KEYS = ['f', 'd']
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
# List serial ports
|
||||
ports = serial.tools.list_ports.comports()
|
||||
|
||||
# If there are no ports, exit
|
||||
if not ports:
|
||||
print('No serial ports found!')
|
||||
exit(1)
|
||||
|
||||
# If there are more than one serial port, print them out
|
||||
if len(ports) > 1:
|
||||
print('Multiple serial ports found:')
|
||||
for i, port in enumerate(ports):
|
||||
print(f'[{i}] {port.device}')
|
||||
print()
|
||||
|
||||
# Ask the user to select one
|
||||
inp = input('Select a port: ')
|
||||
port = ports[int(inp)].device
|
||||
|
||||
# If there is only one serial port, use it
|
||||
else:
|
||||
port = ports[0].device
|
||||
|
||||
# Open the serial port
|
||||
print(f'Opening serial port {port}...')
|
||||
ser = serial.Serial(port, 115200)
|
||||
|
||||
# Read the serial port
|
||||
try:
|
||||
start_time = time.time()
|
||||
while True:
|
||||
line = ser.readline().decode('utf-8', errors='ignore').strip()
|
||||
print(line)
|
||||
|
||||
# If the line starts with ";", it's a plot point
|
||||
if line.startswith(';'):
|
||||
line = line[1:].split(';')
|
||||
ys = [float(y) / 1024.0 for y in line]
|
||||
yleft, yright = ys
|
||||
|
||||
# If the line starts with ":", it's a keyboard input
|
||||
elif line.startswith('Hit:'):
|
||||
# Index of the drumstick that hit the piezo
|
||||
line = line[4:]
|
||||
cmd = line[0]
|
||||
key = TAIKO_KEYS[int(line[1:])]
|
||||
|
||||
if cmd == "+":
|
||||
keyboard.press(key)
|
||||
elif cmd == "-":
|
||||
keyboard.release(key)
|
||||
|
||||
except KeyboardInterrupt:
|
||||
ser.close()
|
||||
print('Closed serial port.')
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 14 MiB |
@@ -0,0 +1,39 @@
|
||||
|
||||
This directory is intended for project header files.
|
||||
|
||||
A header file is a file containing C declarations and macro definitions
|
||||
to be shared between several project source files. You request the use of a
|
||||
header file in your project source file (C, C++, etc) located in `src` folder
|
||||
by including it, with the C preprocessing directive `#include'.
|
||||
|
||||
```src/main.c
|
||||
|
||||
#include "header.h"
|
||||
|
||||
int main (void)
|
||||
{
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
Including a header file produces the same results as copying the header file
|
||||
into each source file that needs it. Such copying would be time-consuming
|
||||
and error-prone. With a header file, the related declarations appear
|
||||
in only one place. If they need to be changed, they can be changed in one
|
||||
place, and programs that include the header file will automatically use the
|
||||
new version when next recompiled. The header file eliminates the labor of
|
||||
finding and changing all the copies as well as the risk that a failure to
|
||||
find one copy will result in inconsistencies within a program.
|
||||
|
||||
In C, the usual convention is to give header files names that end with `.h'.
|
||||
It is most portable to use only letters, digits, dashes, and underscores in
|
||||
header file names, and at most one dot.
|
||||
|
||||
Read more about using header files in official GCC documentation:
|
||||
|
||||
* Include Syntax
|
||||
* Include Operation
|
||||
* Once-Only Headers
|
||||
* Computed Includes
|
||||
|
||||
https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html
|
||||
@@ -0,0 +1,46 @@
|
||||
|
||||
This directory is intended for project specific (private) libraries.
|
||||
PlatformIO will compile them to static libraries and link into executable file.
|
||||
|
||||
The source code of each library should be placed in a an own separate directory
|
||||
("lib/your_library_name/[here are source files]").
|
||||
|
||||
For example, see a structure of the following two libraries `Foo` and `Bar`:
|
||||
|
||||
|--lib
|
||||
| |
|
||||
| |--Bar
|
||||
| | |--docs
|
||||
| | |--examples
|
||||
| | |--src
|
||||
| | |- Bar.c
|
||||
| | |- Bar.h
|
||||
| | |- library.json (optional, custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html
|
||||
| |
|
||||
| |--Foo
|
||||
| | |- Foo.c
|
||||
| | |- Foo.h
|
||||
| |
|
||||
| |- README --> THIS FILE
|
||||
|
|
||||
|- platformio.ini
|
||||
|--src
|
||||
|- main.c
|
||||
|
||||
and a contents of `src/main.c`:
|
||||
```
|
||||
#include <Foo.h>
|
||||
#include <Bar.h>
|
||||
|
||||
int main (void)
|
||||
{
|
||||
...
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
PlatformIO Library Dependency Finder will find automatically dependent
|
||||
libraries scanning project source files.
|
||||
|
||||
More information about PlatformIO Library Dependency Finder
|
||||
- https://docs.platformio.org/page/librarymanager/ldf.html
|
||||
@@ -0,0 +1,14 @@
|
||||
; PlatformIO Project Configuration File
|
||||
;
|
||||
; Build options: build flags, source filter
|
||||
; Upload options: custom upload port, speed and extra flags
|
||||
; Library options: dependencies, extra library storages
|
||||
; Advanced options: extra scripting
|
||||
;
|
||||
; Please visit documentation for the other options and examples
|
||||
; https://docs.platformio.org/page/projectconf.html
|
||||
|
||||
[env:nanoatmega328new]
|
||||
platform = atmelavr
|
||||
board = nanoatmega328new
|
||||
framework = arduino
|
||||
@@ -0,0 +1,2 @@
|
||||
pyserial
|
||||
keyboard
|
||||
@@ -0,0 +1,81 @@
|
||||
#include <Arduino.h>
|
||||
|
||||
#define val const auto
|
||||
#define let auto
|
||||
|
||||
/**
|
||||
* Since the arduino library doesn't have printf, we have to make our own
|
||||
*/
|
||||
void send(const char* format, ...)
|
||||
{
|
||||
char buffer[512];
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
vsnprintf(buffer, sizeof(buffer), format, args);
|
||||
va_end(args);
|
||||
Serial.println(buffer);
|
||||
}
|
||||
|
||||
const int NUM_DRUMSTICKS = 2;
|
||||
const int DRUMSTICK_PINS[] = {A0, A1};
|
||||
int LAST_VALUES[] = {0, 0};
|
||||
|
||||
unsigned long LAST_HIT_TIMES[] = {0, 0};
|
||||
|
||||
// Values range from 0 to 1023, but since we reduced the resolution to 8 bits, we need to divide by 8
|
||||
// After the division, values range from 0 to 127
|
||||
val threshold = (int) (0.7 * 127);
|
||||
|
||||
// Minimum time between two hits
|
||||
// This is to prevent falsely detecting the bouncing force as a hit
|
||||
val bounce_delay = 5;
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
for (val pin: DRUMSTICK_PINS) pinMode(pin, INPUT);
|
||||
|
||||
send("Initialized");
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
val time = millis();
|
||||
|
||||
// Loop through all the pins, indexed
|
||||
for (let i = 0; i < NUM_DRUMSTICKS; i++)
|
||||
{
|
||||
val pin = DRUMSTICK_PINS[i];
|
||||
val value = analogRead(pin) / 8;
|
||||
val last = LAST_VALUES[i];
|
||||
LAST_VALUES[i] = value;
|
||||
|
||||
// If the value is different from the last value, update it
|
||||
if (value != last)
|
||||
{
|
||||
// Check last hit time
|
||||
val last_hit_time = LAST_HIT_TIMES[i];
|
||||
if (time - last_hit_time < bounce_delay)
|
||||
continue;
|
||||
|
||||
// If it's greater than the threshold
|
||||
if (value > threshold)
|
||||
{
|
||||
send(";%d;%d", i, value);
|
||||
|
||||
// If the last value was less than the threshold, it means the drumstick was just hit
|
||||
if (last < threshold)
|
||||
send("Hit:+%d", i);
|
||||
}
|
||||
else
|
||||
{
|
||||
// If the last value was greater than the threshold, it means the drumstick was just released
|
||||
if (last > threshold)
|
||||
{
|
||||
send("Hit:-%d", i);
|
||||
LAST_HIT_TIMES[i] = time;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user