diff --git a/.gitignore b/.gitignore
index c4509976609..9c3d7df58e3 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,4 +2,6 @@ app/bin/
app/pde.jar
build/macosx/work/
core/bin/
-core/core.jar
\ No newline at end of file
+core/core.jar
+/.cproject
+/.project
diff --git a/.project b/.project
index 0b76a40ba80..a3f29214ef7 100644
--- a/.project
+++ b/.project
@@ -1,17 +1,85 @@
-
-
- processing-head
-
-
-
-
-
- org.eclipse.jdt.core.javabuilder
-
-
-
-
-
- org.eclipse.jdt.core.javanature
-
-
+
+
+ processing-head
+
+
+ Arduino_Uno
+
+
+
+ org.eclipse.cdt.managedbuilder.core.genmakebuilder
+ clean,full,incremental,
+
+
+ ?name?
+
+
+
+ org.eclipse.cdt.make.core.append_environment
+ true
+
+
+ org.eclipse.cdt.make.core.autoBuildTarget
+ all
+
+
+ org.eclipse.cdt.make.core.buildArguments
+
+
+
+ org.eclipse.cdt.make.core.buildCommand
+ make
+
+
+ org.eclipse.cdt.make.core.buildLocation
+ ${workspace_loc:/second eclipse test/Release}
+
+
+ org.eclipse.cdt.make.core.cleanBuildTarget
+ clean
+
+
+ org.eclipse.cdt.make.core.contents
+ org.eclipse.cdt.make.core.activeConfigSettings
+
+
+ org.eclipse.cdt.make.core.enableAutoBuild
+ false
+
+
+ org.eclipse.cdt.make.core.enableCleanBuild
+ true
+
+
+ org.eclipse.cdt.make.core.enableFullBuild
+ true
+
+
+ org.eclipse.cdt.make.core.fullBuildTarget
+ all
+
+
+ org.eclipse.cdt.make.core.stopOnError
+ true
+
+
+ org.eclipse.cdt.make.core.useDefaultBuildCmd
+ true
+
+
+
+
+ org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder
+ full,incremental,
+
+
+
+
+
+ org.eclipse.cdt.core.cnature
+ org.eclipse.cdt.core.ccnature
+ org.eclipse.cdt.managedbuilder.core.managedBuildNature
+ org.eclipse.cdt.managedbuilder.core.ScannerConfigNature
+ it.baeyens.arduinonature
+
+
diff --git a/app/src/processing/app/Sketch.java b/app/src/processing/app/Sketch.java
index 1d540c3741c..8e347454298 100644
--- a/app/src/processing/app/Sketch.java
+++ b/app/src/processing/app/Sketch.java
@@ -98,7 +98,7 @@ public class Sketch {
*/
private String libraryPath;
/**
- * List of library folders.
+ * List of library folders.
*/
private ArrayList importedLibraries;
@@ -365,8 +365,8 @@ protected void nameCode(String newName) {
if (!validExtension(newExtension)) {
Base.showWarning(_("Problem with rename"),
I18n.format(
- _("\".{0}\" is not a valid extension."), newExtension
- ), null);
+ _("\".{0}\" is not a valid extension."), newExtension
+ ), null);
return;
}
@@ -399,33 +399,33 @@ protected void nameCode(String newName) {
if (newName.equalsIgnoreCase(c.getFileName())) {
Base.showMessage(_("Nope"),
I18n.format(
- _("A file named \"{0}\" already exists in \"{1}\""),
- c.getFileName(),
- folder.getAbsolutePath()
- ));
+ _("A file named \"{0}\" already exists in \"{1}\""),
+ c.getFileName(),
+ folder.getAbsolutePath()
+ ));
return;
}
}
-
+
// In Arduino, don't allow a .cpp file with the same name as the sketch,
// because the sketch is concatenated into a file with that name as part
- // of the build process.
+ // of the build process.
if (newName.equals(getName() + ".cpp")) {
Base.showMessage(_("Nope"),
_("You can't have a .cpp file with the same name as the sketch."));
return;
}
-
+
if (renamingCode && currentIndex == 0) {
for (int i = 1; i < codeCount; i++) {
if (sanitaryName.equalsIgnoreCase(code[i].getPrettyName()) &&
code[i].getExtension().equalsIgnoreCase("cpp")) {
Base.showMessage(_("Nope"),
I18n.format(
- _("You can't rename the sketch to \"{0}\"\n" +
- "because the sketch already has a .cpp file with that name."),
- sanitaryName
- ));
+ _("You can't rename the sketch to \"{0}\"\n" +
+ "because the sketch already has a .cpp file with that name."),
+ sanitaryName
+ ));
return;
}
}
@@ -458,10 +458,10 @@ protected void nameCode(String newName) {
if (newFolder.exists()) {
Base.showWarning(_("Cannot Rename"),
I18n.format(
- _("Sorry, a sketch (or folder) named " +
+ _("Sorry, a sketch (or folder) named " +
"\"{0}\" already exists."),
- newName
- ), null);
+ newName
+ ), null);
return;
}
@@ -484,10 +484,10 @@ protected void nameCode(String newName) {
if (!current.renameTo(newFile, newExtension)) {
Base.showWarning(_("Error"),
I18n.format(
- _("Could not rename \"{0}\" to \"{1}\""),
- current.getFileName(),
- newFile.getName()
- ), null);
+ _("Could not rename \"{0}\" to \"{1}\""),
+ current.getFileName(),
+ newFile.getName()
+ ), null);
return;
}
@@ -529,10 +529,10 @@ protected void nameCode(String newName) {
if (!current.renameTo(newFile, newExtension)) {
Base.showWarning(_("Error"),
I18n.format(
- _("Could not rename \"{0}\" to \"{1}\""),
- current.getFileName(),
- newFile.getName()
- ), null);
+ _("Could not rename \"{0}\" to \"{1}\""),
+ current.getFileName(),
+ newFile.getName()
+ ), null);
return;
}
}
@@ -545,11 +545,11 @@ protected void nameCode(String newName) {
}
} catch (IOException e) {
Base.showWarning(_("Error"),
- I18n.format(
+ I18n.format(
"Could not create the file \"{0}\" in \"{1}\"",
- newFile,
- folder.getAbsolutePath()
- ), e);
+ newFile,
+ folder.getAbsolutePath()
+ ), e);
return;
}
SketchCode newCode = new SketchCode(newFile, newExtension);
@@ -735,7 +735,7 @@ public boolean accept(File dir, String name) {
return name.toLowerCase().endsWith(".pde");
}
});
-
+
if (pdeFiles != null && pdeFiles.length > 0) {
if (Preferences.get("editor.update_extension") == null) {
Object[] options = { _("OK"), _("Cancel") };
@@ -753,12 +753,12 @@ public boolean accept(File dir, String name) {
null,
options,
options[0]);
-
+
if (result != JOptionPane.OK_OPTION) return false; // save cancelled
-
+
Preferences.setBoolean("editor.update_extension", true);
}
-
+
if (Preferences.getBoolean("editor.update_extension")) {
// Do rename of all .pde files to new .ino extension
for (File pdeFile : pdeFiles)
@@ -768,14 +768,14 @@ public boolean accept(File dir, String name) {
}
for (int i = 0; i < codeCount; i++) {
- if (code[i].isModified())
+ if (code[i].isModified())
code[i].save();
}
calcModified();
return true;
}
-
+
protected boolean renameCodeToInoExtension(File pdeFile) {
for (SketchCode c : code) {
if (!c.getFile().equals(pdeFile))
@@ -787,7 +787,7 @@ protected boolean renameCodeToInoExtension(File pdeFile) {
}
return false;
}
-
+
/**
* Handles 'Save As' for a sketch.
@@ -861,11 +861,11 @@ protected boolean saveAs() throws IOException {
if (newName.equalsIgnoreCase(code[i].getPrettyName()) &&
code[i].getExtension().equalsIgnoreCase("cpp")) {
Base.showMessage(_("Nope"),
- I18n.format(
+ I18n.format(
_("You can't save the sketch as \"{0}\"\n" +
"because the sketch already has a .cpp file with that name."),
- newName
- ));
+ newName
+ ));
return false;
}
}
@@ -1068,7 +1068,7 @@ public boolean addFile(File sourceFile) {
if (!muchSuccess) {
Base.showWarning(_("Error adding file"),
I18n.format(_("Could not delete the existing ''{0}'' file."), filename),
- null);
+ null);
return false;
}
}
@@ -1091,7 +1091,7 @@ public boolean addFile(File sourceFile) {
} catch (IOException e) {
Base.showWarning(_("Error adding file"),
I18n.format(_("Could not add ''{0}'' to the sketch."), filename),
- e);
+ e);
return false;
}
}
@@ -1216,13 +1216,13 @@ protected void cleanup() {
// need to be recompiled, or if the board does not
// use setting build.dependency
//Base.removeDir(tempBuildFolder);
-
+
// note that we can't remove the builddir itself, otherwise
// the next time we start up, internal runs using Runner won't
// work because the build dir won't exist at startup, so the classloader
// will ignore the fact that that dir is in the CLASSPATH in run.sh
Base.removeDescendants(tempBuildFolder);
-
+
deleteFilesOnNextBuild = false;
} else {
// delete only stale source files, from the previously
@@ -1240,7 +1240,7 @@ protected void cleanup() {
}
}
}
-
+
// Create a fresh applet folder (needed before preproc is run below)
//tempBuildFolder.mkdirs();
}
@@ -1282,8 +1282,8 @@ public static void buildSettingChanged() {
private static boolean deleteFilesOnNextBuild = true;
/**
- * When running from the editor, take care of preparations before running
- * the build.
+ * When running from the editor, take care of preparations before running
+ * the build.
*/
public void prepare() {
// make sure the user didn't hide the sketch folder
@@ -1479,7 +1479,7 @@ public ArrayList getImportedLibraries() {
return importedLibraries;
}
-
+
/**
* Map an error from a set of processed .java files back to its location
* in the actual sketch.
@@ -1489,7 +1489,7 @@ public ArrayList getImportedLibraries() {
* @return A RunnerException to be sent to the editor, or null if it wasn't
* possible to place the exception to the sketch code.
*/
-// public RunnerException placeExceptionAlt(String message,
+// public RunnerException placeExceptionAlt(String message,
// String filename, int line) {
// String appletJavaFile = appletClassName + ".java";
// SketchCode errorCode = null;
@@ -1521,14 +1521,14 @@ public ArrayList getImportedLibraries() {
// line--;
//
// // getMessage() will be what's shown in the editor
-// RunnerException exception =
+// RunnerException exception =
// new RunnerException(message, codeIndex, line, -1);
// exception.hideStackTrace();
// return exception;
// }
// return null;
// }
-
+
/**
* Map an error from a set of processed .java files back to its location
@@ -1539,8 +1539,8 @@ public ArrayList getImportedLibraries() {
* @return A RunnerException to be sent to the editor, or null if it wasn't
* possible to place the exception to the sketch code.
*/
- public RunnerException placeException(String message,
- String dotJavaFilename,
+ public RunnerException placeException(String message,
+ String dotJavaFilename,
int dotJavaLine) {
int codeIndex = 0; //-1;
int codeLine = -1;
@@ -1582,7 +1582,7 @@ public RunnerException placeException(String message,
}
}
// could not find a proper line number, so deal with this differently.
- // but if it was in fact the .java file we're looking for, though,
+ // but if it was in fact the .java file we're looking for, though,
// send the error message through.
// this is necessary because 'import' statements will be at a line
// that has a lower number than the preproc offset, for instance.
@@ -1614,7 +1614,7 @@ public String build(boolean verbose) throws RunnerException {
*/
public String build(String buildPath, boolean verbose)
throws RunnerException {
-
+
// run the preprocessor
editor.status.progressUpdate(20);
String primaryClassName = preprocess(buildPath);
@@ -1628,8 +1628,8 @@ public String build(String buildPath, boolean verbose)
}
return null;
}
-
-
+
+
protected boolean exportApplet(boolean usingProgrammer) throws Exception {
return exportApplet(tempBuildFolder.getAbsolutePath(), usingProgrammer);
}
@@ -1642,7 +1642,7 @@ public boolean exportApplet(String appletPath, boolean usingProgrammer)
throws RunnerException, IOException, SerialException {
prepare();
-
+
// build the sketch
editor.status.progressNotice(_("Compiling sketch..."));
String foundName = build(appletPath, false);
@@ -1664,34 +1664,46 @@ public boolean exportApplet(String appletPath, boolean usingProgrammer)
return true;
}
-
+
public void setCompilingProgress(int percent) {
editor.status.progressUpdate(percent);
}
-
+
protected void size(String buildPath, String suggestedClassName)
- throws RunnerException {
+ throws RunnerException {
long size = 0;
String maxsizeString = Base.getBoardPreferences().get("upload.maximum_size");
if (maxsizeString == null) return;
long maxsize = Integer.parseInt(maxsizeString);
+
+ String maxramString = Base.getBoardPreferences().get("upload.maximum_ram_size");
+ long maxram = maxramString == null ? 1024 : Integer.parseInt(maxramString);
+
+ String warningramString = Base.getBoardPreferences().get("upload.warning_ram_size");
+ long warningram = warningramString == null ? maxram/2 : Integer.parseInt(warningramString);
+
Sizer sizer = new Sizer(buildPath, suggestedClassName);
- try {
+ try {
size = sizer.computeSize();
- System.out.println(
- I18n.format(
- _("Binary sketch size: {0} bytes (of a {1} byte maximum)"),
- size, maxsize
- )
- );
+ System.out.println("Binary sketch size: " + size + " bytes (of a " +
+ maxsize + " byte maximum)");
+ System.out.println("Chip memory sram: " + sizer.data +
+ " bytes (of a " +maxram+ " byte maximum)");
} catch (RunnerException e) {
- System.err.println(I18n.format(_("Couldn't determine program size: {0}"), e.getMessage()));
+ e.printStackTrace();
}
+ if (sizer.data > maxram)
+ throw new RunnerException(
+ "Allowable chip memory exceeded; see http://www.arduino.cc/en/Reference/PROGMEM to reduce ram size");
+
+ if (sizer.data > warningram)
+ System.err.println("Warning Large amount of chip memory used. Consider using PROGMEM, http://www.arduino.cc/en/Reference/PROGMEM, to reduce ram size ");
+
if (size > maxsize)
throw new RunnerException(
- _("Sketch too big; see http://www.arduino.cc/en/Guide/Troubleshooting#size for tips on reducing it."));
+ "Sketch too big; see http://www.arduino.cc/en/Guide/Troubleshooting#size for tips on reducing it.");
}
@@ -1766,9 +1778,9 @@ public boolean exportApplicationPrompt() throws IOException, RunnerException {
return false;
}
-
+
/**
- * Export to application via GUI.
+ * Export to application via GUI.
*/
protected boolean exportApplication() throws IOException, RunnerException {
return false;
@@ -1902,7 +1914,7 @@ public String getDefaultExtension() {
public List getHiddenExtensions() {
return hiddenExtensions;
}
-
+
/**
* Returns a String[] array of proper extensions.
*/
diff --git a/app/src/processing/app/debug/Sizer.java b/app/src/processing/app/debug/Sizer.java
index d67728a3c85..b6a544f9f3d 100644
--- a/app/src/processing/app/debug/Sizer.java
+++ b/app/src/processing/app/debug/Sizer.java
@@ -1,35 +1,10 @@
-/* -*- mode: jde; c-basic-offset: 2; indent-tabs-mode: nil -*- */
-
-/*
- Sizer - computes the size of a .hex file
- Part of the Arduino project - http://www.arduino.cc/
-
- Copyright (c) 2006 David A. Mellis
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software Foundation,
- Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-
- $Id$
-*/
-
package processing.app.debug;
-import processing.app.Base;
-
import java.io.*;
import java.util.*;
+import processing.app.*;
+
public class Sizer implements MessageConsumer {
private String buildPath, sketchName;
private String firstLine;
@@ -40,34 +15,40 @@ public Sizer(String buildPath, String sketchName) {
this.buildPath = buildPath;
this.sketchName = sketchName;
}
-
+
public long computeSize() throws RunnerException {
- String avrBasePath = Base.getAvrBasePath();
+ String userdir = System.getProperty("user.dir") + File.separator;
+ String avrBasePath;
+ if(Base.isMacOS()) {
+ avrBasePath = new String("Arduino.app/Contents/Resources/Java/hardware/tools/avr/bin/");
+ }
+ else if(Base.isLinux()) {
+ avrBasePath = new String("");
+ }
+ else {
+ avrBasePath = new String(userdir + "hardware/tools/avr/bin/");
+ }
String commandSize[] = new String[] {
- avrBasePath + "avr-size",
- " "
+ avrBasePath + "avr-objdump",
+ "-h",
+ ""
};
-
- commandSize[1] = buildPath + File.separator + sketchName + ".hex";
- int r = 0;
+ commandSize[2] = buildPath + File.separator + sketchName + ".elf";
+
try {
exception = null;
size = -1;
firstLine = null;
Process process = Runtime.getRuntime().exec(commandSize);
- MessageSiphon in = new MessageSiphon(process.getInputStream(), this);
- MessageSiphon err = new MessageSiphon(process.getErrorStream(), this);
-
+ MessageSiphon messageSiphon = new MessageSiphon(process.getInputStream(), this);
boolean running = true;
-
while(running) {
try {
- if (in.thread != null)
- in.thread.join();
- if (err.thread != null)
- err.thread.join();
- r = process.waitFor();
+ process.waitFor();
+ if (messageSiphon.getThread() != null) {
+ Thread.sleep(100);
+ }
running = false;
} catch (InterruptedException intExc) { }
}
@@ -76,33 +57,40 @@ public long computeSize() throws RunnerException {
// some sub-class has overridden it to do so, thus we need to check for
// it. See: http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1166589459
exception = new RunnerException(
- (e.toString() == null) ? e.getClass().getName() + r : e.toString() + r);
+ (e.toString() == null) ? e.getClass().getName() : e.toString());
}
-
+
if (exception != null)
throw exception;
-
+
if (size == -1)
throw new RunnerException(firstLine);
-
- return size;
+
+ return size+1;
}
-
+
+ public int data = 0;
public void message(String s) {
if (firstLine == null)
firstLine = s;
else {
- StringTokenizer st = new StringTokenizer(s, " ");
- try {
- st.nextToken();
- st.nextToken();
- st.nextToken();
- size = (new Integer(st.nextToken().trim())).longValue();
- } catch (NoSuchElementException e) {
- exception = new RunnerException(e.toString());
- } catch (NumberFormatException e) {
- exception = new RunnerException(e.toString());
- }
+ size+=checkTag(s," .text ");
+ data+=checkTag(s," .data ");
+ data+=checkTag(s," .bss ");
+ // exception = new RunnerException(e.toString());
+
+ }
+ }
+
+ private int checkTag(String s, String tag){
+ int size=0;
+ int p = s.indexOf(tag);
+ if(p != -1){
+ s=s.substring(p+6).trim();
+ p=s.indexOf(" ");
+ if(p != -1)
+ size = Integer.parseInt(s.substring(0,p).trim(),16);
}
+ return size;
}
}
\ No newline at end of file
diff --git a/libraries/Stepper/MultiStepper.cpp b/libraries/Stepper/MultiStepper.cpp
new file mode 100644
index 00000000000..b09c875c2dd
--- /dev/null
+++ b/libraries/Stepper/MultiStepper.cpp
@@ -0,0 +1,116 @@
+#include
+#include
+
+#include
+#include "Stepper.h"
+#include "utility/vector.h"
+
+#include "MultiStepper.h"
+
+MultiStepper::MultiStepper() {}
+
+MultiStepper::~MultiStepper() {}
+
+uint8_t MultiStepper::registerStepper(Stepper* stepper)
+{
+ this->steppers.push_back(stepper);
+ return this->steppers.size() - 1;
+}
+
+Stepper* MultiStepper::getStepper(uint8_t motor_id)
+{
+ return this->steppers[motor_id];
+}
+
+void MultiStepper::setSpeed(int speed)
+{
+ uint8_t num_motors = numMotors();
+ for (uint8_t i = 0; i < num_motors; i++) {
+ this->steppers[i]->setSpeed(speed);
+ }
+}
+
+void MultiStepper::setDriveType(Stepper::DriveType drive_type)
+{
+ uint8_t num_motors = numMotors();
+ for (uint8_t i = 0; i < num_motors; i++) {
+ this->steppers[i]->setDriveType(drive_type);
+ }
+}
+
+void MultiStepper::setHold(bool hold)
+{
+ uint8_t num_motors = numMotors();
+ for (uint8_t i = 0; i < num_motors; i++) {
+ this->steppers[i]->setHold(hold);
+ }
+}
+
+void MultiStepper::setDirection(bool forward)
+{
+ uint8_t num_motors = numMotors();
+ for (uint8_t i = 0; i < num_motors; i++) {
+ this->steppers[i]->setDirection(forward);
+ }
+}
+
+void MultiStepper::setStepsToMove(unsigned int steps_to_move)
+{
+ uint8_t num_motors = numMotors();
+ for (uint8_t i = 0; i < num_motors; i++) {
+ this->steppers[i]->setStepsToMove(steps_to_move);
+ }
+}
+
+void MultiStepper::step(int steps_to_move) {
+ uint8_t num_motors = numMotors();
+ int steps_to_move_array[num_motors];
+ for (uint8_t i = 0; i < num_motors; i++) {
+ steps_to_move_array[i] = steps_to_move;
+ }
+ step(steps_to_move_array);
+}
+
+void MultiStepper::step(int steps_to_move[])
+{
+ uint8_t num_motors = numMotors();
+
+ for (uint8_t i = 0; i < num_motors; i++) {
+ Stepper* stepper = this->steppers[i];
+
+ stepper->setStepsToMove(abs(steps_to_move[i]));
+ // determine direction based on whether steps_to_mode is + or -:
+ stepper->setDirection(steps_to_move[i] > 0);
+ }
+
+ while(true) {
+ if (!stepSlice()) {
+ // no steps left for any motor. We're done!
+ break;
+ }
+ }
+}
+
+bool MultiStepper::stepSlice()
+{
+ uint8_t num_motors = numMotors();
+
+ bool any_steps_left = false;
+ const unsigned long now = micros();
+ for (uint8_t i = 0; i < num_motors; i++) {
+ Stepper* stepper = this->steppers[i];
+ // if there are no steps left for any motors, we're done!
+ if (stepper->getStepsLeftToMove() > 0) {
+ any_steps_left = true;
+
+ stepper->stepSlice(now);
+ }
+ }
+
+ return any_steps_left;
+}
+
+uint8_t MultiStepper::numMotors()
+{
+ return this->steppers.size();
+}
diff --git a/libraries/Stepper/MultiStepper.h b/libraries/Stepper/MultiStepper.h
new file mode 100644
index 00000000000..7a6f7c05732
--- /dev/null
+++ b/libraries/Stepper/MultiStepper.h
@@ -0,0 +1,77 @@
+/*
+ Multi.h - - Stepper library for Wiring/Arduino - Version 0.4
+
+ Original library (0.1) by Tom Igoe.
+ Two-wire modifications (0.2) by Sebastian Gassner
+ Combination version (0.3) by Tom Igoe and David Mellis
+ Bug fix for four-wire (0.4) by Tom Igoe, bug fix from Noah Shibley
+
+ Drives unipolar or bipolar stepper motors using 2 wires or 4 wires
+
+ You can drive multiple motors simultaneously by calling registerStepper() multiple times
+ You can move all of them in unison using the void step(int[]) or void step(int) functions.
+*/
+
+// ensure this library description is only included once
+#ifndef MultiStepper_h
+#define MultiStepper_h
+
+#include
+#include "utility/Vector.h"
+#include "Stepper.h"
+
+// library interface description
+class MultiStepper {
+ public:
+ // constructors:
+ // Empty constructor
+ MultiStepper();
+
+ // destructor
+ ~MultiStepper();
+
+ // Registers an extra stepper. The return value is the motor's id, and should be used to
+ // reference it in the future.
+ uint8_t registerStepper(Stepper* stepper);
+
+ Stepper* getStepper(uint8_t motor_id);
+
+ // speed setter methods:
+ // Set the speed for all motors. in RPM
+ void setSpeed(int speed);
+
+ // drive type setter methods:
+ // Set the drive type for all motors.
+ void setDriveType(Stepper::DriveType drive_type);
+
+ void setDirection(bool forward);
+
+ // sets a limit on how many steps should be moved
+ void setStepsToMove(unsigned int steps_to_move);
+
+ // mover methods:
+ // Move all motors the number_of_steps
+ // Note that steps_to_move is an integer, with a max value of 2^15-1
+ void step(int steps_to_move);
+ // Move all of the motors simultaneously. Each element in the number_of_steps array corresponds
+ // to the number of steps the motor with motor_id being the index of that element should be
+ // moved. steps_to_move must have exactly numMotors() elements. If you dont want some motors
+ // to move, set those values to 0.
+ void step(int steps_to_move[]);
+
+ bool stepSlice();
+
+ // Sets whether the steppers should hold their position after they finish stepping.
+ // This can only be done for 4-pin motor configurations, and will be ignored otherwise.
+ // This will only take effect after the next step() call finishes. Call step(0) if you want to
+ // have it take immediately.
+ void setHold(bool hold);
+
+ // Returns the number of motors registered.
+ uint8_t numMotors(void);
+
+ private:
+ Vector steppers;
+};
+
+#endif
diff --git a/libraries/Stepper/Stepper.cpp b/libraries/Stepper/Stepper.cpp
index 5d6b5e53664..0d289162ebb 100644
--- a/libraries/Stepper/Stepper.cpp
+++ b/libraries/Stepper/Stepper.cpp
@@ -1,220 +1,262 @@
-/*
- Stepper.cpp - - Stepper library for Wiring/Arduino - Version 0.4
-
- Original library (0.1) by Tom Igoe.
- Two-wire modifications (0.2) by Sebastian Gassner
- Combination version (0.3) by Tom Igoe and David Mellis
- Bug fix for four-wire (0.4) by Tom Igoe, bug fix from Noah Shibley
-
- Drives a unipolar or bipolar stepper motor using 2 wires or 4 wires
-
- When wiring multiple stepper motors to a microcontroller,
- you quickly run out of output pins, with each motor requiring 4 connections.
-
- By making use of the fact that at any time two of the four motor
- coils are the inverse of the other two, the number of
- control connections can be reduced from 4 to 2.
-
- A slightly modified circuit around a Darlington transistor array or an L293 H-bridge
- connects to only 2 microcontroler pins, inverts the signals received,
- and delivers the 4 (2 plus 2 inverted ones) output signals required
- for driving a stepper motor.
-
- The sequence of control signals for 4 control wires is as follows:
-
- Step C0 C1 C2 C3
- 1 1 0 1 0
- 2 0 1 1 0
- 3 0 1 0 1
- 4 1 0 0 1
-
- The sequence of controls signals for 2 control wires is as follows
- (columns C1 and C2 from above):
-
- Step C0 C1
- 1 0 1
- 2 1 1
- 3 1 0
- 4 0 0
-
- The circuits can be found at
-
-http://www.arduino.cc/en/Tutorial/Stepper
-
-
- */
+#include
+#include
+#include
+#include "utility/Vector.h"
-#include "Arduino.h"
#include "Stepper.h"
+// Only even rows are used for full-stepping.
+// Only odd rows are used for wave-stepping.
+// All rows are used for half-stepping.
+const uint8_t Stepper::STEP_VALUES[8][4] = {
+ {HIGH, LOW, HIGH, LOW}, // not used for wave-stepping
+ {LOW, LOW, HIGH, LOW}, // not used for full-stepping
+ {LOW, HIGH, HIGH, LOW}, // not used for wave-stepping
+ {LOW, HIGH, LOW, LOW}, // not used for full-stepping
+ {LOW, HIGH, LOW, HIGH}, // not used for wave-stepping
+ {LOW, LOW, LOW, HIGH}, // not used for full-stepping
+ {HIGH, LOW, LOW, HIGH}, // not used for wave-stepping
+ {HIGH, LOW, LOW, LOW} // not used for full-stepping
+};
+
+// Pin values that turn off current to a motor so that it does not hold its position.
+// This is only possible for 4-pin configurations
+const uint8_t Stepper::OFF_VALUES[] = { LOW, LOW, LOW, LOW };
+
+Stepper::Stepper(const Stepper& copy)
+{
+ init(copy.steps_per_rev, copy.motor_pins, copy.num_pins);
+}
+
+Stepper& Stepper::operator=(const Stepper& copy) {
+ free(this->motor_pins);
+ init(copy.steps_per_rev, copy.motor_pins, copy.num_pins);
+}
+
/*
* two-wire constructor.
* Sets which wires should control the motor.
*/
-Stepper::Stepper(int number_of_steps, int motor_pin_1, int motor_pin_2)
-{
- this->step_number = 0; // which step the motor is on
- this->speed = 0; // the motor speed, in revolutions per minute
- this->direction = 0; // motor direction
- this->last_step_time = 0; // time stamp in ms of the last step taken
- this->number_of_steps = number_of_steps; // total number of steps for this motor
-
- // Arduino pins for the motor control connection:
- this->motor_pin_1 = motor_pin_1;
- this->motor_pin_2 = motor_pin_2;
-
- // setup the pins on the microcontroller:
- pinMode(this->motor_pin_1, OUTPUT);
- pinMode(this->motor_pin_2, OUTPUT);
-
- // When there are only 2 pins, set the other two to 0:
- this->motor_pin_3 = 0;
- this->motor_pin_4 = 0;
-
- // pin_count is used by the stepMotor() method:
- this->pin_count = 2;
+Stepper::Stepper(int steps_per_rev, uint8_t motor_pin_1, uint8_t motor_pin_2)
+{
+ uint8_t motor_pins[] = {motor_pin_1, motor_pin_2};
+ init(steps_per_rev, motor_pins, 2);
}
-
/*
* constructor for four-pin version
* Sets which wires should control the motor.
*/
+Stepper::Stepper(int steps_per_rev,
+ uint8_t motor_pin_1, uint8_t motor_pin_2, uint8_t motor_pin_3, uint8_t motor_pin_4)
+{
+ uint8_t motor_pins[] = {motor_pin_1, motor_pin_2, motor_pin_3, motor_pin_4};
+ init(steps_per_rev, motor_pins, 4);
+}
+
+Stepper::~Stepper()
+{
+ free(this->motor_pins);
+}
-Stepper::Stepper(int number_of_steps, int motor_pin_1, int motor_pin_2, int motor_pin_3, int motor_pin_4)
+void Stepper::init(int steps_per_rev, uint8_t motor_pins[], uint8_t num_pins)
{
- this->step_number = 0; // which step the motor is on
- this->speed = 0; // the motor speed, in revolutions per minute
- this->direction = 0; // motor direction
- this->last_step_time = 0; // time stamp in ms of the last step taken
- this->number_of_steps = number_of_steps; // total number of steps for this motor
-
- // Arduino pins for the motor control connection:
- this->motor_pin_1 = motor_pin_1;
- this->motor_pin_2 = motor_pin_2;
- this->motor_pin_3 = motor_pin_3;
- this->motor_pin_4 = motor_pin_4;
+ this->forward = true;
+ this->drive_type = FullStep;
+ this->last_step_time = 0UL;
+
+ this->motor_pins = (uint8_t*)malloc(num_pins * sizeof(uint8_t));
+ for (uint8_t i = 0; i < num_pins; i++) {
+ this->motor_pins[i] = motor_pins[i];
+ }
- // setup the pins on the microcontroller:
- pinMode(this->motor_pin_1, OUTPUT);
- pinMode(this->motor_pin_2, OUTPUT);
- pinMode(this->motor_pin_3, OUTPUT);
- pinMode(this->motor_pin_4, OUTPUT);
+ this->num_pins = num_pins;
+ this->step_delay = 0UL;
+ this->step_number = 0;
+ this->steps_per_rev = steps_per_rev;
+ this->steps_to_move = 0;
+ this->should_hold = true;
+
+ // Setup the pins on the microcontroller.
+ for (uint8_t i = 0; i < num_pins; i++) {
+ pinMode(motor_pins[i], OUTPUT);
+ }
- // pin_count is used by the stepMotor() method:
- this->pin_count = 4;
+ // Write LOW to each pin initially so the motor is not driven and current is not wasted.
+ // This only really makes sense for a 4-pin motor, but it's still better than letting the pins of
+ // a 2-pin motor have random values.
+ writeMotorPins(motor_pins, Stepper::OFF_VALUES, num_pins);
}
/*
Sets the speed in revs per minute
-
*/
-void Stepper::setSpeed(long whatSpeed)
+void Stepper::setSpeed(unsigned int speed)
{
- this->step_delay = 60L * 1000L / this->number_of_steps / whatSpeed;
+ this->step_delay = 60UL * 1000000UL / this->steps_per_rev / speed;
+ this->step_delay = this->step_delay;
}
/*
- Moves the motor steps_to_move steps. If the number is negative,
+ Sets the drive type
+ */
+void Stepper::setDriveType(DriveType drive_type)
+{
+ this->drive_type = drive_type;
+}
+
+void Stepper::setHold(bool hold)
+{
+ this->should_hold = hold;
+
+ // Only makes sense to do for 4-pin motors, but we still pass num_pins to writeMotorPins since a
+ // SEGFAULT would be really bad.
+ if (this->num_pins == 4) {
+ if (this->should_hold) {
+ // This will rewrite the latest pin values
+ stepMotor();
+ } else {
+ writeMotorPins(this->motor_pins, Stepper::OFF_VALUES, this->num_pins);
+ }
+ }
+}
+
+void Stepper::setDirection(bool forward)
+{
+ this->forward = forward;
+}
+
+void Stepper::setStepsToMove(unsigned int steps_to_move)
+{
+ this->steps_to_move = steps_to_move;
+}
+
+unsigned int Stepper::getStepsLeftToMove()
+{
+ return this->steps_to_move;
+}
+
+/*
+ Moves the motor steps_to_move steps. If the number is negative,
the motor moves in the reverse direction.
*/
-void Stepper::step(int steps_to_move)
-{
- int steps_left = abs(steps_to_move); // how many steps to take
-
+void Stepper::step(int steps_to_move) {
+ setStepsToMove(abs(steps_to_move));
// determine direction based on whether steps_to_mode is + or -:
- if (steps_to_move > 0) {this->direction = 1;}
- if (steps_to_move < 0) {this->direction = 0;}
-
-
- // decrement the number of steps, moving one step each time:
- while(steps_left > 0) {
+ setDirection(steps_to_move > 0);
+
+ while(this->steps_to_move > 0) {
+ stepSlice();
+ }
+
+ // TODO(smike): Since this happens right after the last step, it will effectively cancel it out.
+ // Add a delay so the motor has time to complete its last step.
+ setHold(this->should_hold);
+}
+
+void Stepper::stepSlice() {
+ stepSlice(micros());
+}
+
+void Stepper::stepSlice(const unsigned long now)
+{
+ if (this->steps_to_move == 0) {
+ // we have nothing to do
+ return;
+ }
+
+ int steps_per_rev;
+ unsigned long step_delay;
+
+ steps_per_rev = this->steps_per_rev;
+ step_delay = this->step_delay;
+ if (this->drive_type == HalfStep) {
+ // There are twice as many steps, adjust appropriately.
+ steps_per_rev *= 2;
+ step_delay /= 2UL;
+ }
+
+ unsigned long elapsed_time = now - this->last_step_time;
+
+ // micros has rolled over. Assume that it has only rolled over once.
+ if (now < this->last_step_time) {
+ // 0xFFFF is 2^32-1, the maximum value of an unsigned long
+ elapsed_time += 0xFFFFUL;
+ }
+
// move only if the appropriate delay has passed:
- if (millis() - this->last_step_time >= this->step_delay) {
- // get the timeStamp of when you stepped:
- this->last_step_time = millis();
- // increment or decrement the step number,
- // depending on direction:
- if (this->direction == 1) {
- this->step_number++;
- if (this->step_number == this->number_of_steps) {
- this->step_number = 0;
- }
- }
- else {
- if (this->step_number == 0) {
- this->step_number = this->number_of_steps;
- }
- this->step_number--;
- }
- // decrement the steps left:
- steps_left--;
- // step the motor to step number 0, 1, 2, or 3:
- stepMotor(this->step_number % 4);
- }
+ if (elapsed_time >= step_delay) {
+ // get the timeStamp of when you stepped:
+ this->last_step_time = now;
+
+ stepNow();
+
+ // decrement the steps left:
+ this->steps_to_move--;
+ }
+}
+
+void Stepper::stepNow()
+{
+ // increment or decrement the step number,
+ // depending on direction:
+ if (this->forward) {
+ this->step_number++;
+ } else {
+ this->step_number--;
}
+ this->step_number %= steps_per_rev;
+ // step the motor:
+ stepMotor();
}
/*
* Moves the motor forward or backwards.
*/
-void Stepper::stepMotor(int thisStep)
+void Stepper::stepMotor()
{
- if (this->pin_count == 2) {
- switch (thisStep) {
- case 0: /* 01 */
- digitalWrite(motor_pin_1, LOW);
- digitalWrite(motor_pin_2, HIGH);
- break;
- case 1: /* 11 */
- digitalWrite(motor_pin_1, HIGH);
- digitalWrite(motor_pin_2, HIGH);
- break;
- case 2: /* 10 */
- digitalWrite(motor_pin_1, HIGH);
- digitalWrite(motor_pin_2, LOW);
- break;
- case 3: /* 00 */
- digitalWrite(motor_pin_1, LOW);
- digitalWrite(motor_pin_2, LOW);
- break;
- }
+ // Only write out the values if the configuration is valid.
+ if (this->num_pins != 4 &&
+ !(this->num_pins == 2 && this->drive_type == FullStep)) {
+ return;
}
- if (this->pin_count == 4) {
- switch (thisStep) {
- case 0: // 1010
- digitalWrite(motor_pin_1, HIGH);
- digitalWrite(motor_pin_2, LOW);
- digitalWrite(motor_pin_3, HIGH);
- digitalWrite(motor_pin_4, LOW);
- break;
- case 1: // 0110
- digitalWrite(motor_pin_1, LOW);
- digitalWrite(motor_pin_2, HIGH);
- digitalWrite(motor_pin_3, HIGH);
- digitalWrite(motor_pin_4, LOW);
+
+ const uint8_t* step_row;
+ switch(this->drive_type) {
+ case FullStep:
+ step_row = Stepper::STEP_VALUES[(this->step_number % 4) * 2];
+ if (this->num_pins == 2) {
+ // For 2-wire configurations we take the middle two values, so we move the pointer up by
+ // one so that the first two values are really elements 1 and 2, instead of 0 and 1.
+ step_row++;
+ }
break;
- case 2: //0101
- digitalWrite(motor_pin_1, LOW);
- digitalWrite(motor_pin_2, HIGH);
- digitalWrite(motor_pin_3, LOW);
- digitalWrite(motor_pin_4, HIGH);
+ case HalfStep:
+ step_row = Stepper::STEP_VALUES[this->step_number % 8];
break;
- case 3: //1001
- digitalWrite(motor_pin_1, HIGH);
- digitalWrite(motor_pin_2, LOW);
- digitalWrite(motor_pin_3, LOW);
- digitalWrite(motor_pin_4, HIGH);
+ case Wave:
+ step_row = Stepper::STEP_VALUES[(this->step_number % 4) * 2 + 1];
break;
- }
+ default:
+ // If the this is an unknown drive type do nothing.
+ return;
+ }
+
+ writeMotorPins(this->motor_pins, step_row, this->num_pins);
+}
+
+void Stepper::writeMotorPins(uint8_t motor_pins[], const uint8_t values[], uint8_t num_pins)
+{
+ for (uint8_t i = 0; i < num_pins; i++) {
+ digitalWrite(motor_pins[i], values[i]);
}
}
/*
version() returns the version of the library:
*/
-int Stepper::version(void)
+uint8_t Stepper::version(void)
{
- return 4;
+ return 5;
}
diff --git a/libraries/Stepper/Stepper.h b/libraries/Stepper/Stepper.h
index 4094aee9077..5dff30eaf73 100644
--- a/libraries/Stepper/Stepper.h
+++ b/libraries/Stepper/Stepper.h
@@ -1,19 +1,19 @@
/*
Stepper.h - - Stepper library for Wiring/Arduino - Version 0.4
-
+
Original library (0.1) by Tom Igoe.
Two-wire modifications (0.2) by Sebastian Gassner
Combination version (0.3) by Tom Igoe and David Mellis
Bug fix for four-wire (0.4) by Tom Igoe, bug fix from Noah Shibley
- Drives a unipolar or bipolar stepper motor using 2 wires or 4 wires
+ Drives unipolar or bipolar stepper motors using 2 wires or 4 wires
When wiring multiple stepper motors to a microcontroller,
- you quickly run out of output pins, with each motor requiring 4 connections.
+ you quickly run out of output pins, with each motor requiring 4 connections.
By making use of the fact that at any time two of the four motor
coils are the inverse of the other two, the number of
- control connections can be reduced from 4 to 2.
+ control connections can be reduced from 4 to 2.
A slightly modified circuit around a Darlington transistor array or an L293 H-bridge
connects to only 2 microcontroler pins, inverts the signals received,
@@ -37,47 +37,140 @@
3 1 0
4 0 0
- The circuits can be found at
- http://www.arduino.cc/en/Tutorial/Stepper
+ For 4 wire configurations only, the motor can be driven with full-stepping (the default),
+ half-stepping, or a wave drive.
+
+ Half-stepping will halve the size of the motor's step, giving it double the resolution.
+ Remember that the amount of steps you pass to step() will be interpreted based on the current
+ value of the drive type. The sequence of control signals is as follows:
+
+ Step C0 C1 C2 C3
+ 1 1 0 1 0
+ 2 0 0 1 0
+ 3 0 1 1 0
+ 4 0 1 0 0
+ 5 0 1 0 1
+ 6 0 0 0 1
+ 7 1 0 0 1
+ 8 1 0 0 0
+
+ Wave drive mode only keeps one phase on a time. This means that the motor will use less power, but
+ will also only have half of the torque of full-stepping. The sequence of control signals is as
+ follows:
+
+ Step C0 C1 C2 C3
+ 1 0 0 1 0
+ 2 0 1 0 0
+ 3 0 0 0 1
+ 4 1 0 0 0
+
+ The circuits can be found at http://www.arduino.cc/en/Tutorial/Stepper
+ More info on the different types of drives can be found at
+ http://www.wikipedia.org/wiki/Stepper_motor#Phase_current_waveforms
*/
// ensure this library description is only included once
#ifndef Stepper_h
#define Stepper_h
+#include
+#include "utility/Vector.h"
+
+// forward declaration so it can be counted as a friend class.
+class MultiStepper;
+
// library interface description
class Stepper {
public:
+ enum DriveType { FullStep, HalfStep, Wave };
+
// constructors:
- Stepper(int number_of_steps, int motor_pin_1, int motor_pin_2);
- Stepper(int number_of_steps, int motor_pin_1, int motor_pin_2, int motor_pin_3, int motor_pin_4);
+ // The two constructors below will also add a motor as motor_id 0.
+ // steps_per_rev should be in full steps
+ Stepper() {}
+ Stepper(const Stepper& copy);
+ Stepper(int steps_per_rev, uint8_t motor_pin_1, uint8_t motor_pin_2);
+ Stepper(int steps_per_rev, uint8_t motor_pin_1, uint8_t motor_pin_2, uint8_t motor_pin_3, uint8_t motor_pin_4);
+
+ // destructor
+ ~Stepper();
+
+ Stepper& operator=(const Stepper& copy);
+
+ // speed setter methods:
+ // Set the speed of the motor, in RPM
+ void setSpeed(unsigned int speed);
+
+ // drive type setter methods:
+ // Set the drive type of the motor.
+ void setDriveType(DriveType drive_type);
+
+ // mover methods:
+ // Note that steps_to_move is an integer, with a max value of 2^15-1
+ void step(int steps_to_move);
+ // Does a step without regard for speed or the steps left to move. After this method it will be
+ // just like no steps have happened with respect to speed and number of steps left.
+ void stepNow();
- // speed setter method:
- void setSpeed(long whatSpeed);
+ // Sets whether the steppers should hold their position after they finish stepping.
+ // This can only be done for 4-pin motor configurations, and will be ignored otherwise.
+ // This will only take effect after the next step() call finishes. Call step(0) if you want to
+ // have it take immediately.
+ void setHold(bool hold);
- // mover method:
- void step(int number_of_steps);
+ void setDirection(bool forward);
- int version(void);
+ // sets a limit on how many steps should be moved
+ void setStepsToMove(unsigned int steps_to_move);
+
+ // returns how many steps are left to move.
+ // This is scaled based on the drive type (1 FullStep = 2 HalfSteps)
+ unsigned int getStepsLeftToMove();
+
+ void stepSlice();
+
+ uint8_t version(void);
+
+ friend class MultiStepper;
+
+ protected:
+ // Helper method for stepSlice(). Takes the current time in microseconds.
+ // It is useful when needing to move multiple motors simultaneously. Having each motor calculate
+ // can make them out of sync, and slow since micros() take a long time to evaluate.
+ void stepSlice(const unsigned long now);
private:
- void stepMotor(int this_step);
-
- int direction; // Direction of rotation
- int speed; // Speed in RPMs
- unsigned long step_delay; // delay between steps, in ms, based on speed
- int number_of_steps; // total number of steps this motor can take
- int pin_count; // whether you're driving the motor with 2 or 4 pins
- int step_number; // which step the motor is on
-
- // motor pin numbers:
- int motor_pin_1;
- int motor_pin_2;
- int motor_pin_3;
- int motor_pin_4;
-
- long last_step_time; // time stamp in ms of when the last step was taken
+ // initialization
+ void init(int steps_per_rev, uint8_t motor_pins[], uint8_t num_pins);
+
+ // moves the motor specified one step.
+ void stepMotor();
+
+ // writes the given values to the motor pins.
+ void writeMotorPins(uint8_t motor_pins[], const uint8_t values[], uint8_t num_pins);
+
+ // Only even rows are used for full-stepping.
+ // Only odd rows are used for wave-stepping.
+ // All rows are used for half-stepping.
+ static const uint8_t STEP_VALUES[8][4];
+
+ // Pin values that turn off current to a motor so that it does not hold its position.
+ // This is only possible for 4-pin configurations
+ static const uint8_t OFF_VALUES[4];
+
+ uint8_t* motor_pins; // motor pin numbers
+ uint8_t num_pins;
+
+ Stepper::DriveType drive_type; // What kind of stepping to use. Defaults to full.
+ unsigned long step_delay; // delay between steps, in micros, based on speed
+ int steps_per_rev; // total number of steps this motor can take
+ bool forward; // whether to move forward or backward
+
+ unsigned int step_number; // which step the motor is on
+ unsigned int steps_to_move; // the number of steps left to take
+ unsigned long last_step_time; // time stamp in micros of when the last step was taken
+
+ bool should_hold; // whether to hold the motor position when not stepping.
};
#endif
-
diff --git a/libraries/Stepper/keywords.txt b/libraries/Stepper/keywords.txt
index 19a0fadf2bd..1f98a38c724 100644
--- a/libraries/Stepper/keywords.txt
+++ b/libraries/Stepper/keywords.txt
@@ -6,23 +6,41 @@
# Datatypes (KEYWORD1)
#######################################
-Stepper KEYWORD1
+MultiStepper KEYWORD1
+Stepper KEYWORD1
#######################################
# Methods and Functions (KEYWORD2)
#######################################
-step KEYWORD2
-setSpeed KEYWORD2
-version KEYWORD2
+
+# Common betwen Stepper and MultiStepper
+setDriveType KEYWORD2
+setDirection KEYWORD2
+setStepsToMove KEYWORD2
+setHold KEYWORD2
+setSpeed KEYWORD2
+step KEYWORD2
+stepSlice KEYWORD2
+
+# Unique to Stepper
+getStepsLeftToMove KEYWORD2
+stepNow KEYWORD2
+version KEYWORD2
+
+# Unique to MultiStepper
+getStepper KEYWORD2
+numMotors KEYWORD2
+registerStepper KEYWORD2
######################################
# Instances (KEYWORD2)
#######################################
-direction KEYWORD2
-speed KEYWORD2
-
#######################################
# Constants (LITERAL1)
#######################################
+
+FullStep LITERAL1
+HalfStep LITERAL1
+Wave LITERAL1
\ No newline at end of file
diff --git a/libraries/Stepper/utility/Vector.h b/libraries/Stepper/utility/Vector.h
new file mode 100644
index 00000000000..3b10d1529be
--- /dev/null
+++ b/libraries/Stepper/utility/Vector.h
@@ -0,0 +1,73 @@
+// Adapted from a post on the Arduino Forums by Gabb:
+// http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1289151491
+
+#ifndef VECTOR_H
+#define VECTOR_H
+
+#include
+#include
+
+// Minimal class to replace std::vector
+template
+class Vector {
+ size_t d_size; // Stores no. of actually stored objects
+ size_t d_capacity; // Stores allocated capacity
+ Data *d_data; // Stores data
+public:
+ // Default constructor
+ Vector() : d_size(0), d_capacity(0), d_data(0) {};
+ // Copy constuctor
+ Vector(Vector const &other) : d_size(other.d_size), d_capacity(other.d_capacity), d_data(0) {
+ d_data = (Data *) malloc(d_capacity * sizeof(Data));
+ memcpy(d_data, other.d_data, d_size * sizeof(Data));
+ };
+
+ // Destructor
+ ~Vector() {
+ free(d_data);
+ };
+
+ // Needed for memory management
+ Vector &operator=(Vector const &other) {
+ free(d_data);
+ d_size = other.d_size;
+ d_capacity = other.d_capacity;
+ d_data = (Data *) malloc(d_capacity * sizeof(Data));
+ memcpy(d_data, other.d_data, d_size * sizeof(Data));
+ return *this;
+ };
+
+ // Const getter
+ Data const &operator[](size_t idx) const {
+ return d_data[idx];
+ };
+ // Changeable getter
+ Data &operator[](size_t idx) {
+ return d_data[idx];
+ };
+
+ // Adds new value. If needed, allocates more space
+ void push_back(Data const &x) {
+ if (d_capacity == d_size) {
+ resize();
+ }
+ d_data[d_size++] = x;
+ };
+
+ // Size getter
+ size_t size() const {
+ return d_size;
+ };
+
+private:
+ // Allocates double the old space
+ void resize() {
+ d_capacity = d_capacity ? d_capacity * 2 : 1;
+ Data *newdata = (Data *) malloc(d_capacity * sizeof(Data));
+ memcpy(newdata, d_data, d_size * sizeof(Data));
+ free(d_data);
+ d_data = newdata;
+ };
+};
+
+#endif
diff --git a/libraries/Stepper3/Stepper3.cpp b/libraries/Stepper3/Stepper3.cpp
new file mode 100644
index 00000000000..c6b26ec2781
--- /dev/null
+++ b/libraries/Stepper3/Stepper3.cpp
@@ -0,0 +1,402 @@
+/*
+ Stepper.cpp - - Stepper library for Wiring/Arduino - Version 0.4
+
+ Original library (0.1) by Tom Igoe.
+ Two-wire modifications (0.2) by Sebastian Gassner
+ Combination version (0.3) by Tom Igoe and David Mellis
+ Bug fix for four-wire (0.4) by Tom Igoe, bug fix from Noah Shibley
+
+ Drives unipolar or bipolar stepper motors using 2 wires or 4 wires
+
+ You can drive multiple motors simultaneously by calling registerMotor() multiple times on the same
+ instance of Stepper. You can then either move one motor at a time, or all of them in unison using
+ void step(int[] steps) function.
+
+ When wiring multiple stepper motors to a microcontroller,
+ you quickly run out of output pins, with each motor requiring 4 connections.
+
+ By making use of the fact that at any time two of the four motor
+ coils are the inverse of the other two, the number of
+ control connections can be reduced from 4 to 2.
+
+ A slightly modified circuit around a Darlington transistor array or an L293 H-bridge
+ connects to only 2 microcontroler pins, inverts the signals received,
+ and delivers the 4 (2 plus 2 inverted ones) output signals required
+ for driving a stepper motor.
+
+ The sequence of control signals for 4 control wires is as follows:
+
+ Step C0 C1 C2 C3
+ 1 1 0 1 0
+ 2 0 1 1 0
+ 3 0 1 0 1
+ 4 1 0 0 1
+
+ The sequence of controls signals for 2 control wires is as follows
+ (columns C1 and C2 from above):
+
+ Step C0 C1
+ 1 0 1
+ 2 1 1
+ 3 1 0
+ 4 0 0
+
+ For 4 wire configurations only, the motor can be driven with full-stepping (the default),
+ half-stepping, or a wave drive.
+
+ Half-stepping will halve the size of the motor's step, giving it double the resolution.
+ Remember that the amount of steps you pass to step() will be interpreted based on the current
+ value of the drive type. The sequence of control signals is as follows:
+
+ Step C0 C1 C2 C3
+ 1 1 0 1 0
+ 2 0 0 1 0
+ 3 0 1 1 0
+ 4 0 1 0 0
+ 5 0 1 0 1
+ 6 0 0 0 1
+ 7 1 0 0 1
+ 8 1 0 0 0
+
+ Wave drive mode only keeps one phase on a time. This means that the motor will use less power, but
+ will also only have half of the torque of full-stepping. The sequence of control signals is as
+ follows:
+
+ Step C0 C1 C2 C3
+ 1 0 0 1 0
+ 2 0 1 0 0
+ 3 0 0 0 1
+ 4 1 0 0 0
+
+ The circuits can be found at http://www.arduino.cc/en/Tutorial/Stepper
+ More info on the different types of drives can be found at
+ http://www.wikipedia.org/wiki/Stepper_motor#Phase_current_waveforms
+*/
+
+#include
+#include
+
+#include
+#include "utility/vector.h"
+
+#include "Stepper3.h"
+
+// Only even rows are used for full-stepping.
+// Only odd rows are used for wave-stepping.
+// All rows are used for half-stepping.
+const uint8_t Stepper::STEP_VALUES[8][4] = {
+ {HIGH, LOW, HIGH, LOW}, // not used for wave-stepping
+ {LOW, LOW, HIGH, LOW}, // not used for full-stepping
+ {LOW, HIGH, HIGH, LOW}, // not used for wave-stepping
+ {LOW, HIGH, LOW, LOW}, // not used for full-stepping
+ {LOW, HIGH, LOW, HIGH}, // not used for wave-stepping
+ {LOW, LOW, LOW, HIGH}, // not used for full-stepping
+ {HIGH, LOW, LOW, HIGH}, // not used for wave-stepping
+ {HIGH, LOW, LOW, LOW} // not used for full-stepping
+};
+
+// Pin values that turn off current to a motor so that it does not hold its position.
+// This is only possible for 4-pin configurations
+const uint8_t Stepper::OFF_VALUES[] = { LOW, LOW, LOW, LOW };
+
+Stepper::Stepper() : should_halt(false), callback(NULL) {}
+
+/*
+ * two-wire constructor.
+ * Sets which wires should control the motor.
+ */
+Stepper::Stepper(int steps_per_rev, uint8_t motor_pin_1, uint8_t motor_pin_2)
+ : should_halt(false), callback(NULL)
+{
+ registerMotor(steps_per_rev, motor_pin_1, motor_pin_2);
+}
+
+/*
+ * constructor for four-pin version
+ * Sets which wires should control the motor.
+ */
+Stepper::Stepper(int steps_per_rev,
+ uint8_t motor_pin_1, uint8_t motor_pin_2, uint8_t motor_pin_3, uint8_t motor_pin_4)
+ : should_halt(false), callback(NULL)
+{
+ registerMotor(steps_per_rev, motor_pin_1, motor_pin_2, motor_pin_3, motor_pin_4);
+}
+
+Stepper::~Stepper()
+{
+ uint8_t num_motors = numMotors();
+ for(uint8_t i = 0; i < num_motors; i++) {
+ free(motor_infos[i]->motor_pins);
+ delete motor_infos[i];
+ }
+}
+
+uint8_t Stepper::registerMotor(int steps_per_rev, uint8_t motor_pin_1, uint8_t motor_pin_2)
+{
+ uint8_t motor_pins[] = { motor_pin_1, motor_pin_2 };
+ return registerMotor(steps_per_rev, motor_pins, 2);
+}
+
+uint8_t Stepper::registerMotor(int steps_per_rev, uint8_t motor_pin_1, uint8_t motor_pin_2, uint8_t motor_pin_3, uint8_t motor_pin_4)
+{
+ uint8_t motor_pins[] = { motor_pin_1, motor_pin_2, motor_pin_3, motor_pin_4 };
+ return registerMotor(steps_per_rev, motor_pins, 4);
+}
+
+uint8_t Stepper::registerMotor(int steps_per_rev, uint8_t motor_pins[], uint8_t num_pins)
+{
+ MotorInfo* motor_info = new MotorInfo;
+ motor_info->drive_type = FullStep;
+ motor_info->last_step_time = 0UL;
+
+ motor_info->motor_pins = (uint8_t*)malloc(num_pins * sizeof(uint8_t));
+ for (uint8_t i = 0; i < num_pins; i++) {
+ motor_info->motor_pins[i] = motor_pins[i];
+ }
+
+ motor_info->num_pins = num_pins;
+ motor_info->step_delay = 0UL;
+ motor_info->step_number = 0;
+ motor_info->steps_per_rev = steps_per_rev;
+ motor_info->should_hold = true;
+
+ setupMotorPins(motor_pins, num_pins);
+
+ this->motor_infos.push_back(motor_info);
+ return motor_infos.size() - 1;
+}
+
+void Stepper::setupMotorPins(uint8_t motor_pins[], uint8_t num_pins) {
+ // Setup the pins on the microcontroller.
+ for (uint8_t i = 0; i < num_pins; i++) {
+ pinMode(motor_pins[i], OUTPUT);
+ }
+
+ // Write LOW to each pin initially so the motor is not driven and current is not wasted.
+ // This only really makes sense for a 4-pin motor, but it's still better than letting the pins of
+ // a 2-pin motor have random values.
+ writeMotorPins(motor_pins, Stepper::OFF_VALUES, num_pins);
+}
+
+/*
+ Sets the speed in revs per minute
+*/
+void Stepper::setSpeed(int speed)
+{
+ uint8_t num_motors = numMotors();
+ for (uint8_t i = 0; i < num_motors; i++) {
+ setSpeed(i, speed);
+ }
+}
+
+void Stepper::setSpeed(uint8_t motor_id, int speed)
+{
+ MotorInfo* motor_info = this->motor_infos[motor_id];
+ motor_info->step_delay = 60UL * 1000000UL / motor_info->steps_per_rev / speed;
+ motor_info->step_delay = abs(motor_info->step_delay);
+}
+
+/*
+ Sets the drive type
+ */
+void Stepper::setDriveType(DriveType drive_type)
+{
+ uint8_t num_motors = numMotors();
+ for (uint8_t i = 0; i < num_motors; i++) {
+ setDriveType(i, drive_type);
+ }
+}
+
+void Stepper::setDriveType(uint8_t motor_id, DriveType drive_type)
+{
+ this->motor_infos[motor_id]->drive_type = drive_type;
+}
+
+void Stepper::setHold(bool hold)
+{
+ uint8_t num_motors = numMotors();
+ for (uint8_t i = 0; i < num_motors; i++) {
+ setHold(i, hold);
+ }
+}
+
+void Stepper::setHold(uint8_t motor_id, bool hold)
+{
+ this->motor_infos[motor_id]->should_hold = hold;
+}
+
+/*
+ Moves the motor steps_to_move steps. If the number is negative,
+ the motor moves in the reverse direction.
+ */
+void Stepper::step(int steps_to_move) {
+ uint8_t num_motors = numMotors();
+ int steps_to_move_array[num_motors];
+ for (uint8_t i = 0; i < num_motors; i++) {
+ steps_to_move_array[i] = steps_to_move;
+ }
+ step(steps_to_move_array);
+}
+
+void Stepper::step(uint8_t motor_id, int steps_to_move) {
+ uint8_t num_motors = numMotors();
+ int steps_to_move_array[num_motors];
+ for (uint8_t i = 0; i < num_motors; i++) {
+ steps_to_move_array[i] = i == motor_id ? steps_to_move : 0;
+ }
+ step(steps_to_move_array);
+}
+
+void Stepper::step(int steps_to_move[])
+{
+ uint8_t num_motors = numMotors();
+
+ unsigned int steps_left[num_motors];
+ bool direction_positive[num_motors];
+ int steps_per_rev[num_motors];
+ unsigned long step_delay[num_motors];
+ for (uint8_t i = 0; i < num_motors; i++) {
+ const MotorInfo* motor_info = this->motor_infos[i];
+ steps_left[i] = abs(steps_to_move[i]); // how many steps to take
+
+ // determine direction based on whether steps_to_mode is + or -:
+ direction_positive[i] = steps_to_move[i] > 0;
+
+ steps_per_rev[i] = motor_info->steps_per_rev;
+ step_delay[i] = motor_info->step_delay;
+ if (motor_info->drive_type == HalfStep) {
+ // There are twice as many steps, adjust appropriately.
+ steps_per_rev[i] *= 2;
+ step_delay[i] /= 2UL;
+ }
+ }
+
+ while(!this->should_halt) {
+ const unsigned long now = micros();
+ bool any_steps_left = false;
+ // look at each motor to see if it should be moved now.
+ for (uint8_t i = 0; i < num_motors; i++) {
+ MotorInfo* motor_info = this->motor_infos[i];
+ if (steps_left[i] > 0) {
+ any_steps_left = true;
+
+ unsigned long elapsed_time = now - motor_info->last_step_time;
+ // micros has rolled over. Assume that it has only rolled over once.
+ if (now < motor_info->last_step_time) {
+ // 0xFFFF is 2^32-1, the maximum value of an unsigned long
+ elapsed_time += 0xFFFFUL;
+ }
+
+ // move only if the appropriate delay has passed:
+ if (elapsed_time >= step_delay[i]) {
+ // get the timeStamp of when you stepped:
+ motor_info->last_step_time = now;
+ // increment or decrement the step number,
+ // depending on direction:
+ if (direction_positive[i]) {
+ motor_info->step_number++;
+ } else {
+ motor_info->step_number--;
+ }
+ motor_info->step_number %= steps_per_rev[i];
+ // decrement the steps left:
+ steps_left[i]--;
+ // step the motor:
+ stepMotor(i);
+ }
+ }
+ }
+
+ // if there are no steps left for any motors, we're done!
+ if (!any_steps_left) {
+ break;
+ }
+
+ // if it is set, call the callback.
+ if (this->callback != NULL) {
+ this->callback();
+ }
+ }
+
+ // reset halt signal
+ this->should_halt = false;
+
+ // TODO(smike): Since this happens right after the last step, it will effectively cancel it out.
+ // Add a delay so the motor has time to complete its last step.
+ for (uint8_t i = 0; i < num_motors; i++) {
+ MotorInfo* motor_info = this->motor_infos[i];
+ // Only makes sense to do for 4-pin motors, but we still pass num_pins to writeMotorPins since a
+ // SEGFAULT would be really bad.
+ if (!motor_info->should_hold && motor_info->num_pins == 4) {
+ writeMotorPins(motor_info->motor_pins, Stepper::OFF_VALUES, motor_info->num_pins);
+ }
+ }
+}
+
+/*
+ * Moves the motor forward or backwards.
+ */
+void Stepper::stepMotor(uint8_t motor_id)
+{
+ const MotorInfo* motor_info = this->motor_infos[motor_id];
+ uint8_t* motor_pins = motor_info->motor_pins;
+
+ // Only write out the values if the configuration is valid.
+ if (motor_info->num_pins != 4 &&
+ motor_info->num_pins != 2 && motor_info->drive_type != FullStep) {
+ return;
+ }
+
+ const uint8_t* step_row;
+ switch(motor_info->drive_type) {
+ case FullStep:
+ step_row = Stepper::STEP_VALUES[(motor_info->step_number % 4) * 2];
+ if (motor_info->num_pins == 2) {
+ // For 2-wire configurations we take the middle two values, so we move the pointer up by
+ // one so that the first two values are really elements 1 and 2, instead of 0 and 1.
+ step_row++;
+ }
+ break;
+ case HalfStep:
+ step_row = Stepper::STEP_VALUES[motor_info->step_number % 8];
+ break;
+ case Wave:
+ step_row = Stepper::STEP_VALUES[(motor_info->step_number % 4) * 2 + 1];
+ break;
+ default:
+ // If the this is an unknown drive type do nothing.
+ return;
+ }
+
+ writeMotorPins(motor_pins, step_row, motor_info->num_pins);
+}
+
+void Stepper::writeMotorPins(uint8_t motor_pins[], const uint8_t values[], uint8_t num_pins)
+{
+ for (uint8_t i = 0; i < num_pins; i++) {
+ digitalWrite(motor_pins[i], values[i]);
+ }
+}
+
+void Stepper::halt()
+{
+ this->should_halt = true;
+}
+
+void Stepper::setCallback(void (*callback)())
+{
+ this->callback = callback;
+}
+
+uint8_t Stepper::numMotors()
+{
+ return this->motor_infos.size();
+}
+
+/*
+ version() returns the version of the library:
+*/
+uint8_t Stepper::version(void)
+{
+ return 5;
+}
diff --git a/libraries/Stepper3/Stepper3.h b/libraries/Stepper3/Stepper3.h
new file mode 100644
index 00000000000..b0c0cf3ed01
--- /dev/null
+++ b/libraries/Stepper3/Stepper3.h
@@ -0,0 +1,187 @@
+/*
+ Stepper.h - - Stepper library for Wiring/Arduino - Version 0.4
+
+ Original library (0.1) by Tom Igoe.
+ Two-wire modifications (0.2) by Sebastian Gassner
+ Combination version (0.3) by Tom Igoe and David Mellis
+ Bug fix for four-wire (0.4) by Tom Igoe, bug fix from Noah Shibley
+
+ Drives unipolar or bipolar stepper motors using 2 wires or 4 wires
+
+ You can drive multiple motors simultaneously by calling registerMotor() multiple times on the same
+ instance of Stepper. You can then either move one motor at a time, or all of them in unison using
+ void step(int[] steps) function.
+
+ When wiring multiple stepper motors to a microcontroller,
+ you quickly run out of output pins, with each motor requiring 4 connections.
+
+ By making use of the fact that at any time two of the four motor
+ coils are the inverse of the other two, the number of
+ control connections can be reduced from 4 to 2.
+
+ A slightly modified circuit around a Darlington transistor array or an L293 H-bridge
+ connects to only 2 microcontroler pins, inverts the signals received,
+ and delivers the 4 (2 plus 2 inverted ones) output signals required
+ for driving a stepper motor.
+
+ The sequence of control signals for 4 control wires is as follows:
+
+ Step C0 C1 C2 C3
+ 1 1 0 1 0
+ 2 0 1 1 0
+ 3 0 1 0 1
+ 4 1 0 0 1
+
+ The sequence of controls signals for 2 control wires is as follows
+ (columns C1 and C2 from above):
+
+ Step C0 C1
+ 1 0 1
+ 2 1 1
+ 3 1 0
+ 4 0 0
+
+ For 4 wire configurations only, the motor can be driven with full-stepping (the default),
+ half-stepping, or a wave drive.
+
+ Half-stepping will halve the size of the motor's step, giving it double the resolution.
+ Remember that the amount of steps you pass to step() will be interpreted based on the current
+ value of the drive type. The sequence of control signals is as follows:
+
+ Step C0 C1 C2 C3
+ 1 1 0 1 0
+ 2 0 0 1 0
+ 3 0 1 1 0
+ 4 0 1 0 0
+ 5 0 1 0 1
+ 6 0 0 0 1
+ 7 1 0 0 1
+ 8 1 0 0 0
+
+ Wave drive mode only keeps one phase on a time. This means that the motor will use less power, but
+ will also only have half of the torque of full-stepping. The sequence of control signals is as
+ follows:
+
+ Step C0 C1 C2 C3
+ 1 0 0 1 0
+ 2 0 1 0 0
+ 3 0 0 0 1
+ 4 1 0 0 0
+
+ The circuits can be found at http://www.arduino.cc/en/Tutorial/Stepper
+ More info on the different types of drives can be found at
+ http://www.wikipedia.org/wiki/Stepper_motor#Phase_current_waveforms
+*/
+
+// ensure this library description is only included once
+#ifndef Stepper_h
+#define Stepper_h
+
+#include
+#include "utility/vector.h"
+
+// library interface description
+class Stepper {
+ public:
+ enum DriveType { FullStep, HalfStep, Wave };
+
+ // constructors:
+ // Empty constructor
+ Stepper();
+ // The two constructors below will also add a motor as motor_id 0.
+ // steps_per_rev should be in full steps
+ Stepper(int steps_per_rev, uint8_t motor_pin_1, uint8_t motor_pin_2);
+ Stepper(int steps_per_rev, uint8_t motor_pin_1, uint8_t motor_pin_2, uint8_t motor_pin_3, uint8_t motor_pin_4);
+
+ // destructor
+ ~Stepper();
+
+ // Registers an extra motor. The return value is the motor's id, and should be used to
+ // reference it in the future.
+ // steps_per_rev should be in full steps
+ uint8_t registerMotor(int steps_per_rev, uint8_t motor_pin_1, uint8_t motor_pin_2);
+ uint8_t registerMotor(int steps_per_rev, uint8_t motor_pin_1, uint8_t motor_pin_2, uint8_t motor_pin_3, uint8_t motor_pin_4);
+
+ // speed setter methods:
+ // Set the speed for all motors. in RPM
+ void setSpeed(int speed);
+ // Set the speed for a specific motor, in RPM
+ void setSpeed(uint8_t motor_id, int speed);
+
+ // drive type setter methods:
+ // Set the drive type for all motors.
+ void setDriveType(DriveType drive_type);
+ // Set the drive type for a specific motor
+ void setDriveType(uint8_t motor_id, DriveType drive_type);
+
+ // mover methods:
+ // Move all motors the number_of_steps
+ // Note that steps_to_move is an integer, with a max value of 2^15-1
+ void step(int steps_to_move);
+ // Move only the motor with motor_id number_of_steps
+ void step(uint8_t motor_id, int steps_to_move);
+ // Move all of the motors simultaneously. Each element in the number_of_steps array corresponds
+ // to the number of steps the motor with motor_id being the index of that element should be
+ // moved. steps_to_move must have exactly numMotors() elements. If you dont want some motors
+ // to move, set those values to 0.
+ void step(int steps_to_move[]);
+
+ // Aborts the step() loop once.
+ void halt();
+
+ // Sets whether the steppers should hold their position after they finish stepping.
+ // This can only be done for 4-pin motor configurations, and will be ignored otherwise.
+ // This will only take effect after the next step() call finishes. Call step(0) if you want to
+ // have it take immediately.
+ void setHold(bool hold);
+ void setHold(uint8_t motor_id, bool hold);
+
+ // Sets a callback to call after each iteration of the step() loop. Set to NULL to disable.
+ // Remember that the callback should execute quickly and not block. The longer the callback
+ // takes the slower steps can be taken.
+ void setCallback(void (*callback)());
+
+ // Returns the number of motors registered.
+ uint8_t numMotors(void);
+
+ uint8_t version(void);
+
+ private:
+ struct MotorInfo {
+ uint8_t* motor_pins; // motor pin numbers
+ uint8_t num_pins;
+
+ Stepper::DriveType drive_type; // What kind of stepping to use. Defaults to full.
+ unsigned long step_delay; // delay between steps, in micros, based on speed
+ int steps_per_rev; // total number of steps this motor can take
+
+ unsigned int step_number; // which step the motor is on
+ unsigned long last_step_time; // time stamp in micros of when the last step was taken
+
+ bool should_hold; // whether to hold the motor position when not stepping.
+ };
+
+ uint8_t registerMotor(int steps_per_rev, uint8_t motor_pins[], uint8_t num_pins);
+ void setupMotorPins(uint8_t motor_pins[], uint8_t num_pins);
+
+ // moves the motor specified one step.
+ void stepMotor(uint8_t motor_id);
+
+ // writes the given values to the motor pins.
+ void writeMotorPins(uint8_t motor_pins[], const uint8_t values[], uint8_t num_pins);
+
+ // Only even rows are used for full-stepping.
+ // Only odd rows are used for wave-stepping.
+ // All rows are used for half-stepping.
+ static const uint8_t STEP_VALUES[8][4];
+
+ // Pin values that turn off current to a motor so that it does not hold its position.
+ // This is only possible for 4-pin configurations
+ static const uint8_t OFF_VALUES[4];
+
+ Vector motor_infos;
+ bool should_halt;
+ void (*callback)();
+};
+
+#endif
diff --git a/libraries/Stepper3/examples/MotorKnob/MotorKnob.ino b/libraries/Stepper3/examples/MotorKnob/MotorKnob.ino
new file mode 100644
index 00000000000..d428186342d
--- /dev/null
+++ b/libraries/Stepper3/examples/MotorKnob/MotorKnob.ino
@@ -0,0 +1,41 @@
+/*
+ * MotorKnob
+ *
+ * A stepper motor follows the turns of a potentiometer
+ * (or other sensor) on analog input 0.
+ *
+ * http://www.arduino.cc/en/Reference/Stepper
+ * This example code is in the public domain.
+ */
+
+#include
+
+// change this to the number of steps on your motor
+#define STEPS 100
+
+// create an instance of the stepper class, specifying
+// the number of steps of the motor and the pins it's
+// attached to
+Stepper stepper(STEPS, 8, 9, 10, 11);
+
+// the previous reading from the analog input
+int previous = 0;
+
+void setup()
+{
+ // set the speed of the motor to 30 RPMs
+ stepper.setSpeed(30);
+}
+
+void loop()
+{
+ // get the sensor value
+ int val = analogRead(0);
+
+ // move a number of steps equal to the change in the
+ // sensor reading
+ stepper.step(val - previous);
+
+ // remember the previous value of the sensor
+ previous = val;
+}
\ No newline at end of file
diff --git a/libraries/Stepper3/examples/stepper_oneRevolution/stepper_oneRevolution.ino b/libraries/Stepper3/examples/stepper_oneRevolution/stepper_oneRevolution.ino
new file mode 100644
index 00000000000..2dbb57d7af3
--- /dev/null
+++ b/libraries/Stepper3/examples/stepper_oneRevolution/stepper_oneRevolution.ino
@@ -0,0 +1,44 @@
+
+/*
+ Stepper Motor Control - one revolution
+
+ This program drives a unipolar or bipolar stepper motor.
+ The motor is attached to digital pins 8 - 11 of the Arduino.
+
+ The motor should revolve one revolution in one direction, then
+ one revolution in the other direction.
+
+
+ Created 11 Mar. 2007
+ Modified 30 Nov. 2009
+ by Tom Igoe
+
+ */
+
+#include
+
+const int stepsPerRevolution = 200; // change this to fit the number of steps per revolution
+ // for your motor
+
+// initialize the stepper library on pins 8 through 11:
+Stepper myStepper(stepsPerRevolution, 8,9,10,11);
+
+void setup() {
+ // set the speed at 60 rpm:
+ myStepper.setSpeed(60);
+ // initialize the serial port:
+ Serial.begin(9600);
+}
+
+void loop() {
+ // step one revolution in one direction:
+ Serial.println("clockwise");
+ myStepper.step(stepsPerRevolution);
+ delay(500);
+
+ // step one revolution in the other direction:
+ Serial.println("counterclockwise");
+ myStepper.step(-stepsPerRevolution);
+ delay(500);
+}
+
diff --git a/libraries/Stepper3/examples/stepper_oneStepAtATime/stepper_oneStepAtATime.ino b/libraries/Stepper3/examples/stepper_oneStepAtATime/stepper_oneStepAtATime.ino
new file mode 100644
index 00000000000..36d32991dc9
--- /dev/null
+++ b/libraries/Stepper3/examples/stepper_oneStepAtATime/stepper_oneStepAtATime.ino
@@ -0,0 +1,44 @@
+
+/*
+ Stepper Motor Control - one step at a time
+
+ This program drives a unipolar or bipolar stepper motor.
+ The motor is attached to digital pins 8 - 11 of the Arduino.
+
+ The motor will step one step at a time, very slowly. You can use this to
+ test that you've got the four wires of your stepper wired to the correct
+ pins. If wired correctly, all steps should be in the same direction.
+
+ Use this also to count the number of steps per revolution of your motor,
+ if you don't know it. Then plug that number into the oneRevolution
+ example to see if you got it right.
+
+ Created 30 Nov. 2009
+ by Tom Igoe
+
+ */
+
+#include
+
+const int stepsPerRevolution = 200; // change this to fit the number of steps per revolution
+ // for your motor
+
+// initialize the stepper library on pins 8 through 11:
+Stepper myStepper(stepsPerRevolution, 8,9,10,11);
+
+int stepCount = 0; // number of steps the motor has taken
+
+void setup() {
+ // initialize the serial port:
+ Serial.begin(9600);
+}
+
+void loop() {
+ // step one step:
+ myStepper.step(1);
+ Serial.print("steps:" );
+ Serial.println(stepCount);
+ stepCount++;
+ delay(500);
+}
+
diff --git a/libraries/Stepper3/examples/stepper_speedControl/stepper_speedControl.ino b/libraries/Stepper3/examples/stepper_speedControl/stepper_speedControl.ino
new file mode 100644
index 00000000000..dbd0f7f02a8
--- /dev/null
+++ b/libraries/Stepper3/examples/stepper_speedControl/stepper_speedControl.ino
@@ -0,0 +1,49 @@
+
+/*
+ Stepper Motor Control - speed control
+
+ This program drives a unipolar or bipolar stepper motor.
+ The motor is attached to digital pins 8 - 11 of the Arduino.
+ A potentiometer is connected to analog input 0.
+
+ The motor will rotate in a clockwise direction. The higher the potentiometer value,
+ the faster the motor speed. Because setSpeed() sets the delay between steps,
+ you may notice the motor is less responsive to changes in the sensor value at
+ low speeds.
+
+ Created 30 Nov. 2009
+ Modified 28 Oct 2010
+ by Tom Igoe
+
+ */
+
+#include
+
+const int stepsPerRevolution = 200; // change this to fit the number of steps per revolution
+// for your motor
+
+
+// initialize the stepper library on pins 8 through 11:
+Stepper myStepper(stepsPerRevolution, 8,9,10,11);
+
+int stepCount = 0; // number of steps the motor has taken
+
+void setup() {
+ // initialize the serial port:
+ Serial.begin(9600);
+}
+
+void loop() {
+ // read the sensor value:
+ int sensorReading = analogRead(A0);
+ // map it to a range from 0 to 100:
+ int motorSpeed = map(sensorReading, 0, 1023, 0, 100);
+ // set the motor speed:
+ if (motorSpeed > 0) {
+ myStepper.setSpeed(motorSpeed);
+ // step 1/100 of a revolution:
+ myStepper.step(stepsPerRevolution/100);
+ }
+}
+
+
diff --git a/libraries/Stepper3/keywords.txt b/libraries/Stepper3/keywords.txt
new file mode 100644
index 00000000000..6ffdb733643
--- /dev/null
+++ b/libraries/Stepper3/keywords.txt
@@ -0,0 +1,34 @@
+#######################################
+# Syntax Coloring Map For Test
+#######################################
+
+#######################################
+# Datatypes (KEYWORD1)
+#######################################
+
+Stepper KEYWORD1
+
+#######################################
+# Methods and Functions (KEYWORD2)
+#######################################
+
+registerMotor KEYWORD2
+halt KEYWORD2
+numMotors KEYWORD2
+setCallback KEYWORD2
+setDriveType KEYWORD2
+setSpeed KEYWORD2
+step KEYWORD2
+version KEYWORD2
+
+######################################
+# Instances (KEYWORD2)
+#######################################
+
+#######################################
+# Constants (LITERAL1)
+#######################################
+
+FullStep LITERAL1
+HalfStep LITERAL1
+Wave LITERAL1
\ No newline at end of file
diff --git a/libraries/Stepper3/utility/Vector.h b/libraries/Stepper3/utility/Vector.h
new file mode 100644
index 00000000000..3b10d1529be
--- /dev/null
+++ b/libraries/Stepper3/utility/Vector.h
@@ -0,0 +1,73 @@
+// Adapted from a post on the Arduino Forums by Gabb:
+// http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1289151491
+
+#ifndef VECTOR_H
+#define VECTOR_H
+
+#include
+#include
+
+// Minimal class to replace std::vector
+template
+class Vector {
+ size_t d_size; // Stores no. of actually stored objects
+ size_t d_capacity; // Stores allocated capacity
+ Data *d_data; // Stores data
+public:
+ // Default constructor
+ Vector() : d_size(0), d_capacity(0), d_data(0) {};
+ // Copy constuctor
+ Vector(Vector const &other) : d_size(other.d_size), d_capacity(other.d_capacity), d_data(0) {
+ d_data = (Data *) malloc(d_capacity * sizeof(Data));
+ memcpy(d_data, other.d_data, d_size * sizeof(Data));
+ };
+
+ // Destructor
+ ~Vector() {
+ free(d_data);
+ };
+
+ // Needed for memory management
+ Vector &operator=(Vector const &other) {
+ free(d_data);
+ d_size = other.d_size;
+ d_capacity = other.d_capacity;
+ d_data = (Data *) malloc(d_capacity * sizeof(Data));
+ memcpy(d_data, other.d_data, d_size * sizeof(Data));
+ return *this;
+ };
+
+ // Const getter
+ Data const &operator[](size_t idx) const {
+ return d_data[idx];
+ };
+ // Changeable getter
+ Data &operator[](size_t idx) {
+ return d_data[idx];
+ };
+
+ // Adds new value. If needed, allocates more space
+ void push_back(Data const &x) {
+ if (d_capacity == d_size) {
+ resize();
+ }
+ d_data[d_size++] = x;
+ };
+
+ // Size getter
+ size_t size() const {
+ return d_size;
+ };
+
+private:
+ // Allocates double the old space
+ void resize() {
+ d_capacity = d_capacity ? d_capacity * 2 : 1;
+ Data *newdata = (Data *) malloc(d_capacity * sizeof(Data));
+ memcpy(newdata, d_data, d_size * sizeof(Data));
+ free(d_data);
+ d_data = newdata;
+ };
+};
+
+#endif