Browse Source

working for now

main
Hendrik Langer 5 years ago
parent
commit
04ec3a9897
  1. 37
      README.md
  2. 8
      platformio.ini
  3. 14
      send.py
  4. 38
      src/main.cpp
  5. 45
      src/stepper.h

37
README.md

@ -0,0 +1,37 @@
MidiStepper
===========
Made for an old (AnyCubic) Trigorilla-Board from an 3D-Printer.
Also compatible with Arduino Nano and old floppy drives.
Floppy pins:
------------
.....j..DS.......
..G5 . ...j..GG.......
j: jumper (drive select)
D: direction
S: step
G: corresponding ground
5: 5V for the motors
Caveats:
--------
The ATmega2560 has 6 timers, so we can use them to generate the square waves for the steps. Be aware that delay() and similar arduino-functions will not work as expected if you extend this and use Timer0. RAMPS14-compatible boards have only 5 stepper drivers, so we're fine.
Other arduinos don't have enough timer peripherals, so we generate them in software. This could be done in an ISR. See: https://www.youtube.com/watch?v=fHAO7SW-SZI
Usage:
------
The arduino part accepts raw midi messages over its serial interface. baudrate is 115200.
Use the python script send.py to send midi files over the serial port. It can also act as a virtual midi port.
Compile:
--------
$ git clone
$ virtualenv -p python --no-site-packages .
$ source bin/activate
$ pip install -U platformio
$ pio run
$ pio run -t upload

8
platformio.ini

@ -10,10 +10,12 @@
[platformio]
default_envs = megaatmega2560
#default_envs = nano
[common]
lib_deps =
ToneLibrary
# TimerOne
# AccelStepper
# SpeedyStepper
MIDI Library
@ -30,3 +32,9 @@ platform = atmelavr
board = megaatmega2560
board_build.f_cpu = 16000000L
lib_deps = ${common.lib_deps}
[env:nano]
platform = atmelavr
board = nanoatmega328
board_build.f_cpu = 16000000L
lib_deps = ${common.lib_deps}

14
send.py

@ -4,7 +4,7 @@ import sys, argparse
import time
import threading
from mido import MidiFile
import mido
import serial
drum_channels = [9]
@ -23,16 +23,22 @@ def main(argv):
inputfile = ''
outputport = ''
parser = argparse.ArgumentParser()
parser.add_argument('midifilename', help="the midi file you want to send")
parser.add_argument('midifilename', help="the midi file you want to send. Set 'ALSA' for virtual midi port, see 'aconnect -o'")
parser.add_argument('-P', '--serialport', help="serial port to open", default="/dev/ttyUSB0")
parser.add_argument('--with-drums', action="store_true", help="send percussion track 10")
parser.add_argument('--delay', help="add delay before startup", type=int, default=1)
args = parser.parse_args()
with serial.Serial(args.serialport, 115200, timeout=12) as ser:
receivethread = threading.Thread(target=serialreceive, args=(ser,))
receivethread.daemon = True
receivethread.start()
time.sleep(1)
with MidiFile(args.midifilename) as mid:
time.sleep(args.delay)
if args.midifilename == 'ALSA':
# portmidi = mido.Backend('mido.backends.portmidi')
midi_in = mido.open_input()
else:
midi_in = mido.MidiFile(args.midifilename)
with midi_in as mid:
for msg in mid:
time.sleep(msg.time)
if not msg.is_meta:

38
src/main.cpp

@ -5,9 +5,26 @@
*/
#include <Arduino.h>
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
#include "pins/pins_TRIGORILLA_14.h"
#include <Tone.h>
#elif defined(__AVR_ATmega328P__)
#define LED_PIN LED_BUILTIN
#define X_DIR_PIN PD2
#define X_STEP_PIN PD3
#define X_ENABLE_PIN A0
#define Y_DIR_PIN PD4
#define Y_STEP_PIN PD5
#define Y_ENABLE_PIN A1
#define Z_DIR_PIN PD6
#define Z_STEP_PIN PD7
#define Z_ENABLE_PIN A2
#define E0_DIR_PIN PB0
#define E0_STEP_PIN PB1
#define E0_ENABLE_PIN A3
#define E1_DIR_PIN PB2
#define E1_STEP_PIN PB3
#define E1_ENABLE_PIN A4
#endif
#include <MIDI.h>
//#include "midi/noteList.h"
@ -24,7 +41,11 @@ MIDI_CREATE_CUSTOM_INSTANCE(HardwareSerial, Serial, MIDI, MySettings);
const int NUM_STEPPER = 5;
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
TimerStepper stepper[NUM_STEPPER];
#elif defined(__AVR_ATmega328P__)
LoopStepper stepper[NUM_STEPPER];
#endif
unsigned long previousMillis[NUM_STEPPER] = {0}; // will store last time LED was updated
const long interval = 1000; // interval at which to blink (milliseconds)
@ -140,6 +161,19 @@ void setup()
stepper[3].begin(E0_DIR_PIN, E0_STEP_PIN, E0_ENABLE_PIN);
stepper[4].begin(E1_DIR_PIN, E1_STEP_PIN, E1_ENABLE_PIN);
for (int i = 0; i < NUM_STEPPER; i++) {
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
stepper[i].setMaxFrequency(12000);
#elif defined(__AVR_ATmega328P__)
stepper[i].setMaxFrequency(1400);
Serial.print("homing stepper ");
Serial.println(i);
stepper[i].setMaxPosition(80);
#endif
}
MIDI.setHandleNoteOn(handleNoteOn);
MIDI.setHandleNoteOff(handleNoteOff);
MIDI.setHandlePitchBend(handlePitchBend);

45
src/stepper.h

@ -3,6 +3,7 @@
#include <Arduino.h>
#include <Tone.h>
//#include <TimerOne.h>
class FrequencyLUT {
public:
@ -12,7 +13,11 @@ class FrequencyLUT {
};
FrequencyLUT::FrequencyLUT() {
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
int pitch = 24;
#elif defined(__AVR_ATmega328P__)
int pitch = 0;
#endif
frequencies = malloc(128*sizeof(uint16_t));
for (int d=0; d<128; d++) {
frequencies[d] = pow(2.0, (d-69.0+pitch)/12.0) * 440.0;
@ -35,12 +40,14 @@ class Stepper {
virtual void stopTone() = 0;
void enable();
void disable();
void setMaxFrequency(uint16_t max_freq);
protected:
int8_t currentNote;
int dir_pin;
int step_pin;
int enable_pin;
uint8_t multiplicator = 4;
uint16_t maxFrequency;
};
class TimerStepper : public Stepper {
@ -59,8 +66,12 @@ class LoopStepper : public Stepper {
void playTone(uint16_t freq) override;
void stopTone() override;
void loop() override;
void setMaxPosition(int pos);
private:
unsigned long currentStepMicros;
unsigned long currentStepMicros = 0;
unsigned long currentPosition;
unsigned long maxPosition;
bool direction;
unsigned long prevStepMicros;
};
@ -81,6 +92,7 @@ void Stepper::enable() {
}
void Stepper::disable() {
stopTone();
digitalWrite(enable_pin, HIGH);
}
@ -88,7 +100,7 @@ void Stepper::playNote(int8_t midi_note) {
currentNote = midi_note;
uint16_t f = frequencies[midi_note];
f *= multiplicator;
while (f > 12000) f/=2;
while (f > maxFrequency) f/=2;
playTone(f);
}
@ -98,6 +110,10 @@ void Stepper::bend(int value) {
playTone(f_b);
}
void Stepper::setMaxFrequency(uint16_t max_freq) {
maxFrequency = max_freq;
}
void TimerStepper::begin(int dir_pin, int step_pin, int enable_pin) {
Stepper::begin(dir_pin, step_pin, enable_pin);
tone.begin(step_pin);
@ -128,15 +144,34 @@ void LoopStepper::stopTone() {
currentStepMicros = 0;
}
void LoopStepper::setMaxPosition(int pos) {
maxPosition = 2*pos;
currentPosition = 2*pos;
currentStepMicros = 4545UL;
direction = 1;
prevStepMicros = micros();
while (currentPosition > 0) loop();
while (currentPosition != 2) loop();
currentPosition = 0; maxPosition -=4;
direction = 0;
currentStepMicros = 0;
}
void LoopStepper::loop() {
if (currentStepMicros == 0) return;
if (micros() - prevStepMicros >= currentStepMicros) {
prevStepMicros += currentStepMicros;
digitalWrite(step_pin, HIGH);
digitalWrite(step_pin, LOW);
digitalWrite(step_pin, !digitalRead(step_pin));
// digitalWrite(step_pin, HIGH);
// digitalWrite(step_pin, LOW);
if (direction == 0) currentPosition++;
else currentPosition--;
if (currentPosition >= maxPosition) direction = 1;
if (currentPosition <= 0) direction = 0;
digitalWrite(dir_pin, direction);
}
}
#endif /* _STEPPER_H */

Loading…
Cancel
Save