Skip to content

Commit

Permalink
Merge branch 'release/1.2.0'
Browse files Browse the repository at this point in the history
  • Loading branch information
laurb9 committed Feb 9, 2019
2 parents 2fe6a8a + 8b2e10e commit d241495
Show file tree
Hide file tree
Showing 10 changed files with 160 additions and 62 deletions.
7 changes: 7 additions & 0 deletions .cli-config.yml
@@ -0,0 +1,7 @@
sketchbook_path: .arduino
arduino_data: .arduino
board_manager:
additional_urls:
- http://arduino.esp8266.com/stable/package_esp8266com_index.json
- https://dl.espressif.com/dl/package_esp32_index.json
- https://adafruit.github.io/arduino-board-index/package_adafruit_index.json
9 changes: 9 additions & 0 deletions .gitignore
Expand Up @@ -33,5 +33,14 @@
# VScode
.vscode

# PyCharm/Jetbrains editors
.idea

# Mac
.DS_Store

# Arduino
*.hex
*.bin
*.elf
.arduino
21 changes: 21 additions & 0 deletions .travis.yml
@@ -0,0 +1,21 @@
language: minimal
git:
depth: false
addons:
apt:
packages:
- python
env:
matrix:
- TARGET=arduino:avr:uno
- TARGET=adafruit:samd:adafruit_feather_m0
- TARGET=arduino:avr:mega
- TARGET=esp8266:esp8266:nodemcu
before_install:
- make setup
install: true
script:
- make all
cache:
directories:
- .arduino
54 changes: 54 additions & 0 deletions Makefile
@@ -0,0 +1,54 @@
# Default build architecture and board
TARGET ?= arduino:avr:uno

# Default list of cores to install with `make setup`
CORES ?= arduino:avr adafruit:samd esp8266:esp8266 esp32:esp32

# Where to save the Arduino support files, this should match what is in .cli-config.yml
ARDUINO_DIR ?= .arduino

default:
#################################################################################################
# Initial setup: make .arduino/arduino-cli setup
#
# Build all the examples: make all TARGET=adafruit:samd:adafruit_feather_m0
#
# Install more cores: make setup CORES=arduino:samd
# (edit .cli-config.yml and add repository if needed)
#################################################################################################

ARDUINO_CLI_URL = http://downloads.arduino.cc/arduino-cli/arduino-cli-latest-linux64.tar.bz2
ARDUINO_CLI ?= $(ARDUINO_DIR)/arduino-cli --config-file .cli-config.yml
EXAMPLES := $(shell ls examples)

all: # Build all example sketches
all: $(EXAMPLES:%=%.hex)

%.hex: # Generic rule for compiling sketch to uploadable hex file
%.hex: examples/%
$(ARDUINO_CLI) compile --warnings all --fqbn $(TARGET) $< --output $@
ls -l $@*

# Remove built objects
clean:
rm -fv $(EXAMPLES:%=%.{hex,elf}*)

$(ARDUINO_DIR)/arduino-cli: # Download and install arduino-cli
$(ARDUINO_DIR)/arduino-cli:
mkdir -p $(ARDUINO_DIR)
cd $(ARDUINO_DIR)
curl -s $(ARDUINO_CLI_URL) \
| tar xfj - -O -C $(ARDUINO_DIR) \
> $@
chmod 755 $@

setup: # Configure cores and libraries for arduino-cli (which it will download if missing)
setup: $(ARDUINO_DIR)/arduino-cli
mkdir -p $(ARDUINO_DIR)/libraries
ln -sf $(CURDIR) $(ARDUINO_DIR)/libraries/
$(ARDUINO_CLI) config dump
$(ARDUINO_CLI) core update-index
$(ARDUINO_CLI) core install $(CORES)
$(ARDUINO_CLI) core list

.PHONY: clean %.hex all setup
2 changes: 2 additions & 0 deletions README.md
@@ -1,3 +1,5 @@
[![Build Status](https://travis-ci.com/laurb9/StepperDriver.svg?branch=master)](https://travis-ci.com/laurb9/StepperDriver)

StepperDriver
=============

Expand Down
80 changes: 49 additions & 31 deletions src/BasicStepperDriver.cpp
Expand Up @@ -18,15 +18,8 @@
* Microstepping controls should be hardwired.
*/
BasicStepperDriver::BasicStepperDriver(short steps, short dir_pin, short step_pin)
:motor_steps(steps), dir_pin(dir_pin), step_pin(step_pin)
:BasicStepperDriver(steps, dir_pin, step_pin, PIN_UNCONNECTED)
{
steps_to_cruise = 0;
steps_remaining = 0;
dir_state = 0;
steps_to_brake = 0;
step_pulse = 0;
rest = 0;
step_count = 0;
}

BasicStepperDriver::BasicStepperDriver(short steps, short dir_pin, short step_pin, short enable_pin)
Expand All @@ -37,14 +30,15 @@ BasicStepperDriver::BasicStepperDriver(short steps, short dir_pin, short step_pi
dir_state = 0;
steps_to_brake = 0;
step_pulse = 0;
cruise_step_pulse = 0;
rest = 0;
step_count = 0;
}

/*
* Initialize pins, calculate timings etc
*/
void BasicStepperDriver::begin(short rpm, short microsteps){
void BasicStepperDriver::begin(float rpm, short microsteps){
pinMode(dir_pin, OUTPUT);
digitalWrite(dir_pin, HIGH);

Expand All @@ -65,7 +59,7 @@ void BasicStepperDriver::begin(short rpm, short microsteps){
/*
* Set target motor RPM (1-200 is a reasonable range)
*/
void BasicStepperDriver::setRPM(short rpm){
void BasicStepperDriver::setRPM(float rpm){
if (this->rpm == 0){ // begin() has not been called (old 1.0 code)
begin(rpm, microsteps);
}
Expand Down Expand Up @@ -125,8 +119,8 @@ void BasicStepperDriver::rotate(double deg){
/*
* Set up a new move (calculate and save the parameters)
*/
void BasicStepperDriver::startMove(long steps){
long speed;
void BasicStepperDriver::startMove(long steps, long time){
float speed;
// set up new move
dir_state = (steps >= 0) ? HIGH : LOW;
last_action_end = 0;
Expand All @@ -137,24 +131,39 @@ void BasicStepperDriver::startMove(long steps){
case LINEAR_SPEED:
// speed is in [steps/s]
speed = rpm * motor_steps / 60;
// how many steps from 0 to target rpm
steps_to_cruise = speed * speed * microsteps / (2 * profile.accel);
// how many steps are needed from target rpm to a full stop
if (time > 0){
// Calculate a new speed to finish in the time requested
float t = time / (1e+6); // convert to seconds
float d = steps_remaining / microsteps; // convert to full steps
float a2 = 1.0 / profile.accel + 1.0 / profile.decel;
float sqrt_candidate = t*t - 2 * a2 * d; // in √b^2-4ac
if (sqrt_candidate >= 0){
speed = min(speed, (t - (float)sqrt(sqrt_candidate)) / a2);
};
}
// how many microsteps from 0 to target speed
steps_to_cruise = microsteps * (speed * speed / (2 * profile.accel));
// how many microsteps are needed from cruise speed to a full stop
steps_to_brake = steps_to_cruise * profile.accel / profile.decel;
if (steps_remaining < steps_to_cruise + steps_to_brake){
// cannot reach max speed, will need to brake early
steps_to_cruise = steps_remaining * profile.decel / (profile.accel + profile.decel);
steps_to_brake = steps_remaining - steps_to_cruise;
}
// Initial pulse (c0) including error correction factor 0.676 [us]
step_pulse = (1e+6)*0.676*sqrt(2.0f/(profile.accel*microsteps));
step_pulse = (1e+6)*0.676*sqrt(2.0f/profile.accel/microsteps);
// Save cruise timing since we will no longer have the calculated target speed later
cruise_step_pulse = 1e+6 / speed / microsteps;
break;

case CONSTANT_SPEED:
default:
step_pulse = STEP_PULSE(rpm, motor_steps, microsteps);
steps_to_cruise = 0;
steps_to_brake = 0;
step_pulse = cruise_step_pulse = STEP_PULSE(rpm, motor_steps, microsteps);
if (time > steps_remaining * step_pulse){
step_pulse = (float)time / steps_remaining;
}
}
}
/*
Expand Down Expand Up @@ -208,19 +217,27 @@ long BasicStepperDriver::stop(void){
* Return calculated time to complete the given move
*/
long BasicStepperDriver::getTimeForMove(long steps){
long t;
float t;
if (steps == 0){
return 0;
}
switch (profile.mode){
case LINEAR_SPEED:
startMove(steps);
t = sqrt(2 * steps_to_cruise / profile.accel) +
(steps_remaining - steps_to_cruise - steps_to_brake) * STEP_PULSE(rpm, motor_steps, microsteps) +
sqrt(2 * steps_to_brake / profile.decel);
if (steps_remaining >= steps_to_cruise + steps_to_brake){
float speed = rpm * motor_steps / 60; // full steps/s
t = (steps / (microsteps * speed)) + (speed / (2 * profile.accel)) + (speed / (2 * profile.decel)); // seconds
} else {
t = sqrt(2.0 * steps_to_cruise / profile.accel / microsteps) +
sqrt(2.0 * steps_to_brake / profile.decel / microsteps);
}
t *= (1e+6); // seconds -> micros
break;
case CONSTANT_SPEED:
default:
t = steps * STEP_PULSE(rpm, motor_steps, microsteps);
}
return t;
return round(t);
}
/*
* Move the motor an integer number of degrees (360 = full rotation)
Expand All @@ -245,15 +262,19 @@ void BasicStepperDriver::calcStepPulse(void){
if (steps_remaining <= 0){ // this should not happen, but avoids strange calculations
return;
}

steps_remaining--;
step_count++;

if (profile.mode == LINEAR_SPEED){
switch (getCurrentState()){
case ACCELERATING:
step_pulse = step_pulse - (2*step_pulse+rest)/(4*step_count+1);
rest = (step_count < steps_to_cruise) ? (2*step_pulse+rest) % (4*step_count+1) : 0;
if (step_count < steps_to_cruise){
step_pulse = step_pulse - (2*step_pulse+rest)/(4*step_count+1);
rest = (step_count < steps_to_cruise) ? (2*step_pulse+rest) % (4*step_count+1) : 0;
} else {
// The series approximates target, set the final value to what it should be instead
step_pulse = cruise_step_pulse;
}
break;

case DECELERATING:
Expand Down Expand Up @@ -281,15 +302,12 @@ long BasicStepperDriver::nextAction(void){
unsigned m = micros();
unsigned long pulse = step_pulse; // save value because calcStepPulse() will overwrite it
calcStepPulse();
m = micros() - m;
// We should pull HIGH for 1-2us (step_high_min)
if (m < step_high_min){ // fast MCPU or CONSTANT_SPEED
delayMicros(step_high_min-m);
m = step_high_min;
};
// We should pull HIGH for at least 1-2us (step_high_min)
delayMicros(step_high_min);
digitalWrite(step_pin, LOW);
// account for calcStepPulse() execution time; sets ceiling for max rpm on slower MCUs
last_action_end = micros();
m = last_action_end - m;
next_action_interval = (pulse > m) ? pulse - m : 1;
} else {
// end of move
Expand Down
21 changes: 12 additions & 9 deletions src/BasicStepperDriver.h
Expand Up @@ -19,7 +19,7 @@
* calculate the step pulse in microseconds for a given rpm value.
* 60[s/min] * 1000000[us/s] / microsteps / steps / rpm
*/
#define STEP_PULSE(steps, microsteps, rpm) (60*1000000L/steps/microsteps/rpm)
#define STEP_PULSE(steps, microsteps, rpm) (60.0*1000000L/steps/microsteps/rpm)

// don't call yield if we have a wait shorter than this
#define MIN_YIELD_MICROS 50
Expand Down Expand Up @@ -80,7 +80,7 @@ class BasicStepperDriver {
// tWAKE wakeup time, nSLEEP inactive to STEP (us)
static const int wakeup_time = 0;

short rpm = 0;
float rpm = 0;

/*
* Movement state
Expand All @@ -92,6 +92,7 @@ class BasicStepperDriver {
long steps_to_cruise; // steps to reach cruising (max) rpm
long steps_to_brake; // steps needed to come to a full stop
long step_pulse; // step pulse duration (microseconds)
long cruise_step_pulse; // step pulse duration for constant speed section (max rpm)

// DIR pin state
short dir_state;
Expand All @@ -114,7 +115,7 @@ class BasicStepperDriver {
/*
* Initialize pins, calculate timings etc
*/
void begin(short rpm=60, short microsteps=1);
void begin(float rpm=60, short microsteps=1);
/*
* Set current microstep level, 1=full speed, 32=fine microstepping
* Returns new level or previous level if value out of range
Expand All @@ -129,12 +130,12 @@ class BasicStepperDriver {
/*
* Set target motor RPM (1-200 is a reasonable range)
*/
void setRPM(short rpm);
short getRPM(void){
void setRPM(float rpm);
float getRPM(void){
return rpm;
};
short getCurrentRPM(void){
return (short)(60*1000000L / step_pulse / microsteps / motor_steps);
float getCurrentRPM(void){
return (60.0*1000000L / step_pulse / microsteps / motor_steps);
}
/*
* Set speed profile - CONSTANT_SPEED, LINEAR_SPEED (accelerated)
Expand Down Expand Up @@ -186,9 +187,11 @@ class BasicStepperDriver {
/*
* Initiate a move over known distance (calculate and save the parameters)
* Pick just one based on move type and distance type.
* If time (microseconds) is given, the driver will attempt to execute the move in exactly that time
* by altering rpm for this move only (up to preset rpm).
*/
void startMove(long steps);
inline void startRotate(int deg){
void startMove(long steps, long time=0);
inline void startRotate(int deg){
startRotate((long)deg);
};
void startRotate(long deg);
Expand Down
5 changes: 2 additions & 3 deletions src/MultiDriver.cpp
Expand Up @@ -67,7 +67,7 @@ long MultiDriver::nextAction(void){
*/
void MultiDriver::startBrake(void){
FOREACH_MOTOR(
if (event_timers[i] >= 0){
if (event_timers[i] > 0){
motors[i]->startBrake();
}
)
Expand All @@ -91,10 +91,9 @@ bool MultiDriver::isRunning(void){
* positive to move forward, negative to reverse, 0 to remain still
*/
void MultiDriver::move(long steps1, long steps2, long steps3){
unsigned long next_event;
startMove(steps1, steps2, steps3);
while (!ready){
next_event = nextAction();
nextAction();
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/MultiDriver.h
Expand Up @@ -36,7 +36,7 @@ class MultiDriver {
// ready to start a new move
bool ready = true;
// when next state change is due for each motor
long event_timers[MAX_MOTORS];
unsigned long event_timers[MAX_MOTORS];
unsigned long next_action_interval = 0;
unsigned long last_action_end = 0;

Expand Down

0 comments on commit d241495

Please sign in to comment.