library - TMC26x Stepper

This commit is contained in:
Richard Wackerbarth
2015-06-18 13:05:11 -04:00
parent ae9de515b8
commit d8785ffc6f
52 changed files with 33033 additions and 0 deletions

View File

@ -0,0 +1,176 @@
/*
TMC26XMotorTest.ino - - TMC26X Stepper library tester for Wiring/Arduino
Copyright (c) 2011, Interactive Matter, Marcus Nowotny
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
unsigned int motor_counter = 0;
unsigned char motor_moved = 0;
int sgThreshold = 4;
int sgFilter = 0;
int direction = 1;
unsigned int lower_SG_threshold = 0;
unsigned int upper_SG_threshold = 0;
unsigned char number_of_SG_readings=0;
unsigned char current_increment_step_size=0;
unsigned char lower_current_limit=0;
char chopperMode = 0; //0 for spread, 1 for constant off
char t_off = 2;
char t_blank = 24;
char h_start = 8;
char h_end = 6;
char h_decrement = 0;
void startMotor() {
Serial.println(F("Configuring stepper driver"));
//char constant_off_time, char blank_time, char hysteresis_start, char hysteresis_end, char hysteresis_decrement
tmc26XStepper.setSpreadCycleChopper(t_off,t_blank,h_start,h_end,h_decrement);
tmc26XStepper.setRandomOffTime(0);
tmc26XStepper.setMicrosteps(32);
tmc26XStepper.setStallGuardThreshold(sgThreshold,sgFilter);
// Serial.println("config finished, starting");
digitalWrite(ENABLE_PIN,LOW);
tmc26XStepper.start();
tmc26XStepper.setSpeed(10);
TCNT2=setupTimer2(10000);
sei();
}
void runMotor() {
if (running && !tmc26XStepper.isMoving()) {
tmc26XStepper.step(direction*10000);
Serial.println("run");
}
if (!running & tmc26XStepper.isMoving()) {
tmc26XStepper.stop();
Serial.println("stop");
}
}
void setSpeed(unsigned int targetSpeed) {
if (targetSpeed>0 && targetSpeed<MAX_SPEED) {
Serial.print(F("Setting speed: "));
Serial.println(targetSpeed);
tmc26XStepper.setSpeed(targetSpeed);
}
else {
Serial.print(F("improper speed "));
Serial.println(targetSpeed);
}
}
void setMicrostepping(int microstepping) {
if (microstepping<1 || microstepping>256) {
Serial.print(F("Improperd microstepping setting [1...256]: "));
Serial.print(microstepping);
}
else {
tmc26XStepper.setMicrosteps(microstepping);
}
}
void setStallGuardThreshold(int threshold) {
if (threshold<-64 || threshold > 63) {
Serial.print(F("Improper Stall Guard Threshold [-64...63]: "));
Serial.println(threshold);
}
else {
sgThreshold = threshold;
tmc26XStepper.setStallGuardThreshold(threshold,sgFilter);
}
}
void setStallGuardFilter(int filter) {
if (filter) {
sgFilter=1;
}
else {
sgFilter=0;
}
tmc26XStepper.setStallGuardThreshold(sgThreshold,sgFilter);
}
void setCurrent(int current) {
if (current>0 && current <1700) {
tmc26XStepper.setCurrent(current);
}
else {
Serial.print(F("Improper current {0 ... 1200}: "));
Serial.print(current);
}
}
void updateChopper() {
//we can do only spread now
if (chopperMode==0) {
tmc26XStepper.setSpreadCycleChopper(t_off,t_blank,h_start,h_end,h_decrement);
}
}
void updateCoolStep() {
tmc26XStepper.setCoolStepConfiguration(
lower_SG_threshold, upper_SG_threshold, number_of_SG_readings,
current_increment_step_size, lower_current_limit);
}
//from http://www.uchobby.com/index.php/2007/11/24/arduino-interrupts/
//Setup Timer2.s
//Configures the ATMega168 8-Bit Timer2 to generate an interrupt
//at the specified frequency.
//Returns the timer load value which must be loaded into TCNT2
//inside your ISR routine.
//See the example usage below.
unsigned char setupTimer2(float timeoutFrequency){
unsigned char result; //The timer load value.
//Calculate the timer load value
result=(int)((257.0-(TIMER_CLOCK_FREQ/timeoutFrequency))+0.5);
//The 257 really should be 256 but I get better results with 257.
//Timer2 Settings: Timer Prescaler /8, mode 0
//Timer clock = 16MHz/8 = 2Mhz or 0.5us
//The /8 prescale gives us a good range to work with
//so we just hard code this for now.
TCCR2A = 0;
TCCR2B = 0<<CS22 | 1<<CS21 | 0<<CS20;
//Timer2 Overflow Interrupt Enable
TIMSK2 = 1<<TOIE2;
//load the timer for its first cycle
TCNT2=result;
return(result);
}
ISR(TIMER2_OVF_vect) {
motor_moved = tmc26XStepper.move();
motor_counter++;
}

View File

@ -0,0 +1,369 @@
/*
TMC26XMotorTest.ino - - TMC26X Stepper library tester for Wiring/Arduino
Copyright (c) 2011, Interactive Matter, Marcus Nowotny
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#define INPUT_BUFFER_LENGTH 32
#define SERIAL_SPEED 115200
#define STATUS_COUNTER 100
char inputBuffer[INPUT_BUFFER_LENGTH+1]; //ad on character to keep the trainling 0
unsigned char inputBufferPosition;
void startSerial() {
Serial.begin(SERIAL_SPEED);
Serial.println(F("================================="));
Serial.println(F("TMC26X Stepper Driver Motor Tester"));
Serial.println(F("================================="));
//empty the input buffer
for (unsigned char i=0; i< INPUT_BUFFER_LENGTH+1; i++) {
inputBuffer[i]=0;
}
inputBufferPosition=0;
}
void loopSerial() {
if (Serial.available()>0 && inputBufferPosition<INPUT_BUFFER_LENGTH) {
char c = Serial.read();
//Read the char
inputBuffer[inputBufferPosition]=c;
inputBufferPosition++;
//always terminate the string
inputBuffer[inputBufferPosition]=0;
//and if the line ended we execute the command
if (c=='\n') {
executeSerialCommand();
}
}
if (motor_moved) {
Serial.print("#sg");
Serial.print(tmc26XStepper.getCurrentStallGuardReading(),DEC);
Serial.print(",p");
Serial.print(tmc26XStepper.getMotorPosition(),DEC);
Serial.print(",k");
Serial.print(tmc26XStepper.getCurrentCurrent(),DEC);
Serial.println(',');
motor_moved=0;
}
if (motor_counter>STATUS_COUNTER) {
motor_counter=0;
char moving = tmc26XStepper.isMoving();
Serial.print('#');
if (moving) {
Serial.print('r');
}
else {
Serial.print('s');
}
Serial.print(',');
Serial.print('d');
Serial.print(direction);
Serial.print(',');
Serial.print("c");
Serial.print(tmc26XStepper.getCurrent(),DEC);
Serial.print(',');
Serial.print('S');
Serial.print(tmc26XStepper.getSpeed(),DEC);
Serial.print(',');
Serial.print('m');
Serial.print(tmc26XStepper.getMicrosteps(),DEC);
Serial.print(',');
Serial.print("t");
Serial.print(tmc26XStepper.getStallGuardThreshold(),DEC);
Serial.print(',');
Serial.print('f');
Serial.print(tmc26XStepper.getStallGuardFilter(),DEC);
Serial.print(',');
//print out the general cool step config
if (tmc26XStepper.isCoolStepEnabled()) {
Serial.print("Ke+,");
}
else {
Serial.print("Ke-,");
}
Serial.print("Kl");
Serial.print(tmc26XStepper.getCoolStepLowerSgThreshold(),DEC);
Serial.print(",Ku");
Serial.print(tmc26XStepper.getCoolStepUpperSgThreshold(),DEC);
Serial.print(",Kn");
Serial.print(tmc26XStepper.getCoolStepNumberOfSGReadings(),DEC);
Serial.print(",Ki");
Serial.print(tmc26XStepper.getCoolStepCurrentIncrementSize(),DEC);
Serial.print(",Km");
Serial.print(tmc26XStepper.getCoolStepLowerCurrentLimit(),DEC);
Serial.print(',');
//detect the winding status
if (tmc26XStepper.isOpenLoadA()) {
Serial.print("ao,");
}
else if(tmc26XStepper.isShortToGroundA()) {
Serial.print("ag,");
}
else {
Serial.print("a-,");
}
//detect the winding status
if (tmc26XStepper.isOpenLoadB()) {
Serial.print("bo,");
}
else if(tmc26XStepper.isShortToGroundB()) {
Serial.print("bg,");
}
else {
Serial.print("b-,");
}
char temperature = tmc26XStepper.getOverTemperature();
if (temperature==0) {
Serial.print("x-,");
}
else if (temperature==TMC26X_OVERTEMPERATURE_PREWARING) {
Serial.print("xw,");
}
else {
Serial.print("xe,");
}
if (tmc26XStepper.isEnabled()) {
Serial.print("e1,");
}
else {
Serial.print("e0,");
}
//write out the current chopper config
Serial.print("Cm");
Serial.print(chopperMode,DEC);
Serial.print(",Co");
Serial.print(t_off,DEC);
Serial.print(",Cb");
Serial.print(t_blank,DEC);
if (chopperMode==0) {
Serial.print(",Cs");
Serial.print(h_start,DEC);
Serial.print(",Ce");
Serial.print(h_end,DEC);
Serial.print(",Cd");
Serial.print(h_decrement,DEC);
}
Serial.print(',');
Serial.println();
}
}
void executeSerialCommand() {
Serial.print("Executing ");
Serial.println(inputBuffer);
//stimple runn & stop commands
switch(inputBuffer[0]) {
case 's':
running = 0;
break;
case 'r':
running = -1;
break;
case 'S':
{
int targetSpeed = decode(1);
setSpeed(targetSpeed);
}
break;
case 'm':
{
int microstepping = decode(1);
setMicrostepping(microstepping);
}
break;
case 't':
{
int threshold = decode(1);
setStallGuardThreshold(threshold);
}
break;
case 'f':
{
int filter = decode(1);
setStallGuardFilter(filter);
}
break;
case 'd':
{
int value = decode(1);
tmc26XStepper.stop();
if (value<0) {
direction=-1;
}
else {
direction=1;
}
}
break;
case 'c':
{
int current = decode(1);
setCurrent(current);
}
break;
case 'e':
{
int enabled = decode(1);
if (enabled) {
tmc26XStepper.setEnabled(true);
}
else {
tmc26XStepper.setEnabled(false);
}
}
break;
case 'C':
switch(inputBuffer[1]) {
case 'o':
{
int value = decode(2);
if (value>0 && value<16) {
t_off=value;
updateChopper();
}
}
break;
case 'b':
{
int value = decode(2);
if (value>=0 && value<=3) {
t_blank=value;
updateChopper();
}
}
break;
case 's':
{
int value = decode(2);
if (value>=0 && value<=8) {
h_start=value;
updateChopper();
}
}
break;
case 'e':
{
int value = decode(2);
if (value>=-3 && value<=12) {
h_end=value;
updateChopper();
}
}
break;
case 'd':
{
int value = decode(2);
if (value>=0 && value<=3) {
h_decrement=value;
updateChopper();
}
}
break;
}
break;
case 'K':
switch(inputBuffer[1]) {
case '+':
tmc26XStepper.setCoolStepEnabled(true);
break;
case '-':
tmc26XStepper.setCoolStepEnabled(false);
break;
case 'l':
{
int value = decode(2);
if (value>=0 && value<480) {
lower_SG_threshold=value;
updateCoolStep();
}
}
break;
case 'u':
{
int value = decode(2);
if (value>=0 && value<480) {
upper_SG_threshold=value;
updateCoolStep();
}
}
break;
case 'n':
{
int value = decode(2);
if (value>=0 && value<4) {
number_of_SG_readings=value;
updateCoolStep();
}
}
break;
case 'i':
{
int value = decode(2);
if (value>=0 && value<4) {
current_increment_step_size=value;
updateCoolStep();
}
}
break;
case 'm':
{
int value = decode(2);
if (value>=0 && value<2) {
lower_current_limit=value;
updateCoolStep();
}
}
break;
}
break;
}
//at the end delete buffer
inputBufferPosition=0;
inputBuffer[0]=0;
}
int decode(unsigned char startPosition) {
int result=0;
boolean negative = false;
if (inputBuffer[startPosition]=='-') {
negative=true;
startPosition++;
}
for (unsigned char i=startPosition; i< (INPUT_BUFFER_LENGTH+1) && inputBuffer[i]!=0; i++) {
char number = inputBuffer[i];
//this very dumb approac can lead to errors, but we expect only numbers after the command anyway
if (number <= '9' && number >='0') {
result *= 10;
result += number - '0';
}
}
if (negative) {
return -result;
}
else {
return result;
}
}

View File

@ -0,0 +1,61 @@
/*
TMC26XMotorTest.ino - - TMC26X Stepper library Example for Wiring/Arduino
Copyright (c) 2011, Interactive Matter, Marcus Nowotny
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#include <SPI.h>
#include <TMC26XStepper.h>
//you may adapt this to your shield or breakout board connection
#define CS_PIN 2
#define DIR_PIN 6
#define STEP_PIN 7
#define ENABLE_PIN 8 //if it is not connected it won't be a problem
#define TIMER_CLOCK_FREQ 2000000.0 //2MHz for /8 prescale from 16MHz
#define INITIAL_CURRENT 500 //in mA
#define MAX_SPEED 1000
//we have a stepper motor with 200 steps per rotation, CS pin 2, dir pin 3, step pin 4 and a current of 300mA
TMC26XStepper tmc26XStepper = TMC26XStepper(200,CS_PIN,DIR_PIN,STEP_PIN,INITIAL_CURRENT);
char running;
void setup() {
//configure the enable pin
pinMode(ENABLE_PIN, OUTPUT);
digitalWrite(ENABLE_PIN,HIGH);
startSerial();
startMotor();
//set this according to you stepper
Serial.println(F("started"));
}
void loop() {
loopSerial();
runMotor();
}

View File

@ -0,0 +1,306 @@
/*
TMC26XMotorTest.pde - - TMC26X Stepper Tester for Processing
Copyright (c) 2011, Interactive Matter, Marcus Nowotny
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
String channelAStatus=null;
String channelBStatus=null;
String temperatureStatus=null;
boolean motor_connected = false;
RadioButton serialButtons;
Button serialOkButton;
Button helpButton;
Textarea statusArea;
String[] ports;
int activePortIndex = -1;
String identString="TMC26X Stepper Driver Motor Tester";
int connectTimeout=10*1000; //how long do we wait until the Arduino is connected
StringBuilder serialStringBuilder = new StringBuilder();
void setupSerialConfig() {
Tab defaultTab = controlP5.getTab("default");
//add the list of serial interfaces - it get's populated later
serialButtons = controlP5.addRadioButton("serialport", 200, 100+TMCLogo.height*2+50);
serialConfigElements.add(serialButtons);
serialButtons.captionLabel().set("Select Serial Port");
serialButtons.showBar();
serialButtons.moveTo(defaultTab);
//ad the ok button
serialOkButton = controlP5.addButton("serialOk", 1, 200, height-300, 30, 30);
serialConfigElements.add(serialOkButton);
serialOkButton.setCaptionLabel("OK");
runToggle.moveTo(defaultTab);
//add the status area
statusArea = controlP5.addTextarea("statusArea","",200,height-250,300,50);
serialConfigElements.add(statusArea);
statusArea.moveTo(defaultTab);
helpButton = controlP5.addButton("help", 1, 200, height-250, 80, 30);
serialConfigElements.add(helpButton);
helpButton.moveTo(defaultTab);
//finally update the list of serial ports
updateSerialPortList();
}
void updateSerialPortList() {
//first remove all present serial ports
List items = serialButtons.getItems();
for (Object i:items) {
Toggle item = (Toggle) i;
serialButtons.removeItem(item.getName());
}
//add the serial ports
ports = Serial.list();
for (int i=0; i< ports.length; i++) {
serialButtons.addItem(ports[i],i);
}
serialButtons.setValue(-1);
serialOkButton.setVisible(false);
}
void serialport(int value) {
//ok button is only active if a serial port is selected
serialOkButton.setVisible(value>-1);
if (value>-1) {
statusArea.setText("");
}
activePortIndex = value;
}
void serialOk(int value) {
String error = null;
if (value!=0 && activePortIndex>-1) {
try {
arduinoPort = new Serial(this, ports[activePortIndex], 115200);
int timeStarted = millis();
StringBuilder identBuffer = new StringBuilder();
while (!motor_connected && (millis()-timeStarted)<connectTimeout) {
if (arduinoPort.available ()>0) {
char c = arduinoPort.readChar();
identBuffer.append(c);
if (c=='\n') {
if (identString.contains(identString)) {
motor_connected = true;
toggleUi(true);
return;
}
identBuffer = new StringBuilder();
}
}
}
} catch (RuntimeException e) {
//we simply do nothing
//TODO set status label
error = "There was a problem with serial port "+ports[activePortIndex]+": "+e.getMessage();
}
//ok appearantly we did not find an motor tester - so lets deselect that port
if (error == null) {
error = "Could not find TMC26XMotorTester on serial port "+ports[activePortIndex];
}
statusArea.setText(error);
Toggle selected = serialButtons.getItem(activePortIndex);
selected.setState(false);
serialOkButton.setVisible(false);
}
}
void decodeSerial() {
if (motor_connected) {
while (arduinoPort.available ()>0) {
char c = arduinoPort.readChar();
serialStringBuilder.append(c);
if (c=='\n') {
decodeSerial(serialStringBuilder.toString());
serialStringBuilder = new StringBuilder();
}
}
}
}
void sendCommand(String command) {
if (motor_connected) {
arduinoPort.write(command+"\n");
}
}
void decodeSerial(String line) {
settingStatus=true;
if (line.startsWith("#")) {
String status = line.substring(1);
StringTokenizer statusTokenizer = new StringTokenizer(status, ",");
while (statusTokenizer.hasMoreTokens ()) {
String statusToken = statusTokenizer.nextToken();
if ("s".equals(statusToken)) {
runToggle.setValue(0);
}
else if ("r".equals(statusToken)) {
runToggle.setValue(1);
}
else if (statusToken.startsWith("e")) {
int enabled = getValueOfToken(statusToken, 1);
if (enabled!=0) {
enabledToggle.setValue(1);
}
else {
enabledToggle.setValue(0);
}
}
else if (statusToken.startsWith("S")) {
speedSlider.setValue(getValueOfToken(statusToken, 1));
}
else if (statusToken.startsWith("m")) {
microsteppingButtons.activate("m_1/"+String.valueOf(getValueOfToken(statusToken, 1)));
}
else if (statusToken.startsWith("sg")) {
addStallGuardReading(getValueOfToken(statusToken, 2));
}
else if (statusToken.startsWith("p")) {
addPositionReading(getValueOfToken(statusToken, 1));
}
else if (statusToken.startsWith("k")) {
addCurrentReading(getValueOfToken(statusToken, 1));
}
else if (statusToken.startsWith("t")) {
sgtSlider.setValue(getValueOfToken(statusToken, 1));
}
else if (statusToken.startsWith("f")) {
sgFilterToggle.setValue(getValueOfToken(statusToken, 1));
}
else if (statusToken.startsWith("d")) {
setDirection(getValueOfToken(statusToken, 1));
}
else if (statusToken.startsWith("c")) {
setCurrent(getValueOfToken(statusToken, 1));
}
else if (statusToken.startsWith("a")) {
if (statusToken.charAt(1)=='o') {
channelAStatus="Open Load";
}
else if (statusToken.charAt(1)=='g') {
channelAStatus="Short to Ground!";
}
else {
channelAStatus=null;
}
}
else if (statusToken.startsWith("b")) {
if (statusToken.charAt(1)=='o') {
channelBStatus="Open Load";
}
else if (statusToken.charAt(1)=='g') {
channelBStatus="Short to Ground!";
}
else {
channelBStatus=null;
}
}
else if (statusToken.startsWith("x")) {
if (statusToken.charAt(1)=='w') {
temperatureStatus="Prewarning!";
}
else if (statusToken.charAt(1)=='e') {
temperatureStatus="Error";
}
else {
temperatureStatus=null;
}
}
else if (statusToken.startsWith("Cm")) {
//chopper mode is currently ignored
}
else if (statusToken.startsWith("Co")) {
constantOffSlider.setValue(getValueOfToken(statusToken, 2));
}
else if (statusToken.startsWith("Cb")) {
blankTimeSlider.setValue(getValueOfToken(statusToken, 2));
}
else if (statusToken.startsWith("Cs")) {
hysteresisStartSlider.setValue(getValueOfToken(statusToken, 2));
}
else if (statusToken.startsWith("Ce")) {
hysteresisEndSlider.setValue(getValueOfToken(statusToken, 2));
}
else if (statusToken.startsWith("Cd")) {
setHystDecrement(getValueOfToken(statusToken, 2));
}
else if ("Ke+".equals(statusToken)) {
coolStepActiveToggle.setValue(1);
}
else if ("Ke-".equals(statusToken)) {
coolStepActiveToggle.setValue(0);
}
else if (statusToken.startsWith("Kl")) {
coolStepMinSlider.setValue(getValueOfToken(statusToken, 2));
}
else if (statusToken.startsWith("Ku")) {
coolStepMaxSlider.setValue(getValueOfToken(statusToken, 2));
}
else if (statusToken.startsWith("Kn")) {
coolStepDecrementButtons.activate(getValueOfToken(statusToken, 2));
}
else if (statusToken.startsWith("Ki")) {
coolStepIncrementButtons.activate(getValueOfToken(statusToken, 2));
}
else if (statusToken.startsWith("Km")) {
coolStepMinButtons.activate(getValueOfToken(statusToken, 2));
}
}
}
else {
println(line);
}
settingStatus=false;
}
int getValueOfToken(String token, int position) {
String value = token.substring(position);
try {
return Integer.valueOf(value);
}
catch (NumberFormatException e) {
println("Unable to decode '"+value+"'of '"+token+"' !");
return 0;
}
}
void drawSerial() {
//draw the logo and some epxlaining text while setting up the serial port
if (!motor_connected) {
image(TMCLogo,200, 100);
fill(uiTextColor);
text("Select the serial port where your Arduino is connected\nIf in doubt check it in the Arduino IDE.\nThe Motor Tester will automatically verify if it can find an Motor tester ath the port.",200,100+TMCLogo.height+50);
}
}
void help(float value) {
if (value!=0) {
link(helpUrl);
}
}

View File

@ -0,0 +1,175 @@
/*
TMC26XMotorTest.pde - - TMC26X Stepper Tester for Processing
Copyright (c) 2011, Interactive Matter, Marcus Nowotny
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
Slider constantOffSlider;
Slider blankTimeSlider;
Toggle randomOffTimeToggle;
RadioButton ChopperModeButtons;
//for constant off time chopeer
Slider fastDecaySlider;
Slider sineWaveOffsetSlider;
Toggle currentComparatorToggle;
//for spread chopper
Slider hysteresisStartSlider;
Slider hysteresisEndSlider;
Numberbox motorVoltageBox;
Numberbox motorCurrentBox;
Numberbox motorResistanceBox;
Numberbox motorInductanceBox;
RadioButton hysteresisDecrementButtons;
PImage spreadChopperImage;
void setupChooperConfig() {
//add input fields for the various motor parameters
motorVoltageBox = controlP5.addNumberbox("motorvoltage",12.0,20,40,100,20);
motorVoltageBox.setCaptionLabel("Motor Voltage (V)");
motorVoltageBox.setMultiplier(0.025);
motorVoltageBox.setMin(0);
motorVoltageBox.setMax(40.0);
motorVoltageBox.moveTo(configureTab);
motorCurrentBox = controlP5.addNumberbox("motorcurrent",0.5,140,40,100,20);
motorCurrentBox.setCaptionLabel("Motor Current (A)");
motorCurrentBox.setMultiplier(0.025);
motorCurrentBox.setMin(0.46);
motorCurrentBox.setMax(1.7);
motorCurrentBox.moveTo(configureTab);
motorResistanceBox = controlP5.addNumberbox("motorresistance",2,260,40,100,20);
motorResistanceBox.setCaptionLabel("Motor Resistance (Ohm)");
motorResistanceBox.setMultiplier(0.1);
motorResistanceBox.setMin(0);
motorResistanceBox.setMax(250);
motorResistanceBox.moveTo(configureTab);
motorInductanceBox = controlP5.addNumberbox("motorinductance",2,380,40,100,20);
motorInductanceBox.setMultiplier(0.1);
motorInductanceBox.setMin(0);
motorInductanceBox.setMax(250);
motorInductanceBox.setCaptionLabel("Motor Inductance (mH)");
motorInductanceBox.moveTo(configureTab);
// add a vertical slider for speed
constantOffSlider = controlP5.addSlider("constantoff", 1, 15, 1, 20, 80, 400, 20);
constantOffSlider.setCaptionLabel("Constant Off Time");
constantOffSlider.setSliderMode(Slider.FIX);
constantOffSlider.moveTo(configureTab);
blankTimeSlider = controlP5.addSlider("blanktime", 0, 3, 2, 20, 120, 400, 20);
blankTimeSlider.setCaptionLabel("Blank Time");
blankTimeSlider.moveTo(configureTab);
hysteresisStartSlider = controlP5.addSlider("hysteresisstart", 0, 8, 2, 20, 160, 400, 20);
hysteresisStartSlider.setCaptionLabel("Hysteresis Start");
hysteresisStartSlider.moveTo(configureTab);
hysteresisEndSlider = controlP5.addSlider("hysteresisend", -3, 12, 2, 20, 200, 400, 20);
hysteresisEndSlider.setCaptionLabel("Hysteresis End");
hysteresisEndSlider.moveTo(configureTab);
hysteresisDecrementButtons =controlP5.addRadioButton("decrement", 20, 240);
hysteresisDecrementButtons.addItem("fastest", 0);
hysteresisDecrementButtons.addItem("fast", 1);
hysteresisDecrementButtons.addItem("medium", 2);
hysteresisDecrementButtons.addItem("slow", 3);
hysteresisDecrementButtons.showBar();
hysteresisDecrementButtons.moveTo(configureTab);
spreadChopperImage = loadImage("hysteresis.png");
}
void drawChopper() {
if (activeTab!=null && configureTab.equals(activeTab)) {
image(spreadChopperImage, 200, 400);
}
}
void constantoff(int theValue) {
if (!settingStatus) {
if (theValue>0 && theValue<16) {
println("Constant off "+theValue);
sendCommand("cO"+theValue);
}
else {
println("invalid blank time of "+theValue);
}
}
}
void blanktime(int theValue) {
if (!settingStatus) {
if (theValue>=0 && theValue<=3) {
println("blank time "+theValue);
sendCommand("Cb"+theValue);
}
}
}
void hysteresisstart(int start) {
if (!settingStatus) {
if (start>=1 && start<=8) {
println("hystereis start "+start);
sendCommand("Cs"+start);
}
}
}
void hysteresisend(int end) {
if (!settingStatus) {
if (end>=-3 && end<=12) {
println("hystereis end "+end);
sendCommand("Ce"+end);
}
}
}
void setHysteresisDecrement(int theValue) {
if (!settingStatus) {
if (theValue>=0 && theValue<=3) {
println("Hysteresis decrement "+theValue);
sendCommand("Cd"+theValue);
}
else {
println("cannot set decrement to "+theValue);
}
}
}
void setHystDecrement(int value) {
if (value>=0 && value<=3) {
hysteresisDecrementButtons.activate(value);
}
else {
println("this is no proper hysteresis decerement value: "+value);
}
}
void motorcurrent(float value) {
if (activeTab!=null && "default".equals(activeTab.name())) {
currentSlider.setValue(value);
}
}

View File

@ -0,0 +1,327 @@
/*
TMC26XMotorTest.pde - - TMC26X Stepper Tester for Processing
Copyright (c) 2011, Interactive Matter, Marcus Nowotny
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
//our graph dimensions
int plotBottom, plotTop;
int plotLeft, plotRight;
//we already know the minima and maxima of certain dates
int stallGuardMin = 0;
int stallGuardMax =1024;
int positionMin = 0;
int positionMax = 1024;
int dataPointsWidth = 3;
int dataLineWidth = 2;
int highLightWidth = 7;
int numberOfDataPoints=1000;
int legendTitleSize = 10;
int legendTextSize = 10;
int currentLabelInterval = 500;
int currentMinorTickInterval = 25;
DecimalFormat currentLabelFormat = new DecimalFormat("#0.0A");
int stallGuardLabelInterval = 100;
int stallGuardMinorTickInterval = 10;
int positionLabelInterval = 64;
int positionMinorTickInterval = 8;
int coolStepActiveStroke = 2;
int coolStepInactiveStroke = 1;
int stallGuardHighLightDistance = 1;
int positionHighLightDistance = 3;
int currentHighLightDistance = 3;
DataTable stallGuardTable = new DataTable(numberOfDataPoints);
DataTable positionTable = new DataTable(numberOfDataPoints);
DataTable currentTable = new DataTable(numberOfDataPoints);
int logoLeft = 10;
int logoTop = 50;
int logoWidth = 75;
int logoHeight = 75;
void setupData() {
plotBottom = height-50;
plotTop = 300;
plotLeft = 150;
plotRight= width-50;
//recalculate the image dimension for the Logo
logoHeight = (int)((float)logoWidth/(float)TMCLogo.width*(float)TMCLogo.height);
logoTop = height - 10 - logoHeight;
}
void drawData() {
if (motor_connected && activeTab!=null && runTab.equals(activeTab)) {
fill(diagramBackgroundColor);
noStroke();
rect(plotLeft, plotTop, plotRight, plotBottom);
noFill();
rectMode(CORNERS);
noStroke();
//rect(plotLeft, plotBottom, plotRight, plotTop);
strokeWeight(dataLineWidth);
stroke(positionColor);
drawDataLine(positionTable, positionMin, positionMax);
drawDataHighLight(positionTable, positionMin, positionMax, positionHighLightDistance, labelColor, "Microstep Position", false);
strokeWeight(dataLineWidth);
stroke(coolStepColor);
drawCurrentLine(currentTable);
drawCurrentHighLight(positionTable, currentHighLightDistance, labelColor, "Current Ratio", false);
strokeWeight(dataPointsWidth);
stroke(stallGuardColor);
drawDataPoints(stallGuardTable, stallGuardMin, stallGuardMax);
drawDataHighLight(stallGuardTable, stallGuardMin, stallGuardMax, stallGuardHighLightDistance, labelColor, "Stall Guard", true);
if (coolStepActive) {
strokeWeight(coolStepActiveStroke);
} else {
strokeWeight(coolStepInactiveStroke);
}
stroke(coolStepColor);
float coolStepMinHeight = map(coolStepMin, 0, stallGuardMax, plotBottom, plotTop);
line(plotLeft,coolStepMinHeight, plotRight, coolStepMinHeight);
float coolStepMaxHeight = map(coolStepMin+coolStepMax+1, 0, stallGuardMax, plotBottom, plotTop);
line(plotLeft,coolStepMaxHeight, plotRight, coolStepMaxHeight);
textSize(legendTitleSize);
textAlign(RIGHT);
fill(coolStepColor);
text("Motor Current", plotLeft - 50, plotTop - 10);
textSize(legendTextSize);
textAlign(RIGHT);
strokeWeight(1);
stroke(coolStepColor);
int currentScaleMax = (int)(maxCurrent*1000.0);
for (int i=0; i<=currentScaleMax; i++) {
float y = map(i, 0, currentScaleMax, plotBottom, plotTop);
if (i % currentLabelInterval == 0) {
if (i==0) {
textAlign(RIGHT, BOTTOM);
}
else if (i==currentScaleMax) {
textAlign(RIGHT, TOP);
}
else {
textAlign(RIGHT, CENTER);
}
text(currentLabelFormat.format((float)i/1000.0), plotLeft-58, y);
line (plotLeft-55, y, plotLeft-50, y);
}
else if (i % currentMinorTickInterval == 0) {
line (plotLeft-53, y, plotLeft-50, y);
}
}
textSize(legendTitleSize);
textAlign(LEFT);
fill(stallGuardColor);
text("Stall Guard Reading", plotLeft - 30, plotTop - 10);
textSize(legendTextSize);
textAlign(RIGHT);
strokeWeight(1);
stroke(stallGuardColor);
for (int i=stallGuardMin; i<=stallGuardMax; i++) {
float y = map(i, stallGuardMin, stallGuardMax, plotBottom, plotTop);
if (i % stallGuardLabelInterval == 0) {
if (i==stallGuardMin) {
textAlign(RIGHT, BOTTOM);
}
else if (i==stallGuardMax) {
textAlign(RIGHT, TOP);
}
else {
textAlign(RIGHT, CENTER);
}
text(i, plotLeft-8, y);
line (plotLeft-5, y, plotLeft, y);
}
else if (i % stallGuardMinorTickInterval == 0) {
line (plotLeft-3, y, plotLeft, y);
}
}
textSize(legendTitleSize);
fill(positionColor);
textAlign(RIGHT);
text("Position", plotRight + 30, plotTop - 10);
textSize(legendTextSize);
textAlign(LEFT);
strokeWeight(1);
stroke(positionColor);
for (int i=positionMin; i<=positionMax; i++) {
float y = map(i, positionMin, positionMax, plotBottom, plotTop);
if (i % positionLabelInterval == 0) {
if (i==positionMin) {
textAlign(LEFT, BOTTOM);
}
else if (i==stallGuardMax) {
textAlign(LEFT, TOP);
}
else {
textAlign(LEFT, CENTER);
}
text(i, plotRight+8, y);
line (plotRight, y, plotRight+5, y);
}
else if (i % positionMinorTickInterval == 0) {
line (plotRight, y, plotRight+3, y);
}
}
//draw the channel status
textSize(legendTextSize);
textAlign(CENTER);
strokeWeight(1);
int statusY = height - 20;
int channelAX = width/4;
int temperatureX = width/2;
int channelBX = width/4*3;
if (channelAStatus==null) {
fill(goodStatusColor);
text("Channel A: OK", channelAX, statusY);
}
else {
fill(badStatusColor);
text("Channel A: "+channelAStatus, channelAX, statusY);
}
if (channelBStatus==null) {
fill(goodStatusColor);
text("Channel B: OK", channelBX, statusY);
}
else {
fill(badStatusColor);
text("Channel B: "+channelBStatus, channelBX, statusY);
}
if (temperatureStatus==null) {
fill(goodStatusColor);
text("Temperature: OK", temperatureX, statusY);
}
else {
fill(badStatusColor);
text("Temperature: "+temperatureStatus, temperatureX, statusY);
}
}
}
void drawDataPoints(DataTable table, int minValue, int maxValue) {
int dataCount = table.getSize();
for (int i=0; i<dataCount; i++) {
int value = table.getEntry(i);
float x = map(i, 0, numberOfDataPoints-1, plotLeft+dataPointsWidth, plotRight-dataPointsWidth);
float y = map(value, minValue, maxValue, plotBottom-dataPointsWidth, plotTop+dataPointsWidth);
point(x, y);
}
}
void drawDataLine(DataTable table, int minValue, int maxValue) {
beginShape();
int dataCount = table.getSize();
for (int i=0; i<dataCount; i++) {
int value = table.getEntry(i);
float x = map(i, 0, numberOfDataPoints-1, plotLeft+dataPointsWidth, plotRight-dataPointsWidth);
float y = map(value, minValue, maxValue, plotBottom-dataPointsWidth, plotTop+dataPointsWidth);
vertex(x, y);
}
endShape();
}
void drawDataHighLight(DataTable table, int minValue, int maxValue, int distance, color textColor, String name, boolean top) {
int dataCount = table.getSize();
for (int i=0; i<dataCount; i++) {
int value = table.getEntry(i);
float x = map(i, 0, numberOfDataPoints-1, plotLeft+dataPointsWidth, plotRight-dataPointsWidth);
float y = map(value, minValue, maxValue, plotBottom-dataPointsWidth, plotTop+dataPointsWidth);
if (dist(mouseX, mouseY, x, y) < distance) {
strokeWeight(highLightWidth);
point(x, y);
fill(textColor);
textSize(10);
textAlign(CENTER);
if (top) {
text(name+": "+value, x, y-8);
}
else {
text(name+": "+value, x, y+8);
}
}
}
}
void drawCurrentLine(DataTable table) {
noFill();
beginShape();
int dataCount = table.getSize();
for (int i=0; i<dataCount; i++) {
float value = (table.getEntry(i)+1)/1000.0;
float x = map(i, 0, numberOfDataPoints-1, plotLeft+dataPointsWidth, plotRight-dataPointsWidth);
float y = map(value, 0.0, maxCurrent, (float)plotBottom-dataPointsWidth, (float)plotTop+dataPointsWidth);
vertex(x, y);
}
endShape();
}
void drawCurrentHighLight(DataTable table, int distance, color textColor, String name, boolean top) {
int dataCount = table.getSize();
for (int i=0; i<dataCount; i++) {
float value = (table.getEntry(i)+1)/1000.0;
float x = map(i, 0, numberOfDataPoints-1, plotLeft+dataPointsWidth, plotRight-dataPointsWidth);
float y = map(value, 0.0, maxCurrent, plotBottom-dataPointsWidth, plotTop+dataPointsWidth);
if (dist(mouseX, mouseY, x, y) < distance) {
strokeWeight(highLightWidth);
point(x, y);
fill(textColor);
textSize(10);
textAlign(CENTER);
if (top) {
text(name+": "+value, x, y-8);
}
else {
text(name+": "+value, x, y+8);
}
}
}
}
void addStallGuardReading(int value) {
stallGuardTable.addData(value);
}
void addPositionReading(int value) {
positionTable.addData(value);
}
void addCurrentReading(int value) {
currentTable.addData(value);
}

View File

@ -0,0 +1,49 @@
/*
TMC26XMotorTest.pde - - TMC26X Stepper Tester for Processing
Copyright (c) 2011, Interactive Matter, Marcus Nowotny
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
class DataTable {
LinkedList<Integer> dataList = new LinkedList<Integer>();
int maxEntries;
DataTable(int maxEntries) {
this.maxEntries = maxEntries;
}
void addData(int value) {
dataList.add(value);
if (dataList.size()>maxEntries) {
dataList.remove();
}
}
int getSize() {
return dataList.size();
}
int getEntry(int position) {
return dataList.get(position);
}
}

View File

@ -0,0 +1,335 @@
/*
TMC26XMotorTest.pde - - TMC26X Stepper Tester for Processing
Copyright (c) 2011, Interactive Matter, Marcus Nowotny
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
Slider speedSlider;
Toggle runToggle;
RadioButton directionButtons;
Toggle enabledToggle;
RadioButton microsteppingButtons;
Slider sgtSlider;
Button sgtPlus;
Button sgtMinus;
Toggle sgFilterToggle;
Slider currentSlider;
Slider coolStepMinSlider;
Slider coolStepMaxSlider;
Toggle coolStepActiveToggle;
RadioButton coolStepIncrementButtons;
RadioButton coolStepDecrementButtons;
RadioButton coolStepMinButtons;
List runControls = new LinkedList();
Button trinamicButton;
Button motionControlButton;
void setupRunConfig() {
//the run configuration
//controlP5.getControlFont().setSize(10); - the font is too small, try to increase it!
//add a button te let the motor run
runToggle = controlP5.addToggle("run", false, 20, 40, 30, 30);
controlElements.add(runToggle);
runToggle.moveTo(runTab);
//add some directions buttons
directionButtons = controlP5.addRadioButton("direction", 20, 90);
controlElements.add(directionButtons);
directionButtons.addItem("forward", 1);
directionButtons.addItem("backward", -1);
directionButtons.activate(0);
directionButtons.moveTo(runTab);
enabledToggle = controlP5.addToggle("enabled", false, 20, 220, 30, 30);
controlElements.add(enabledToggle);
enabledToggle.moveTo(runTab);
// add a vertical slider for speed
speedSlider = controlP5.addSlider("speed", 1, 100, 10, 85, 40, 20, 210);
controlElements.add(speedSlider);
speedSlider.moveTo(runTab);
//ad a multilist for the microstepping setting
microsteppingButtons = controlP5.addRadioButton("microstepping", 150, 40);
controlElements.add(microsteppingButtons);
microsteppingButtons.addItem("m_1/1", 1);
microsteppingButtons.addItem("m_1/2", 2);
microsteppingButtons.addItem("m_1/4", 4);
microsteppingButtons.addItem("m_1/8", 8);
microsteppingButtons.addItem("m_1/16", 16);
microsteppingButtons.addItem("m_1/32", 32);
microsteppingButtons.addItem("m_1/64", 64);
microsteppingButtons.addItem("m_1/128", 128);
microsteppingButtons.addItem("m_1/256", 256);
for (Object o:microsteppingButtons.getItems()) {
Toggle t = (Toggle) o;
t.setCaptionLabel(t.getName().substring(2));
}
microsteppingButtons.showBar();
microsteppingButtons.moveTo(runTab);
currentSlider = controlP5.addSlider("current", 0.46, maxCurrent, 0.4, 250, 40, 20, 210);
controlElements.add(currentSlider);
currentSlider.moveTo(runTab);
// add a vertical slider for stallGuard threshold
sgtPlus = controlP5.addButton("sgtplus", 0, 400, 40, 20, 20);
controlElements.add(sgtPlus);
sgtPlus.setCaptionLabel("+");
sgtPlus.moveTo(runTab);
sgtMinus = controlP5.addButton("sgtminus", 1, 400, 70, 20, 20);
controlElements.add(sgtMinus);
sgtMinus.setCaptionLabel("-");
sgtMinus.moveTo(runTab);
sgtSlider = controlP5.addSlider("stallguardthreshold", -64, 63, 0, 350, 40, 20, 150);
controlElements.add(sgtSlider);
sgtSlider.setSliderMode(Slider.FIX);
sgtSlider.setCaptionLabel("Stall Guard Threshold");
sgtSlider.moveTo(runTab);
//ading some buttons to have finer sg control
//adding a button for the filter
sgFilterToggle = controlP5.addToggle("sgfilter", false, 350, 220, 30, 30);
controlElements.add(sgFilterToggle);
sgFilterToggle.setCaptionLabel("Stall GuardFilter");
sgFilterToggle.moveTo(runTab);
//add the coolstep sliders
coolStepMaxSlider = controlP5.addSlider("coolStepUpper", 0, 480, 0, 500, 40, 20, 90);
controlElements.add(coolStepMaxSlider);
coolStepMaxSlider.setCaptionLabel("Cool Step Hysteresis");
coolStepMaxSlider.moveTo(runTab);
coolStepMinSlider = controlP5.addSlider("coolStepLower", 0, 480, 0, 500, 160, 20, 90);
controlElements.add(coolStepMinSlider);
coolStepMinSlider.setCaptionLabel("Cool Step Minimum");
coolStepMinSlider.moveTo(runTab);
coolStepActiveToggle = controlP5.addToggle("coolStepActive", false, 600, 220, 30, 30);
controlElements.add(coolStepActiveToggle);
coolStepActiveToggle.setCaptionLabel("Enable CoolStep");
coolStepActiveToggle.moveTo(runTab);
coolStepIncrementButtons = controlP5.addRadioButton("coolStepIncrement", 600, 40);
controlElements.add(coolStepIncrementButtons);
coolStepIncrementButtons.captionLabel().set("Cool Step Increment");
coolStepIncrementButtons.addItem("i_1", 0);
coolStepIncrementButtons.addItem("i_2", 1);
coolStepIncrementButtons.addItem("i_4", 2);
coolStepIncrementButtons.addItem("i_8", 3);
for (Object o:coolStepIncrementButtons.getItems()) {
Toggle t = (Toggle) o;
t.setCaptionLabel(t.getName().substring(2));
}
coolStepIncrementButtons.showBar();
coolStepIncrementButtons.moveTo(runTab);
coolStepDecrementButtons = controlP5.addRadioButton("coolStepDecrement", 600, 110);
controlElements.add(coolStepDecrementButtons);
coolStepDecrementButtons.captionLabel().set("Cool Step Decrement");
coolStepDecrementButtons.addItem("d_32", 0);
coolStepDecrementButtons.addItem("d_8", 1);
coolStepDecrementButtons.addItem("d_2", 2);
coolStepDecrementButtons.addItem("d_1", 3);
for (Object o:coolStepDecrementButtons.getItems()) {
Toggle t = (Toggle) o;
t.setCaptionLabel(t.getName().substring(2));
}
coolStepDecrementButtons.showBar();
coolStepDecrementButtons.moveTo(runTab);
coolStepMinButtons = controlP5.addRadioButton("coolStepMin", 600, 180);
controlElements.add(coolStepMinButtons);
coolStepMinButtons.addItem("s_1/2", 0);
coolStepMinButtons.addItem("s_1/4", 1);
for (Object o:coolStepMinButtons.getItems()) {
Toggle t = (Toggle) o;
t.setCaptionLabel(t.getName().substring(2));
}
coolStepMinButtons.showBar();
coolStepMinButtons.moveTo(runTab);
trinamicButton = controlP5.addButton("trinamicLogo", 1.0, 750, 40, 200, 100);
trinamicButton.setImage(TMCLogo);
trinamicButton.moveTo(runTab);
controlElements.add(trinamicButton);
motionControlButton = controlP5.addButton("mcLogo", 1.0, 750, 150, 200, 100);
motionControlButton.setImage(MCLogo);
motionControlButton.moveTo(runTab);
controlElements.add(motionControlButton);
}
void speed(int theSpeed) {
if (!settingStatus) {
int speed = (int) theSpeed;
println("setting speed to "+speed);
sendCommand("S"+speed);
}
}
void run(int value) {
if (!settingStatus) {
println("button pressed");
if (running) {
println("stopping motor");
sendCommand("s");
running = false;
}
else {
println("starting motor");
sendCommand("r");
running = true;
}
}
}
void enabled(int value) {
if (!settingStatus) {
println("enabled: "+value);
sendCommand("e"+value);
}
}
void microstepping(int value) {
if (!settingStatus) {
println("microstepping: "+value);
sendCommand("m"+value);
}
}
void stallguardthreshold(int value) {
if (!settingStatus) {
println("stall guard threshold: "+value);
sendCommand("t"+value);
}
if (value==sgtSlider.max()) {
sgtPlus.lock();
}
else {
sgtPlus.unlock();
}
if (value==sgtSlider.min()) {
sgtMinus.lock();
}
else {
sgtMinus.unlock();
}
}
void sgtplus(int value) {
sgtSlider.setValue(sgtSlider.value()+1);
}
void sgtminus(int value) {
sgtSlider.setValue(sgtSlider.value()-1);
}
void sgfilter(int value) {
if (!settingStatus) {
println("filter: "+value);
sendCommand("f"+value);
}
}
void current(float value) {
if (!settingStatus) {
int realValue=(int)(value*1000.0);
println("current: "+((float)realValue/1000.0)+" = "+realValue);
sendCommand("c"+realValue);
if (activeTab!=null && "run".equals(activeTab.name())) {
motorCurrentBox.setValue(value);
}
}
}
void coolStepUpper(int value) {
coolStepMax=value;
if (!settingStatus) {
sendCommand("Ku"+value);
}
}
void coolStepLower(int value) {
coolStepMin = value;
if (!settingStatus) {
sendCommand("Kl"+value);
}
}
void setCoolStepIncrement(int value) {
if (!settingStatus) {
println("cool step increment :"+value);
sendCommand("Ki"+value);
}
}
void setCoolStepDecrement(int value) {
if (!settingStatus) {
println("cool step decrement :"+value);
sendCommand("Kn"+value);
}
}
void setCoolStepMin(int value) {
if (!settingStatus) {
println("cool step minimum :"+value);
sendCommand("Km"+value);
}
}
void coolStepActive(int value) {
if (!settingStatus) {
coolStepActive = (value!=0);
sendCommand(coolStepActive? "K+":"K-");
}
}
void setCurrent(int current) {
currentSlider.setValue((float)current/1000.0);
}
void setDirection(int direction) {
if (!settingStatus) {
if (direction<0) {
println("back");
sendCommand("d-1");
}
else {
sendCommand("d1");
}
}
}
void trinamicLogo(float value){
if (value!=0) {
link(trinamicUrl);
}
}
void mcLogo(float value) {
if (value!=0) {
link(mcUrl);
}
}

View File

@ -0,0 +1,156 @@
/*
TMC26XMotorTest.pde - - TMC26X Stepper Tester for Processing
Copyright (c) 2011, Interactive Matter, Marcus Nowotny
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
import controlP5.*;
import processing.serial.*;
import java.util.*;
import java.text.*;
ControlP5 controlP5;
Serial arduinoPort;
String helpUrl = "http://www.motioncontrol-community.org/";
String trinamicUrl = "http://trinamic.com";
String mcUrl = "http://www.motioncontrol-community.org/";
//TODO comde up with a nice color scheme
color activeColor = #01ADF1;
color foreGroundColor = #01ADF1;
color uiTextColor = #4D4D4F;
color uiElementColor = #ffffff;
color labelColor = #f0f0f0;
color valueColor = #f0f0f0;
color backgroundColor = #EDEEEF;
color stallGuardColor = #969696;
color positionColor = #01ADF1;
color goodStatusColor = labelColor;
color badStatusColor = stallGuardColor;
color coolStepColor = #4D4D4F;
color diagramBackgroundColor = #ffffff;
CColor uiColor = new CColor( foreGroundColor, uiElementColor, activeColor, uiTextColor, uiTextColor);
Tab configureTab;
Tab runTab;
Tab activeTab;
boolean settingStatus=false;
boolean running = false;
int coolStepMin = 0;
int coolStepMax = 0;
boolean coolStepActive = false;
float maxCurrent = 1.7;
List controlElements = new LinkedList();
List serialConfigElements = new LinkedList();
PImage TMCLogo;
PImage MCLogo;
void setup() {
size(1000, 800);
//load the logos
TMCLogo=loadImage("tmc_logo.jpg");
MCLogo=loadImage("mc_logo.jpg");
//create the UI
controlP5 = new ControlP5(this);
controlP5.setColor(uiColor);
runTab = controlP5.getTab("default");
configureTab =controlP5.addTab("configure");
//customize the tabs a bit
configureTab.setLabel("configure");
controlElements.add(configureTab);
activeTab = controlP5.getTab("default");
controlP5.setTabEventsActive(true);
configureTab.activateEvent(true);
runTab.activateEvent(true);
//configuring the general UI l&f
//the configuration UI
setupRunConfig();
setupChooperConfig();
setupSerialConfig();
//directly hide the controls again since we are not connected to the Arduino yet
toggleUi(motor_connected);
smooth();
setupData();
}
void toggleUi(boolean show_controls) {
for (Object c:controlElements) {
ControllerInterface controller = (ControllerInterface) c;
if (show_controls) {
controller.show();
} else {
controller.hide();
}
}
for (Object c:serialConfigElements) {
ControllerInterface controller = (ControllerInterface) c;
if (show_controls) {
controller.hide();
} else {
controller.show();
}
}
}
void draw() {
background(backgroundColor);
drawSerial();
drawChopper();
drawData();
decodeSerial();
}
void controlEvent(ControlEvent theEvent) {
if (theEvent.isGroup() && !settingStatus) {
if ("microstepping".equals(theEvent.group().name())) {
microstepping((int)theEvent.group().value());
} else
if ("direction".equals(theEvent.group().name())) {
setDirection((int)theEvent.group().value());
} else if ("decrement".equals(theEvent.group().name())) {
setHysteresisDecrement((int)theEvent.group().value());
} else if ("coolStepIncrement".equals(theEvent.group().name())) {
setCoolStepIncrement((int)theEvent.group().value());
} else if ("coolStepDecrement".equals(theEvent.group().name())) {
setCoolStepDecrement((int)theEvent.group().value());
} else if ("coolStepMin".equals(theEvent.group().name())) {
setCoolStepMin((int)theEvent.group().value());
}
}
else if (theEvent.isTab()) {
activeTab = theEvent.tab();
println("Tab: "+activeTab.name());
}
}

View File

@ -0,0 +1,2 @@
mode.id=processing.mode.java.JavaMode
mode=Java