├── .gitignore ├── 3Axis_SNAP └── 3Axis_SNAP.pde ├── Extruder_SNAP └── Extruder_SNAP.pde ├── GCode_Interpreter ├── GCode_Interpreter.pde ├── _init.pde ├── extruder.pde ├── process_string.pde └── stepper_control.pde ├── GCode_Interpreter_Experimental ├── GCode_Interpreter_Experimental.pde ├── _init.pde ├── extruder.pde ├── interrupt_routines.pde ├── process_string.pde └── stepper_control.pde ├── LICENSE ├── README ├── Single_Arduino_SNAP └── Single_Arduino_SNAP.pde ├── Single_Arduino_SNAP_v2 ├── Single_Arduino_SNAP_v2.pde ├── _init.pde ├── extruder.pde ├── process_snap.pde └── stepper_control.pde ├── library ├── AnalogEncoder │ ├── AnalogEncoder.cpp │ ├── AnalogEncoder.h │ └── keywords.txt ├── CartesianBot │ ├── CartesianBot.cpp │ ├── CartesianBot.h │ └── keywords.txt ├── CartesianBot_SNAP_v1 │ ├── CartesianBot_SNAP_v1.cpp │ └── CartesianBot_SNAP_v1.h ├── LinearAxis │ ├── LinearAxis.cpp │ └── LinearAxis.h ├── RepStepper │ ├── RepStepper.cpp │ ├── RepStepper.h │ └── keywords.txt ├── SNAP │ ├── SNAP.cpp │ └── SNAP.h ├── ThermoplastExtruder │ ├── ThermistorTable.h │ ├── Thermistor_r0_100000_t0_25_r1_0_r2_4700_beta_3960.h │ ├── Thermistor_r0_100000_t0_25_r1_0_r2_4700_beta_4066.h │ ├── Thermistor_r0_10000_t0_25_r1_680_r2_1600_beta_3480.h │ ├── Thermistor_r0_10000_t0_25_r1_680_r2_1600_beta_3964.h │ ├── ThermoplastExtruder.cpp │ ├── ThermoplastExtruder.h │ └── keywords.txt └── ThermoplastExtruder_SNAP_v1 │ ├── ThermoplastExtruder_SNAP_v1.cpp │ └── ThermoplastExtruder_SNAP_v1.h ├── package_release └── utilities └── createTemperatureLookup.py /.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | applet 3 | -------------------------------------------------------------------------------- /3Axis_SNAP/3Axis_SNAP.pde: -------------------------------------------------------------------------------- 1 | /* 2 | 3Axis_SNAP.pde - RepRap cartesian firmware for Arduino 3 | 4 | History: 5 | * (0.1) Created initial version by Zach Smith . 6 | * (0.2) Rewrite by Marius Kintel and Philipp Tiefenbacher 7 | * (0.3) Updated and tested to work with current RepRap host software by Zach Smith 8 | * (0.4) Updated to work the recent optimizations, ie. removal of LimitSwitch by Zach Smith. 9 | * (0.5) Updated with new library changes by Zach Smith. 10 | 11 | License: GPL v2.0 12 | */ 13 | 14 | /******************************** 15 | * digital i/o pin assignment 16 | ********************************/ 17 | 18 | //this uses the undocumented feature of Arduino - pins 14-19 correspond to analog 0-5 19 | #define X_STEP_PIN 2 20 | #define X_DIR_PIN 3 21 | #define X_MIN_PIN 4 22 | #define X_MAX_PIN 5 23 | #define X_ENABLE_PIN 14 24 | #define Y_STEP_PIN 6 25 | #define Y_DIR_PIN 7 26 | #define Y_MIN_PIN 8 27 | #define Y_MAX_PIN 9 28 | #define Y_ENABLE_PIN 15 29 | #define Z_STEP_PIN 10 30 | #define Z_DIR_PIN 11 31 | #define Z_MIN_PIN 12 32 | #define Z_MAX_PIN 13 33 | #define Z_ENABLE_PIN 16 34 | 35 | /******************************** 36 | * how many steps do our motors have? 37 | ********************************/ 38 | #define X_MOTOR_STEPS 400 39 | #define Y_MOTOR_STEPS 400 40 | #define Z_MOTOR_STEPS 400 41 | 42 | CartesianBot bot = CartesianBot( 43 | 'x', X_MOTOR_STEPS, X_DIR_PIN, X_STEP_PIN, X_MIN_PIN, X_MAX_PIN, X_ENABLE_PIN, 44 | 'y', Y_MOTOR_STEPS, Y_DIR_PIN, Y_STEP_PIN, Y_MIN_PIN, Y_MAX_PIN, Y_ENABLE_PIN, 45 | 'z', Z_MOTOR_STEPS, Z_DIR_PIN, Z_STEP_PIN, Z_MIN_PIN, Z_MAX_PIN, Z_ENABLE_PIN 46 | ); 47 | 48 | #include 49 | #include 50 | #include 51 | #include 52 | #include 53 | 54 | void setup() 55 | { 56 | Serial.begin(19200); 57 | 58 | //run any setup code we need. 59 | setup_cartesian_bot_snap_v1(); 60 | } 61 | 62 | void loop() 63 | { 64 | //get our state status / manage our status. 65 | bot.readState(); 66 | 67 | //process our commands 68 | snap.receivePacket(); 69 | if (snap.packetReady()) 70 | process_cartesian_bot_snap_commands_v1(); 71 | } 72 | -------------------------------------------------------------------------------- /Extruder_SNAP/Extruder_SNAP.pde: -------------------------------------------------------------------------------- 1 | /* 2 | Extruder_SNAP.pde - RepRap Thermoplastic Extruder firmware for Arduino 3 | 4 | Main firmware for the extruder (heater, motor and temp. sensor) 5 | 6 | History: 7 | * (0.1) Created intial version by Philipp Tiefenbacher and Marius Kintel 8 | * (0.2) Updated code to properly work with the RepRap host software. 9 | * (0.3) Updated code to work with v1 of the comms protocol and the associated optimizations by Zach Smith. 10 | * (0.4) Updated with new library changes by Zach Smith. 11 | 12 | License: GPL v2.0 13 | */ 14 | 15 | #include 16 | #include 17 | #include 18 | 19 | #define EXTRUDER_MOTOR_SPEED_PIN 3 20 | #define EXTRUDER_MOTOR_DIR_PIN 4 21 | #define EXTRUDER_HEATER_PIN 5 22 | #define EXTRUDER_COOLER_PIN 6 23 | #define EXTRUDER_THERMISTOR_PIN 0 24 | 25 | ThermoplastExtruder extruder(EXTRUDER_MOTOR_DIR_PIN, EXTRUDER_MOTOR_SPEED_PIN, EXTRUDER_HEATER_PIN, EXTRUDER_COOLER_PIN, EXTRUDER_THERMISTOR_PIN); 26 | 27 | #include 28 | 29 | void setup() 30 | { 31 | Serial.begin(19200); 32 | 33 | setup_extruder_snap_v1(); 34 | } 35 | 36 | void loop() 37 | { 38 | //manage our temperature 39 | extruder.manageTemperature(); 40 | 41 | //process our commands 42 | snap.receivePacket(); 43 | if (snap.packetReady()) 44 | process_thermoplast_extruder_snap_commands_v1(); 45 | } 46 | -------------------------------------------------------------------------------- /GCode_Interpreter/GCode_Interpreter.pde: -------------------------------------------------------------------------------- 1 | // Arduino G-code Interpreter 2 | // v1.0 by Mike Ellery - initial software (mellery@gmail.com) 3 | // v1.1 by Zach Hoeken - cleaned up and did lots of tweaks (hoeken@gmail.com) 4 | // v1.2 by Chris Meighan - cleanup / G2&G3 support (cmeighan@gmail.com) 5 | // v1.3 by Zach Hoeken - added thermocouple support and multi-sample temp readings. (hoeken@gmail.com) 6 | #include 7 | 8 | //our command string 9 | #define COMMAND_SIZE 128 10 | char word[COMMAND_SIZE]; 11 | byte serial_count; 12 | int no_data = 0; 13 | 14 | void setup() 15 | { 16 | //Do startup stuff here 17 | Serial.begin(19200); 18 | Serial.println("start"); 19 | 20 | //other initialization. 21 | init_process_string(); 22 | init_steppers(); 23 | init_extruder(); 24 | } 25 | 26 | void loop() 27 | { 28 | char c; 29 | 30 | //keep it hot! 31 | extruder_manage_temperature(); 32 | 33 | //read in characters if we got them. 34 | if (Serial.available() > 0) 35 | { 36 | c = Serial.read(); 37 | no_data = 0; 38 | 39 | //newlines are ends of commands. 40 | if (c != '\n') 41 | { 42 | word[serial_count] = c; 43 | serial_count++; 44 | } 45 | } 46 | //mark no data. 47 | else 48 | { 49 | no_data++; 50 | delayMicroseconds(100); 51 | } 52 | 53 | //if theres a pause or we got a real command, do it 54 | if (serial_count && (c == '\n' || no_data > 100)) 55 | { 56 | //process our command! 57 | process_string(word, serial_count); 58 | 59 | //clear command. 60 | init_process_string(); 61 | } 62 | 63 | //no data? turn off steppers 64 | if (no_data > 1000) 65 | disable_steppers(); 66 | } 67 | -------------------------------------------------------------------------------- /GCode_Interpreter/_init.pde: -------------------------------------------------------------------------------- 1 | 2 | // define the parameters of our machine. 3 | #define X_STEPS_PER_INCH 416.772354 4 | #define X_STEPS_PER_MM 16.4083604 5 | #define X_MOTOR_STEPS 400 6 | 7 | #define Y_STEPS_PER_INCH 416.772354 8 | #define Y_STEPS_PER_MM 16.4083604 9 | #define Y_MOTOR_STEPS 400 10 | 11 | #define Z_STEPS_PER_INCH 16256.0 12 | #define Z_STEPS_PER_MM 640.0 13 | #define Z_MOTOR_STEPS 400 14 | 15 | //our maximum feedrates 16 | #define FAST_XY_FEEDRATE 1000.0 17 | #define FAST_Z_FEEDRATE 50.0 18 | 19 | // Units in curve section 20 | #define CURVE_SECTION_INCHES 0.019685 21 | #define CURVE_SECTION_MM 0.5 22 | 23 | // Set to one if sensor outputs inverting (ie: 1 means open, 0 means closed) 24 | // RepRap opto endstops are *not* inverting. 25 | #define SENSORS_INVERTING 0 26 | 27 | // How many temperature samples to take. each sample takes about 100 usecs. 28 | #define TEMPERATURE_SAMPLES 5 29 | 30 | /**************************************************************************************** 31 | * digital i/o pin assignment 32 | * 33 | * this uses the undocumented feature of Arduino - pins 14-19 correspond to analog 0-5 34 | ****************************************************************************************/ 35 | 36 | //cartesian bot pins 37 | #define X_STEP_PIN 2 38 | #define X_DIR_PIN 3 39 | #define X_MIN_PIN 4 40 | #define X_MAX_PIN 9 41 | #define X_ENABLE_PIN 15 42 | 43 | #define Y_STEP_PIN 10 44 | #define Y_DIR_PIN 7 45 | #define Y_MIN_PIN 8 46 | #define Y_MAX_PIN 13 47 | #define Y_ENABLE_PIN 15 48 | 49 | #define Z_STEP_PIN 19 50 | #define Z_DIR_PIN 18 51 | #define Z_MIN_PIN 17 52 | #define Z_MAX_PIN 16 53 | #define Z_ENABLE_PIN 15 54 | 55 | //extruder pins 56 | #define EXTRUDER_MOTOR_SPEED_PIN 11 57 | #define EXTRUDER_MOTOR_DIR_PIN 12 58 | #define EXTRUDER_HEATER_PIN 6 59 | #define EXTRUDER_FAN_PIN 5 60 | #define EXTRUDER_THERMISTOR_PIN 0 //a -1 disables thermistor readings 61 | #define EXTRUDER_THERMOCOUPLE_PIN -1 //a -1 disables thermocouple readings 62 | -------------------------------------------------------------------------------- /GCode_Interpreter/extruder.pde: -------------------------------------------------------------------------------- 1 | // 2 | // Start of temperature lookup table 3 | // 4 | // Thermistor lookup table for RepRap Temperature Sensor Boards (http://make.rrrf.org/ts) 5 | // Made with createTemperatureLookup.py (http://svn.reprap.org/trunk/reprap/firmware/Arduino/utilities/createTemperatureLookup.py) 6 | // ./createTemperatureLookup.py --r0=100000 --t0=25 --r1=0 --r2=4700 --beta=4066 --max-adc=1023 7 | // r0: 100000 8 | // t0: 25 9 | // r1: 0 10 | // r2: 4700 11 | // beta: 4066 12 | // max adc: 1023 13 | #define NUMTEMPS 20 14 | short temptable[NUMTEMPS][2] = { 15 | {1, 841}, 16 | {54, 255}, 17 | {107, 209}, 18 | {160, 184}, 19 | {213, 166}, 20 | {266, 153}, 21 | {319, 142}, 22 | {372, 132}, 23 | {425, 124}, 24 | {478, 116}, 25 | {531, 108}, 26 | {584, 101}, 27 | {637, 93}, 28 | {690, 86}, 29 | {743, 78}, 30 | {796, 70}, 31 | {849, 61}, 32 | {902, 50}, 33 | {955, 34}, 34 | {1008, 3} 35 | }; 36 | // 37 | // End of temperature lookup table 38 | // 39 | 40 | #define EXTRUDER_FORWARD true 41 | #define EXTRUDER_REVERSE false 42 | 43 | //these our the default values for the extruder. 44 | int extruder_speed = 128; 45 | int extruder_target_celsius = 0; 46 | int extruder_max_celsius = 0; 47 | byte extruder_heater_low = 64; 48 | byte extruder_heater_high = 255; 49 | 50 | //this is for doing encoder based extruder control 51 | int extruder_rpm = 0; 52 | long extruder_delay = 0; 53 | int extruder_error = 0; 54 | int last_extruder_error = 0; 55 | int extruder_error_delta = 0; 56 | bool extruder_direction = EXTRUDER_FORWARD; 57 | 58 | void init_extruder() 59 | { 60 | //default to room temp. 61 | extruder_set_temperature(21); 62 | 63 | //setup our pins 64 | pinMode(EXTRUDER_MOTOR_DIR_PIN, OUTPUT); 65 | pinMode(EXTRUDER_MOTOR_SPEED_PIN, OUTPUT); 66 | pinMode(EXTRUDER_HEATER_PIN, OUTPUT); 67 | pinMode(EXTRUDER_FAN_PIN, OUTPUT); 68 | 69 | //initialize values 70 | digitalWrite(EXTRUDER_MOTOR_DIR_PIN, EXTRUDER_FORWARD); 71 | analogWrite(EXTRUDER_FAN_PIN, 0); 72 | analogWrite(EXTRUDER_HEATER_PIN, 0); 73 | analogWrite(EXTRUDER_MOTOR_SPEED_PIN, 0); 74 | } 75 | 76 | void extruder_set_direction(bool direction) 77 | { 78 | extruder_direction = direction; 79 | digitalWrite(EXTRUDER_MOTOR_DIR_PIN, direction); 80 | } 81 | 82 | void extruder_set_speed(byte speed) 83 | { 84 | analogWrite(EXTRUDER_MOTOR_SPEED_PIN, speed); 85 | } 86 | 87 | void extruder_set_cooler(byte speed) 88 | { 89 | analogWrite(EXTRUDER_FAN_PIN, speed); 90 | } 91 | 92 | void extruder_set_temperature(int temp) 93 | { 94 | extruder_target_celsius = temp; 95 | extruder_max_celsius = (int)((float)temp * 1.1); 96 | } 97 | 98 | /** 99 | * Samples the temperature and converts it to degrees celsius. 100 | * Returns degrees celsius. 101 | */ 102 | int extruder_get_temperature() 103 | { 104 | if (EXTRUDER_THERMISTOR_PIN > -1) 105 | return extruder_read_thermistor(); 106 | else if (EXTRUDER_THERMOCOUPLE_PIN > -1) 107 | return extruder_read_thermocouple(); 108 | } 109 | 110 | /* 111 | * This function gives us the temperature from the thermistor in Celsius 112 | */ 113 | int extruder_read_thermistor() 114 | { 115 | int raw = extruder_sample_temperature(EXTRUDER_THERMISTOR_PIN); 116 | 117 | int celsius = 0; 118 | byte i; 119 | 120 | for (i=1; i raw) 123 | { 124 | celsius = temptable[i-1][1] + 125 | (raw - temptable[i-1][0]) * 126 | (temptable[i][1] - temptable[i-1][1]) / 127 | (temptable[i][0] - temptable[i-1][0]); 128 | 129 | if (celsius > 255) 130 | celsius = 255; 131 | 132 | break; 133 | } 134 | } 135 | 136 | // Overflow: We just clamp to 0 degrees celsius 137 | if (i == NUMTEMPS) 138 | celsius = 0; 139 | 140 | return celsius; 141 | } 142 | 143 | /* 144 | * This function gives us the temperature from the thermocouple in Celsius 145 | */ 146 | int extruder_read_thermocouple() 147 | { 148 | return ( 5.0 * extruder_sample_temperature(EXTRUDER_THERMOCOUPLE_PIN) * 100.0) / 1024.0; 149 | } 150 | 151 | /* 152 | * This function gives us an averaged sample of the analog temperature pin. 153 | */ 154 | int extruder_sample_temperature(byte pin) 155 | { 156 | int raw = 0; 157 | 158 | //read in a certain number of samples 159 | for (byte i=0; i 0) 142 | feedrate_micros = calculate_feedrate_delay(feedrate); 143 | //nope, no feedrate 144 | else 145 | feedrate_micros = getMaxSpeed(); 146 | } 147 | //use our max for normal moves. 148 | else 149 | feedrate_micros = getMaxSpeed(); 150 | } 151 | //nope, just coordinates! 152 | else 153 | { 154 | //do we have a feedrate yet? 155 | if (feedrate > 0) 156 | feedrate_micros = calculate_feedrate_delay(feedrate); 157 | //nope, no feedrate 158 | else 159 | feedrate_micros = getMaxSpeed(); 160 | } 161 | 162 | //finally move. 163 | dda_move(feedrate_micros); 164 | break; 165 | 166 | //Clockwise arc 167 | case 2: 168 | //Counterclockwise arc 169 | case 3: 170 | FloatPoint cent; 171 | 172 | // Centre coordinates are always relative 173 | cent.x = search_string('I', instruction, size) + current_units.x; 174 | cent.y = search_string('J', instruction, size) + current_units.y; 175 | float angleA, angleB, angle, radius, length, aX, aY, bX, bY; 176 | 177 | aX = (current_units.x - cent.x); 178 | aY = (current_units.y - cent.y); 179 | bX = (fp.x - cent.x); 180 | bY = (fp.y - cent.y); 181 | 182 | if (code == 2) { // Clockwise 183 | angleA = atan2(bY, bX); 184 | angleB = atan2(aY, aX); 185 | } else { // Counterclockwise 186 | angleA = atan2(aY, aX); 187 | angleB = atan2(bY, bX); 188 | } 189 | 190 | // Make sure angleB is always greater than angleA 191 | // and if not add 2PI so that it is (this also takes 192 | // care of the special case of angleA == angleB, 193 | // ie we want a complete circle) 194 | if (angleB <= angleA) angleB += 2 * M_PI; 195 | angle = angleB - angleA; 196 | 197 | radius = sqrt(aX * aX + aY * aY); 198 | length = radius * angle; 199 | int steps, s, step; 200 | steps = (int) ceil(length / curve_section); 201 | 202 | FloatPoint newPoint; 203 | for (s = 1; s <= steps; s++) { 204 | step = (code == 3) ? s : steps - s; // Work backwards for CW 205 | newPoint.x = cent.x + radius * cos(angleA + angle * ((float) step / steps)); 206 | newPoint.y = cent.y + radius * sin(angleA + angle * ((float) step / steps)); 207 | set_target(newPoint.x, newPoint.y, fp.z); 208 | 209 | // Need to calculate rate for each section of curve 210 | if (feedrate > 0) 211 | feedrate_micros = calculate_feedrate_delay(feedrate); 212 | else 213 | feedrate_micros = getMaxSpeed(); 214 | 215 | // Make step 216 | dda_move(feedrate_micros); 217 | } 218 | 219 | break; 220 | 221 | //Dwell 222 | case 4: 223 | delay((int)search_string('P', instruction, size)); 224 | break; 225 | 226 | //Inches for Units 227 | case 20: 228 | x_units = X_STEPS_PER_INCH; 229 | y_units = Y_STEPS_PER_INCH; 230 | z_units = Z_STEPS_PER_INCH; 231 | curve_section = CURVE_SECTION_INCHES; 232 | 233 | calculate_deltas(); 234 | break; 235 | 236 | //mm for Units 237 | case 21: 238 | x_units = X_STEPS_PER_MM; 239 | y_units = Y_STEPS_PER_MM; 240 | z_units = Z_STEPS_PER_MM; 241 | curve_section = CURVE_SECTION_MM; 242 | 243 | calculate_deltas(); 244 | break; 245 | 246 | //go home. 247 | case 28: 248 | set_target(0.0, 0.0, 0.0); 249 | dda_move(getMaxSpeed()); 250 | break; 251 | 252 | //go home via an intermediate point. 253 | case 30: 254 | fp.x = search_string('X', instruction, size); 255 | fp.y = search_string('Y', instruction, size); 256 | fp.z = search_string('Z', instruction, size); 257 | 258 | //set our target. 259 | if(abs_mode) 260 | { 261 | if (!has_command('X', instruction, size)) 262 | fp.x = current_units.x; 263 | if (!has_command('Y', instruction, size)) 264 | fp.y = current_units.y; 265 | if (!has_command('Z', instruction, size)) 266 | fp.z = current_units.z; 267 | 268 | set_target(fp.x, fp.y, fp.z); 269 | } 270 | else 271 | set_target(current_units.x + fp.x, current_units.y + fp.y, current_units.z + fp.z); 272 | 273 | //go there. 274 | dda_move(getMaxSpeed()); 275 | 276 | //go home. 277 | set_target(0.0, 0.0, 0.0); 278 | dda_move(getMaxSpeed()); 279 | break; 280 | 281 | //Absolute Positioning 282 | case 90: 283 | abs_mode = true; 284 | break; 285 | 286 | //Incremental Positioning 287 | case 91: 288 | abs_mode = false; 289 | break; 290 | 291 | //Set as home 292 | case 92: 293 | set_position(0.0, 0.0, 0.0); 294 | break; 295 | 296 | /* 297 | //Inverse Time Feed Mode 298 | case 93: 299 | 300 | break; //TODO: add this 301 | 302 | //Feed per Minute Mode 303 | case 94: 304 | 305 | break; //TODO: add this 306 | */ 307 | 308 | default: 309 | Serial.print("huh? G"); 310 | Serial.println(code,DEC); 311 | } 312 | } 313 | 314 | //find us an m code. 315 | if (has_command('M', instruction, size)) 316 | { 317 | code = search_string('M', instruction, size); 318 | switch (code) 319 | { 320 | //TODO: this is a bug because search_string returns 0. gotta fix that. 321 | case 0: 322 | true; 323 | break; 324 | /* 325 | case 0: 326 | //todo: stop program 327 | break; 328 | 329 | case 1: 330 | //todo: optional stop 331 | break; 332 | 333 | case 2: 334 | //todo: program end 335 | break; 336 | */ 337 | //set max extruder speed, 0-255 PWM 338 | case 100: 339 | extruder_speed = (int)(search_string('P', instruction, size)); 340 | break; 341 | 342 | //turn extruder on, forward 343 | case 101: 344 | extruder_set_direction(1); 345 | extruder_set_speed(extruder_speed); 346 | break; 347 | 348 | //turn extruder on, reverse 349 | case 102: 350 | extruder_set_direction(0); 351 | extruder_set_speed(extruder_speed); 352 | break; 353 | 354 | //turn extruder off 355 | case 103: 356 | extruder_set_speed(0); 357 | break; 358 | 359 | //custom code for temperature control 360 | case 104: 361 | extruder_set_temperature((int)search_string('P', instruction, size)); 362 | 363 | //warmup if we're too cold. 364 | while (extruder_get_temperature() < extruder_target_celsius) 365 | { 366 | extruder_manage_temperature(); 367 | Serial.print("T:"); 368 | Serial.println(extruder_get_temperature()); 369 | delay(1000); 370 | } 371 | 372 | break; 373 | 374 | //custom code for temperature reading 375 | case 105: 376 | Serial.print("T:"); 377 | Serial.println(extruder_get_temperature()); 378 | break; 379 | 380 | //turn fan on 381 | case 106: 382 | extruder_set_cooler(255); 383 | break; 384 | 385 | //turn fan off 386 | case 107: 387 | extruder_set_cooler(0); 388 | break; 389 | 390 | default: 391 | Serial.print("Huh? M"); 392 | Serial.println(code); 393 | } 394 | } 395 | 396 | //tell our host we're done. 397 | Serial.println("ok"); 398 | // Serial.println(line, DEC); 399 | } 400 | 401 | //look for the number that appears after the char key and return it 402 | double search_string(char key, char instruction[], int string_size) 403 | { 404 | char temp[10] = ""; 405 | 406 | for (byte i=0; i= 16383) 69 | milli_delay = micro_delay / 1000; 70 | else 71 | milli_delay = 0; 72 | 73 | //do our DDA line! 74 | do 75 | { 76 | x_can_step = can_step(X_MIN_PIN, X_MAX_PIN, current_steps.x, target_steps.x, x_direction); 77 | y_can_step = can_step(Y_MIN_PIN, Y_MAX_PIN, current_steps.y, target_steps.y, y_direction); 78 | z_can_step = can_step(Z_MIN_PIN, Z_MAX_PIN, current_steps.z, target_steps.z, z_direction); 79 | 80 | if (x_can_step) 81 | { 82 | x_counter += delta_steps.x; 83 | 84 | if (x_counter > 0) 85 | { 86 | do_step(X_STEP_PIN); 87 | x_counter -= max_delta; 88 | 89 | if (x_direction) 90 | current_steps.x++; 91 | else 92 | current_steps.x--; 93 | } 94 | } 95 | 96 | if (y_can_step) 97 | { 98 | y_counter += delta_steps.y; 99 | 100 | if (y_counter > 0) 101 | { 102 | do_step(Y_STEP_PIN); 103 | y_counter -= max_delta; 104 | 105 | if (y_direction) 106 | current_steps.y++; 107 | else 108 | current_steps.y--; 109 | } 110 | } 111 | 112 | if (z_can_step) 113 | { 114 | z_counter += delta_steps.z; 115 | 116 | if (z_counter > 0) 117 | { 118 | do_step(Z_STEP_PIN); 119 | z_counter -= max_delta; 120 | 121 | if (z_direction) 122 | current_steps.z++; 123 | else 124 | current_steps.z--; 125 | } 126 | } 127 | 128 | extruder_manage_temperature(); 129 | 130 | //wait for next step. 131 | if (milli_delay > 0) 132 | delay(milli_delay); 133 | else 134 | delayMicroseconds(micro_delay); 135 | } 136 | while (x_can_step || y_can_step || z_can_step); 137 | 138 | //set our points to be the same 139 | current_units.x = target_units.x; 140 | current_units.y = target_units.y; 141 | current_units.z = target_units.z; 142 | calculate_deltas(); 143 | } 144 | 145 | bool can_step(byte min_pin, byte max_pin, long current, long target, byte direction) 146 | { 147 | //stop us if we're on target 148 | if (target == current) 149 | return false; 150 | //stop us if we're at home and still going 151 | else if (read_switch(min_pin) && !direction) 152 | return false; 153 | //stop us if we're at max and still going 154 | else if (read_switch(max_pin) && direction) 155 | return false; 156 | 157 | //default to being able to step 158 | return true; 159 | } 160 | 161 | void do_step(byte step_pin) 162 | { 163 | digitalWrite(step_pin, HIGH); 164 | delayMicroseconds(5); 165 | digitalWrite(step_pin, LOW); 166 | } 167 | 168 | bool read_switch(byte pin) 169 | { 170 | //dual read as crude debounce 171 | 172 | if ( SENSORS_INVERTING ) 173 | return !digitalRead(pin) && !digitalRead(pin); 174 | else 175 | return digitalRead(pin) && digitalRead(pin); 176 | } 177 | 178 | long to_steps(float steps_per_unit, float units) 179 | { 180 | return steps_per_unit * units; 181 | } 182 | 183 | void set_target(float x, float y, float z) 184 | { 185 | target_units.x = x; 186 | target_units.y = y; 187 | target_units.z = z; 188 | 189 | calculate_deltas(); 190 | } 191 | 192 | void set_position(float x, float y, float z) 193 | { 194 | current_units.x = x; 195 | current_units.y = y; 196 | current_units.z = z; 197 | 198 | calculate_deltas(); 199 | } 200 | 201 | void calculate_deltas() 202 | { 203 | //figure our deltas. 204 | delta_units.x = abs(target_units.x - current_units.x); 205 | delta_units.y = abs(target_units.y - current_units.y); 206 | delta_units.z = abs(target_units.z - current_units.z); 207 | 208 | //set our steps current, target, and delta 209 | current_steps.x = to_steps(x_units, current_units.x); 210 | current_steps.y = to_steps(y_units, current_units.y); 211 | current_steps.z = to_steps(z_units, current_units.z); 212 | 213 | target_steps.x = to_steps(x_units, target_units.x); 214 | target_steps.y = to_steps(y_units, target_units.y); 215 | target_steps.z = to_steps(z_units, target_units.z); 216 | 217 | delta_steps.x = abs(target_steps.x - current_steps.x); 218 | delta_steps.y = abs(target_steps.y - current_steps.y); 219 | delta_steps.z = abs(target_steps.z - current_steps.z); 220 | 221 | //what is our direction 222 | x_direction = (target_units.x >= current_units.x); 223 | y_direction = (target_units.y >= current_units.y); 224 | z_direction = (target_units.z >= current_units.z); 225 | 226 | //set our direction pins as well 227 | digitalWrite(X_DIR_PIN, x_direction); 228 | digitalWrite(Y_DIR_PIN, y_direction); 229 | digitalWrite(Z_DIR_PIN, z_direction); 230 | } 231 | 232 | 233 | long calculate_feedrate_delay(float feedrate) 234 | { 235 | //how long is our line length? 236 | float distance = sqrt(delta_units.x*delta_units.x + delta_units.y*delta_units.y + delta_units.z*delta_units.z); 237 | long master_steps = 0; 238 | 239 | //find the dominant axis. 240 | if (delta_steps.x > delta_steps.y) 241 | { 242 | if (delta_steps.z > delta_steps.x) 243 | master_steps = delta_steps.z; 244 | else 245 | master_steps = delta_steps.x; 246 | } 247 | else 248 | { 249 | if (delta_steps.z > delta_steps.y) 250 | master_steps = delta_steps.z; 251 | else 252 | master_steps = delta_steps.y; 253 | } 254 | 255 | //calculate delay between steps in microseconds. this is sort of tricky, but not too bad. 256 | //the formula has been condensed to save space. here it is in english: 257 | // distance / feedrate * 60000000.0 = move duration in microseconds 258 | // move duration / master_steps = time between steps for master axis. 259 | 260 | return ((distance * 60000000.0) / feedrate) / master_steps; 261 | } 262 | 263 | long getMaxSpeed() 264 | { 265 | if (delta_steps.z > 0) 266 | return calculate_feedrate_delay(FAST_Z_FEEDRATE); 267 | else 268 | return calculate_feedrate_delay(FAST_XY_FEEDRATE); 269 | } 270 | 271 | void disable_steppers() 272 | { 273 | //enable our steppers 274 | digitalWrite(X_ENABLE_PIN, LOW); 275 | digitalWrite(Y_ENABLE_PIN, LOW); 276 | digitalWrite(Z_ENABLE_PIN, LOW); 277 | } 278 | -------------------------------------------------------------------------------- /GCode_Interpreter_Experimental/GCode_Interpreter_Experimental.pde: -------------------------------------------------------------------------------- 1 | // Arduino G-code Interpreter 2 | // v1.0 by Mike Ellery - initial software (mellery@gmail.com) 3 | // v1.1 by Zach Smith - cleaned up and did lots of tweaks (hoeken@gmail.com) 4 | // v1.2 by Chris Meighan - cleanup / G2&G3 support (cmeighan@gmail.com) 5 | // v1.3 by Zach Smith - added thermocouple support and multi-sample temp readings. (hoeken@gmail.com) 6 | // also added preliminary and experimental support for rotary encoders. 7 | 8 | #include 9 | 10 | //our command string 11 | #define COMMAND_SIZE 128 12 | char word[COMMAND_SIZE]; 13 | byte serial_count; 14 | int no_data = 0; 15 | 16 | void setup() 17 | { 18 | //Do startup stuff here 19 | Serial.begin(19200); 20 | Serial.println("start"); 21 | 22 | //other initialization. 23 | init_process_string(); 24 | init_steppers(); 25 | init_extruder(); 26 | } 27 | 28 | void loop() 29 | { 30 | char c; 31 | 32 | //keep it hot! 33 | extruder_manage_temperature(); 34 | 35 | //read in characters if we got them. 36 | if (Serial.available() > 0) 37 | { 38 | c = Serial.read(); 39 | no_data = 0; 40 | 41 | //newlines are ends of commands. 42 | if (c != '\n') 43 | { 44 | word[serial_count] = c; 45 | serial_count++; 46 | } 47 | } 48 | //mark no data. 49 | else 50 | { 51 | no_data++; 52 | delayMicroseconds(100); 53 | } 54 | 55 | //if theres a pause or we got a real command, do it 56 | if (serial_count && (c == '\n' || no_data > 100)) 57 | { 58 | //process our command! 59 | process_string(word, serial_count); 60 | 61 | //clear command. 62 | init_process_string(); 63 | } 64 | 65 | //no data? turn off steppers 66 | if (no_data > 1000) 67 | disable_steppers(); 68 | } 69 | -------------------------------------------------------------------------------- /GCode_Interpreter_Experimental/_init.pde: -------------------------------------------------------------------------------- 1 | 2 | // define the parameters of our machine. 3 | #define X_STEPS_PER_INCH 416.772354 4 | #define X_STEPS_PER_MM 16.4083604 5 | #define X_MOTOR_STEPS 400 6 | 7 | #define Y_STEPS_PER_INCH 416.772354 8 | #define Y_STEPS_PER_MM 16.4083604 9 | #define Y_MOTOR_STEPS 400 10 | 11 | #define Z_STEPS_PER_INCH 16256.0 12 | #define Z_STEPS_PER_MM 640.0 13 | #define Z_MOTOR_STEPS 400 14 | 15 | //our maximum feedrates 16 | #define FAST_XY_FEEDRATE 1000.0 17 | #define FAST_Z_FEEDRATE 50.0 18 | 19 | // Units in curve section 20 | #define CURVE_SECTION_INCHES 0.019685 21 | #define CURVE_SECTION_MM 0.5 22 | 23 | // Set to one if sensor outputs inverting (ie: 1 means open, 0 means closed) 24 | // RepRap opto endstops are *not* inverting. 25 | #define SENSORS_INVERTING 0 26 | 27 | // How many temperature samples to take. each sample takes about 100 usecs. 28 | #define TEMPERATURE_SAMPLES 5 29 | 30 | //these defines are for using rotary encoders on the extruder 31 | #define EXTRUDER_ENCODER_STEPS 512 //number of steps per revolution 32 | #define EXTRUDER_MIN_SPEED 50 //minimum PWM speed to use 33 | #define EXTRUDER_MAX_SPEED 255 //maximum PWM speed to use 34 | #define EXTRUDER_ERROR_MARGIN 10 //our error margin (to prevent constant seeking) 35 | #define INVERT_QUADRATURE 0 // 1 = inverted, 0 = not inverted 36 | 37 | /**************************************************************************************** 38 | * digital i/o pin assignment 39 | * 40 | * this uses the undocumented feature of Arduino - pins 14-19 correspond to analog 0-5 41 | ****************************************************************************************/ 42 | 43 | //cartesian bot pins 44 | #define X_STEP_PIN 7 45 | #define X_DIR_PIN 8 46 | #define X_MIN_PIN 14 47 | #define X_MAX_PIN 17 48 | #define X_ENABLE_PIN 18 49 | 50 | #define Y_STEP_PIN 9 51 | #define Y_DIR_PIN 10 52 | #define Y_MIN_PIN 15 53 | #define Y_MAX_PIN 17 54 | #define Y_ENABLE_PIN 18 55 | 56 | #define Z_STEP_PIN 12 57 | #define Z_DIR_PIN 13 58 | #define Z_MIN_PIN 16 59 | #define Z_MAX_PIN 17 60 | #define Z_ENABLE_PIN 18 61 | 62 | //extruder pins 63 | #define EXTRUDER_ENCODER_A_PIN 2 //quadrature a pin 64 | #define EXTRUDER_ENCODER_B_PIN 3 //quadrature b pin 65 | #define EXTRUDER_MOTOR_DIR_PIN 4 66 | #define EXTRUDER_MOTOR_SPEED_PIN 5 67 | #define EXTRUDER_HEATER_PIN 6 68 | #define EXTRUDER_FAN_PIN 11 69 | #define EXTRUDER_THERMISTOR_PIN 5 //a -1 disables thermistor readings 70 | #define EXTRUDER_THERMOCOUPLE_PIN -1 //a -1 disables thermocouple readings 71 | -------------------------------------------------------------------------------- /GCode_Interpreter_Experimental/extruder.pde: -------------------------------------------------------------------------------- 1 | // 2 | // Start of temperature lookup table 3 | // 4 | // Thermistor lookup table for RepRap Temperature Sensor Boards (http://make.rrrf.org/ts) 5 | // Made with createTemperatureLookup.py (http://svn.reprap.org/trunk/reprap/firmware/Arduino/utilities/createTemperatureLookup.py) 6 | // ./createTemperatureLookup.py --r0=100000 --t0=25 --r1=0 --r2=4700 --beta=4066 --max-adc=1023 7 | // r0: 100000 8 | // t0: 25 9 | // r1: 0 10 | // r2: 4700 11 | // beta: 4066 12 | // max adc: 1023 13 | #define NUMTEMPS 20 14 | short temptable[NUMTEMPS][2] = { 15 | {1, 841}, 16 | {54, 255}, 17 | {107, 209}, 18 | {160, 184}, 19 | {213, 166}, 20 | {266, 153}, 21 | {319, 142}, 22 | {372, 132}, 23 | {425, 124}, 24 | {478, 116}, 25 | {531, 108}, 26 | {584, 101}, 27 | {637, 93}, 28 | {690, 86}, 29 | {743, 78}, 30 | {796, 70}, 31 | {849, 61}, 32 | {902, 50}, 33 | {955, 34}, 34 | {1008, 3} 35 | }; 36 | // 37 | // End of temperature lookup table 38 | // 39 | 40 | #define EXTRUDER_FORWARD true 41 | #define EXTRUDER_REVERSE false 42 | 43 | //these our the default values for the extruder. 44 | int extruder_target_celsius = 0; 45 | int extruder_max_celsius = 0; 46 | byte extruder_heater_low = 64; 47 | byte extruder_heater_high = 255; 48 | 49 | //this is for doing encoder based extruder control 50 | volatile bool extruder_direction = EXTRUDER_FORWARD; 51 | volatile int extruder_error = 0; 52 | 53 | //these keep track of extruder speed, etc. 54 | int extruder_rpm = 0; 55 | long extruder_delay = 0; 56 | 57 | //for our closed loop control 58 | int last_extruder_error = 0; 59 | int last_extruder_delta = 0; 60 | int last_extruder_speed = 0; 61 | 62 | void extruder_read_quadrature() 63 | { 64 | // found a low-to-high on channel A 65 | if (digitalRead(EXTRUDER_ENCODER_A_PIN) == HIGH) 66 | { 67 | // check channel B to see which way 68 | if (digitalRead(EXTRUDER_ENCODER_B_PIN) == LOW) 69 | { 70 | if (INVERT_QUADRATURE) 71 | extruder_error--; 72 | else 73 | extruder_error++; 74 | } 75 | else 76 | { 77 | if (INVERT_QUADRATURE) 78 | extruder_error++; 79 | else 80 | extruder_error--; 81 | } 82 | } 83 | // found a high-to-low on channel A 84 | else 85 | { 86 | // check channel B to see which way 87 | if (digitalRead(EXTRUDER_ENCODER_B_PIN) == LOW) 88 | { 89 | if (INVERT_QUADRATURE) 90 | extruder_error++; 91 | else 92 | extruder_error--; 93 | } 94 | else 95 | { 96 | if (INVERT_QUADRATURE) 97 | extruder_error--; 98 | else 99 | extruder_error++; 100 | } 101 | } 102 | } 103 | 104 | void init_extruder() 105 | { 106 | //default to room temp. 107 | extruder_set_temperature(21); 108 | 109 | //setup our pins 110 | pinMode(EXTRUDER_MOTOR_DIR_PIN, OUTPUT); 111 | pinMode(EXTRUDER_MOTOR_SPEED_PIN, OUTPUT); 112 | pinMode(EXTRUDER_HEATER_PIN, OUTPUT); 113 | pinMode(EXTRUDER_FAN_PIN, OUTPUT); 114 | 115 | //initialize values 116 | digitalWrite(EXTRUDER_MOTOR_DIR_PIN, EXTRUDER_FORWARD); 117 | analogWrite(EXTRUDER_FAN_PIN, 0); 118 | analogWrite(EXTRUDER_HEATER_PIN, 0); 119 | analogWrite(EXTRUDER_MOTOR_SPEED_PIN, 0); 120 | 121 | //setup our encoder interrupt stuff. 122 | //these pins are inputs 123 | pinMode(EXTRUDER_ENCODER_A_PIN, INPUT); 124 | pinMode(EXTRUDER_ENCODER_B_PIN, INPUT); 125 | 126 | //turn on internal pullups 127 | digitalWrite(EXTRUDER_ENCODER_A_PIN, HIGH); 128 | digitalWrite(EXTRUDER_ENCODER_A_PIN, HIGH); 129 | 130 | //attach our interrupt handlers 131 | attachInterrupt(0, extruder_read_quadrature, CHANGE); 132 | 133 | //setup our timer interrupt stuff 134 | setupTimer1Interrupt(); 135 | disableTimer1Interrupt(); 136 | } 137 | 138 | void extruder_set_direction(bool direction) 139 | { 140 | extruder_direction = direction; 141 | } 142 | 143 | void extruder_set_cooler(byte speed) 144 | { 145 | analogWrite(EXTRUDER_FAN_PIN, speed); 146 | } 147 | 148 | void extruder_set_temperature(int temp) 149 | { 150 | extruder_target_celsius = temp; 151 | extruder_max_celsius = (int)((float)temp * 1.1); 152 | } 153 | 154 | /** 155 | * Samples the temperature and converts it to degrees celsius. 156 | * Returns degrees celsius. 157 | */ 158 | int extruder_get_temperature() 159 | { 160 | if (EXTRUDER_THERMISTOR_PIN > -1) 161 | return extruder_read_thermistor(); 162 | else if (EXTRUDER_THERMOCOUPLE_PIN > -1) 163 | return extruder_read_thermocouple(); 164 | } 165 | 166 | /* 167 | * This function gives us the temperature from the thermistor in Celsius 168 | */ 169 | int extruder_read_thermistor() 170 | { 171 | int raw = extruder_sample_temperature(EXTRUDER_THERMISTOR_PIN); 172 | 173 | int celsius = 0; 174 | byte i; 175 | 176 | for (i=1; i raw) 179 | { 180 | celsius = temptable[i-1][1] + 181 | (raw - temptable[i-1][0]) * 182 | (temptable[i][1] - temptable[i-1][1]) / 183 | (temptable[i][0] - temptable[i-1][0]); 184 | 185 | if (celsius > 255) 186 | celsius = 255; 187 | 188 | break; 189 | } 190 | } 191 | 192 | // Overflow: We just clamp to 0 degrees celsius 193 | if (i == NUMTEMPS) 194 | celsius = 0; 195 | 196 | return celsius; 197 | } 198 | 199 | /* 200 | * This function gives us the temperature from the thermocouple in Celsius 201 | */ 202 | int extruder_read_thermocouple() 203 | { 204 | return ( 5.0 * extruder_sample_temperature(EXTRUDER_THERMOCOUPLE_PIN) * 100.0) / 1024.0; 205 | } 206 | 207 | /* 208 | * This function gives us an averaged sample of the analog temperature pin. 209 | */ 210 | int extruder_sample_temperature(byte pin) 211 | { 212 | int raw = 0; 213 | 214 | //read in a certain number of samples 215 | for (byte i=0; i 0) 261 | digitalWrite(EXTRUDER_MOTOR_DIR_PIN, EXTRUDER_REVERSE); 262 | else if (extruder_error < 0) 263 | digitalWrite(EXTRUDER_MOTOR_DIR_PIN, EXTRUDER_FORWARD); 264 | 265 | //send us off at that speed! 266 | if (abs(extruder_error) > EXTRUDER_ERROR_MARGIN) 267 | analogWrite(EXTRUDER_MOTOR_SPEED_PIN, speed); 268 | else 269 | analogWrite(EXTRUDER_MOTOR_SPEED_PIN, 0); 270 | 271 | //save our last error. 272 | last_extruder_error = extruder_error; 273 | last_extruder_delta = extruder_error_delta; 274 | last_extruder_speed = speed; 275 | } 276 | 277 | 278 | /*! 279 | Manages motor and heater based on measured temperature: 280 | o If temp is too low, don't start the motor 281 | o Adjust the heater power to keep the temperature at the target 282 | */ 283 | void extruder_manage_temperature() 284 | { 285 | //make sure we know what our temp is. 286 | int current_celsius = extruder_get_temperature(); 287 | 288 | //put the heater into high mode if we're not at our target. 289 | if (current_celsius < extruder_target_celsius) 290 | analogWrite(EXTRUDER_HEATER_PIN, extruder_heater_high); 291 | //put the heater on low if we're at our target. 292 | else if (current_celsius < extruder_max_celsius) 293 | analogWrite(EXTRUDER_HEATER_PIN, extruder_heater_low); 294 | //turn the heater off if we're above our max. 295 | else 296 | analogWrite(EXTRUDER_HEATER_PIN, 0); 297 | 298 | extruder_manage_speed(); 299 | } 300 | 301 | -------------------------------------------------------------------------------- /GCode_Interpreter_Experimental/interrupt_routines.pde: -------------------------------------------------------------------------------- 1 | //these routines provide an easy interface for controlling timer1 interrupts 2 | 3 | //this handles the timer interrupt event 4 | SIGNAL(SIG_OUTPUT_COMPARE1A) 5 | { 6 | //increment/decrement our error variable. 7 | //the manage extruder function will handle the motor control 8 | if (extruder_direction == EXTRUDER_FORWARD) 9 | extruder_error--; 10 | else 11 | extruder_error++; 12 | } 13 | 14 | void enableTimer1Interrupt() 15 | { 16 | //enable our interrupt! 17 | TIMSK1 |= (1< 0) 142 | feedrate_micros = calculate_feedrate_delay(feedrate); 143 | //nope, no feedrate 144 | else 145 | feedrate_micros = getMaxSpeed(); 146 | } 147 | //use our max for normal moves. 148 | else 149 | feedrate_micros = getMaxSpeed(); 150 | } 151 | //nope, just coordinates! 152 | else 153 | { 154 | //do we have a feedrate yet? 155 | if (feedrate > 0) 156 | feedrate_micros = calculate_feedrate_delay(feedrate); 157 | //nope, no feedrate 158 | else 159 | feedrate_micros = getMaxSpeed(); 160 | } 161 | 162 | //finally move. 163 | dda_move(feedrate_micros); 164 | break; 165 | 166 | //Clockwise arc 167 | case 2: 168 | //Counterclockwise arc 169 | case 3: 170 | FloatPoint cent; 171 | 172 | // Centre coordinates are always relative 173 | cent.x = search_string('I', instruction, size) + current_units.x; 174 | cent.y = search_string('J', instruction, size) + current_units.y; 175 | float angleA, angleB, angle, radius, length, aX, aY, bX, bY; 176 | 177 | aX = (current_units.x - cent.x); 178 | aY = (current_units.y - cent.y); 179 | bX = (fp.x - cent.x); 180 | bY = (fp.y - cent.y); 181 | 182 | if (code == 2) { // Clockwise 183 | angleA = atan2(bY, bX); 184 | angleB = atan2(aY, aX); 185 | } else { // Counterclockwise 186 | angleA = atan2(aY, aX); 187 | angleB = atan2(bY, bX); 188 | } 189 | 190 | // Make sure angleB is always greater than angleA 191 | // and if not add 2PI so that it is (this also takes 192 | // care of the special case of angleA == angleB, 193 | // ie we want a complete circle) 194 | if (angleB <= angleA) angleB += 2 * M_PI; 195 | angle = angleB - angleA; 196 | 197 | radius = sqrt(aX * aX + aY * aY); 198 | length = radius * angle; 199 | int steps, s, step; 200 | steps = (int) ceil(length / curve_section); 201 | 202 | FloatPoint newPoint; 203 | for (s = 1; s <= steps; s++) { 204 | step = (code == 3) ? s : steps - s; // Work backwards for CW 205 | newPoint.x = cent.x + radius * cos(angleA + angle * ((float) step / steps)); 206 | newPoint.y = cent.y + radius * sin(angleA + angle * ((float) step / steps)); 207 | set_target(newPoint.x, newPoint.y, fp.z); 208 | 209 | // Need to calculate rate for each section of curve 210 | if (feedrate > 0) 211 | feedrate_micros = calculate_feedrate_delay(feedrate); 212 | else 213 | feedrate_micros = getMaxSpeed(); 214 | 215 | // Make step 216 | dda_move(feedrate_micros); 217 | } 218 | 219 | break; 220 | 221 | //Dwell 222 | case 4: 223 | delay((int)search_string('P', instruction, size)); 224 | break; 225 | 226 | //Inches for Units 227 | case 20: 228 | x_units = X_STEPS_PER_INCH; 229 | y_units = Y_STEPS_PER_INCH; 230 | z_units = Z_STEPS_PER_INCH; 231 | curve_section = CURVE_SECTION_INCHES; 232 | 233 | calculate_deltas(); 234 | break; 235 | 236 | //mm for Units 237 | case 21: 238 | x_units = X_STEPS_PER_MM; 239 | y_units = Y_STEPS_PER_MM; 240 | z_units = Z_STEPS_PER_MM; 241 | curve_section = CURVE_SECTION_MM; 242 | 243 | calculate_deltas(); 244 | break; 245 | 246 | //go home. 247 | case 28: 248 | set_target(0.0, 0.0, 0.0); 249 | dda_move(getMaxSpeed()); 250 | break; 251 | 252 | //go home via an intermediate point. 253 | case 30: 254 | fp.x = search_string('X', instruction, size); 255 | fp.y = search_string('Y', instruction, size); 256 | fp.z = search_string('Z', instruction, size); 257 | 258 | //set our target. 259 | if(abs_mode) 260 | { 261 | if (!has_command('X', instruction, size)) 262 | fp.x = current_units.x; 263 | if (!has_command('Y', instruction, size)) 264 | fp.y = current_units.y; 265 | if (!has_command('Z', instruction, size)) 266 | fp.z = current_units.z; 267 | 268 | set_target(fp.x, fp.y, fp.z); 269 | } 270 | else 271 | set_target(current_units.x + fp.x, current_units.y + fp.y, current_units.z + fp.z); 272 | 273 | //go there. 274 | dda_move(getMaxSpeed()); 275 | 276 | //go home. 277 | set_target(0.0, 0.0, 0.0); 278 | dda_move(getMaxSpeed()); 279 | break; 280 | 281 | //Absolute Positioning 282 | case 90: 283 | abs_mode = true; 284 | break; 285 | 286 | //Incremental Positioning 287 | case 91: 288 | abs_mode = false; 289 | break; 290 | 291 | //Set as home 292 | case 92: 293 | set_position(0.0, 0.0, 0.0); 294 | break; 295 | 296 | /* 297 | //Inverse Time Feed Mode 298 | case 93: 299 | 300 | break; //TODO: add this 301 | 302 | //Feed per Minute Mode 303 | case 94: 304 | 305 | break; //TODO: add this 306 | */ 307 | 308 | default: 309 | Serial.print("huh? G"); 310 | Serial.println(code,DEC); 311 | } 312 | } 313 | 314 | //find us an m code. 315 | if (has_command('M', instruction, size)) 316 | { 317 | code = search_string('M', instruction, size); 318 | switch (code) 319 | { 320 | //TODO: this is a bug because search_string returns 0. gotta fix that. 321 | case 0: 322 | true; 323 | break; 324 | /* 325 | case 0: 326 | //todo: stop program 327 | break; 328 | 329 | case 1: 330 | //todo: optional stop 331 | break; 332 | 333 | case 2: 334 | //todo: program end 335 | break; 336 | */ 337 | //set max extruder speed, 0-255 PWM 338 | case 100: 339 | extruder_rpm = (int)search_string('P', instruction, size); 340 | extruder_delay = (960000000UL / EXTRUDER_ENCODER_STEPS) / extruder_rpm; 341 | setTimer1Ticks(extruder_delay); 342 | break; 343 | 344 | //turn extruder on, forward 345 | case 101: 346 | extruder_set_direction(1); 347 | enableTimer1Interrupt(); 348 | break; 349 | 350 | //turn extruder on, reverse 351 | case 102: 352 | extruder_set_direction(0); 353 | enableTimer1Interrupt(); 354 | break; 355 | 356 | //turn extruder off 357 | case 103: 358 | disableTimer1Interrupt(); 359 | break; 360 | 361 | //custom code for temperature control 362 | case 104: 363 | extruder_set_temperature((int)search_string('P', instruction, size)); 364 | 365 | //warmup if we're too cold. 366 | while (extruder_get_temperature() < extruder_target_celsius) 367 | { 368 | extruder_manage_temperature(); 369 | Serial.print("T:"); 370 | Serial.println(extruder_get_temperature()); 371 | delay(1000); 372 | } 373 | 374 | break; 375 | 376 | //custom code for temperature reading 377 | case 105: 378 | Serial.print("T:"); 379 | Serial.println(extruder_get_temperature()); 380 | break; 381 | 382 | //turn fan on 383 | case 106: 384 | extruder_set_cooler(255); 385 | break; 386 | 387 | //turn fan off 388 | case 107: 389 | extruder_set_cooler(0); 390 | break; 391 | 392 | default: 393 | Serial.print("Huh? M"); 394 | Serial.println(code); 395 | } 396 | } 397 | 398 | //tell our host we're done. 399 | Serial.println("ok"); 400 | // Serial.println(line, DEC); 401 | } 402 | 403 | //look for the number that appears after the char key and return it 404 | double search_string(char key, char instruction[], int string_size) 405 | { 406 | char temp[10] = ""; 407 | 408 | for (byte i=0; i= 16383) 69 | milli_delay = micro_delay / 1000; 70 | else 71 | milli_delay = 0; 72 | 73 | /* 74 | Serial.print("max:"); 75 | Serial.println(max_delta, DEC); 76 | Serial.print("xd:"); 77 | Serial.println(delta_steps.x, DEC); 78 | Serial.print("yd:"); 79 | Serial.println(delta_steps.y, DEC); 80 | Serial.print("zd:"); 81 | Serial.println(delta_steps.z, DEC); 82 | 83 | Serial.print("msec:"); 84 | Serial.println(millis, DEC); 85 | Serial.print("usec:"); 86 | Serial.println(micro_delay, DEC); 87 | */ 88 | //do our DDA line! 89 | do 90 | { 91 | x_can_step = can_step(X_MIN_PIN, X_MAX_PIN, current_steps.x, target_steps.x, x_direction); 92 | y_can_step = can_step(Y_MIN_PIN, Y_MAX_PIN, current_steps.y, target_steps.y, y_direction); 93 | z_can_step = can_step(Z_MIN_PIN, Z_MAX_PIN, current_steps.z, target_steps.z, z_direction); 94 | 95 | if (x_can_step) 96 | { 97 | x_counter += delta_steps.x; 98 | 99 | if (x_counter > 0) 100 | { 101 | do_step(X_STEP_PIN); 102 | x_counter -= max_delta; 103 | 104 | if (x_direction) 105 | current_steps.x++; 106 | else 107 | current_steps.x--; 108 | } 109 | } 110 | 111 | if (y_can_step) 112 | { 113 | y_counter += delta_steps.y; 114 | 115 | if (y_counter > 0) 116 | { 117 | do_step(Y_STEP_PIN); 118 | y_counter -= max_delta; 119 | 120 | if (y_direction) 121 | current_steps.y++; 122 | else 123 | current_steps.y--; 124 | } 125 | } 126 | 127 | if (z_can_step) 128 | { 129 | z_counter += delta_steps.z; 130 | 131 | if (z_counter > 0) 132 | { 133 | do_step(Z_STEP_PIN); 134 | z_counter -= max_delta; 135 | 136 | if (z_direction) 137 | current_steps.z++; 138 | else 139 | current_steps.z--; 140 | } 141 | } 142 | 143 | extruder_manage_temperature(); 144 | 145 | //wait for next step. 146 | if (milli_delay > 0) 147 | delay(milli_delay); 148 | else 149 | delayMicroseconds(micro_delay); 150 | } 151 | while (x_can_step || y_can_step || z_can_step); 152 | 153 | //set our points to be the same 154 | current_units.x = target_units.x; 155 | current_units.y = target_units.y; 156 | current_units.z = target_units.z; 157 | calculate_deltas(); 158 | } 159 | 160 | bool can_step(byte min_pin, byte max_pin, long current, long target, byte direction) 161 | { 162 | //stop us if we're on target 163 | if (target == current) 164 | return false; 165 | //stop us if we're at home and still going 166 | else if (read_switch(min_pin) && !direction) 167 | return false; 168 | //stop us if we're at max and still going 169 | else if (read_switch(max_pin) && direction) 170 | return false; 171 | 172 | //default to being able to step 173 | return true; 174 | } 175 | 176 | void do_step(byte step_pin) 177 | { 178 | digitalWrite(step_pin, HIGH); 179 | delayMicroseconds(5); 180 | digitalWrite(step_pin, LOW); 181 | } 182 | 183 | bool read_switch(byte pin) 184 | { 185 | //dual read as crude debounce 186 | 187 | if ( SENSORS_INVERTING ) 188 | return !digitalRead(pin) && !digitalRead(pin); 189 | else 190 | return digitalRead(pin) && digitalRead(pin); 191 | } 192 | 193 | long to_steps(float steps_per_unit, float units) 194 | { 195 | return steps_per_unit * units; 196 | } 197 | 198 | void set_target(float x, float y, float z) 199 | { 200 | target_units.x = x; 201 | target_units.y = y; 202 | target_units.z = z; 203 | 204 | calculate_deltas(); 205 | } 206 | 207 | void set_position(float x, float y, float z) 208 | { 209 | current_units.x = x; 210 | current_units.y = y; 211 | current_units.z = z; 212 | 213 | calculate_deltas(); 214 | } 215 | 216 | void calculate_deltas() 217 | { 218 | //figure our deltas. 219 | delta_units.x = abs(target_units.x - current_units.x); 220 | delta_units.y = abs(target_units.y - current_units.y); 221 | delta_units.z = abs(target_units.z - current_units.z); 222 | 223 | //set our steps current, target, and delta 224 | current_steps.x = to_steps(x_units, current_units.x); 225 | current_steps.y = to_steps(y_units, current_units.y); 226 | current_steps.z = to_steps(z_units, current_units.z); 227 | 228 | target_steps.x = to_steps(x_units, target_units.x); 229 | target_steps.y = to_steps(y_units, target_units.y); 230 | target_steps.z = to_steps(z_units, target_units.z); 231 | 232 | delta_steps.x = abs(target_steps.x - current_steps.x); 233 | delta_steps.y = abs(target_steps.y - current_steps.y); 234 | delta_steps.z = abs(target_steps.z - current_steps.z); 235 | 236 | //what is our direction 237 | x_direction = (target_units.x >= current_units.x); 238 | y_direction = (target_units.y >= current_units.y); 239 | z_direction = (target_units.z >= current_units.z); 240 | 241 | //set our direction pins as well 242 | digitalWrite(X_DIR_PIN, x_direction); 243 | digitalWrite(Y_DIR_PIN, y_direction); 244 | digitalWrite(Z_DIR_PIN, z_direction); 245 | } 246 | 247 | 248 | long calculate_feedrate_delay(float feedrate) 249 | { 250 | //how long is our line length? 251 | float distance = sqrt(delta_units.x*delta_units.x + delta_units.y*delta_units.y + delta_units.z*delta_units.z); 252 | long master_steps = 0; 253 | 254 | //find the dominant axis. 255 | if (delta_steps.x > delta_steps.y) 256 | { 257 | if (delta_steps.z > delta_steps.x) 258 | master_steps = delta_steps.z; 259 | else 260 | master_steps = delta_steps.x; 261 | } 262 | else 263 | { 264 | if (delta_steps.z > delta_steps.y) 265 | master_steps = delta_steps.z; 266 | else 267 | master_steps = delta_steps.y; 268 | } 269 | 270 | //calculate delay between steps in microseconds. this is sort of tricky, but not too bad. 271 | //the formula has been condensed to save space. here it is in english: 272 | // distance / feedrate * 60000000.0 = move duration in microseconds 273 | // move duration / master_steps = time between steps for master axis. 274 | 275 | return ((distance * 60000000.0) / feedrate) / master_steps; 276 | } 277 | 278 | long getMaxSpeed() 279 | { 280 | if (delta_steps.z > 0) 281 | return calculate_feedrate_delay(FAST_Z_FEEDRATE); 282 | else 283 | return calculate_feedrate_delay(FAST_XY_FEEDRATE); 284 | } 285 | 286 | void disable_steppers() 287 | { 288 | //enable our steppers 289 | digitalWrite(X_ENABLE_PIN, LOW); 290 | digitalWrite(Y_ENABLE_PIN, LOW); 291 | digitalWrite(Z_ENABLE_PIN, LOW); 292 | } 293 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc., 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Lesser General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | 294 | Copyright (C) 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License along 307 | with this program; if not, write to the Free Software Foundation, Inc., 308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 309 | 310 | Also add information on how to contact you by electronic and paper mail. 311 | 312 | If the program is interactive, make it output a short notice like this 313 | when it starts in an interactive mode: 314 | 315 | Gnomovision version 69, Copyright (C) year name of author 316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 317 | This is free software, and you are welcome to redistribute it 318 | under certain conditions; type `show c' for details. 319 | 320 | The hypothetical commands `show w' and `show c' should show the appropriate 321 | parts of the General Public License. Of course, the commands you use may 322 | be called something other than `show w' and `show c'; they could even be 323 | mouse-clicks or menu items--whatever suits your program. 324 | 325 | You should also get your employer (if you work as a programmer) or your 326 | school, if any, to sign a "copyright disclaimer" for the program, if 327 | necessary. Here is a sample; alter the names: 328 | 329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 330 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 331 | 332 | , 1 April 1989 333 | Ty Coon, President of Vice 334 | 335 | This General Public License does not permit incorporating your program into 336 | proprietary programs. If your program is a subroutine library, you may 337 | consider it more useful to permit linking proprietary applications with the 338 | library. If this is what you want to do, use the GNU Lesser General 339 | Public License instead of this License. 340 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | This zip file contains firmware and libraries designed to run on an Arduino, or Arduino clone. It contains all the files you should need to get everything up and running, as well as some test firmware to let you test various parts of your system. 2 | 3 | All documentation on the electronics themselves are located at http://make.rrrf.org/electronics-2.0 4 | 5 | Here is an explanation of the various files contained: 6 | 7 | /library 8 | 9 | all the folders contained in this directory need to be copied into the library folder of your Arduino installation. on Arduino 10, this is arduino-0010/hardware/libraries. 10 | 11 | /snap 12 | 13 | these are the firmwares that you would actually upload to the Arduino itself. each folder is a 'sketch' that you open with the Arduino software and load onto your board. the top of each file contains pin definitions that will help you hook up your electronics to your Arduino. 14 | 15 | /gcode 16 | 17 | this folder contains some experimental software that implements GCode on the Arduino! 18 | 19 | /gcode/GCode_Interpreter 20 | 21 | this firmware receives and parses GCode commands over serial. pretty rad. 22 | 23 | /gcode/GCode_Interpreter_Experimental 24 | 25 | this is an experimental gcode based firmware with support for a rotary encoder on the extruder 26 | 27 | /snap/3Axis_SNAP 28 | 29 | this is the firmware that controls 3 stepper motors + limit switches on one Arduino. this is for 2 arduino setups where one firmware controls the cartesian bot and the other controls the extruder(s) 30 | 31 | /snap/Extruder_SNAP 32 | 33 | this is the firmware that controls a Thermoplastic Extruder. this is the corresponding firmware for a 2 arduino setup. 34 | 35 | /snap/Single_Arduino_SNAP 36 | 37 | this is the firmware that controls both the Cartesian Bot (3 steppers + limit switches) as well as a Thermoplastic Extruder. This is the firmware you use for a single Arduino setup. its pretty much maxed out. 38 | -------------------------------------------------------------------------------- /Single_Arduino_SNAP/Single_Arduino_SNAP.pde: -------------------------------------------------------------------------------- 1 | /* 2 | Single_Arduino_SNAP.pde - Combined cartesian bot + extruder firmware. 3 | 4 | History: 5 | * (0.1) Created initial version by Zach Smith. 6 | * (0.2) Updated to work with the various optimizations and extruder emulation by Zach Smith 7 | * (0.3) Updated with new library changes by Zach Smith. 8 | 9 | License: GPL v2.0 10 | */ 11 | 12 | /**************************************************************************************** 13 | * digital i/o pin assignment 14 | * 15 | * this uses the undocumented feature of Arduino - pins 14-19 correspond to analog 0-5 16 | ****************************************************************************************/ 17 | 18 | //cartesian bot pins 19 | #define X_STEP_PIN 2 20 | #define X_DIR_PIN 3 21 | #define X_MIN_PIN 4 22 | #define X_MAX_PIN 9 23 | #define X_ENABLE_PIN 15 24 | #define Y_STEP_PIN 10 25 | #define Y_DIR_PIN 7 26 | #define Y_MIN_PIN 8 27 | #define Y_MAX_PIN 13 28 | #define Y_ENABLE_PIN 15 29 | #define Z_STEP_PIN 19 30 | #define Z_DIR_PIN 18 31 | #define Z_MIN_PIN 17 32 | #define Z_MAX_PIN 16 33 | #define Z_ENABLE_PIN 15 34 | 35 | //extruder pins 36 | #define EXTRUDER_MOTOR_SPEED_PIN 11 37 | #define EXTRUDER_MOTOR_DIR_PIN 12 38 | #define EXTRUDER_HEATER_PIN 6 39 | #define EXTRUDER_FAN_PIN 5 40 | #define EXTRUDER_THERMISTOR_PIN 0 41 | #define VALVE_DIR_PIN 15 42 | #define VALVE_ENABLE_PIN 16 //NB: Conflicts with Max Z!!!! 43 | 44 | // how many steps do our motors have? 45 | #define X_MOTOR_STEPS 400 46 | #define Y_MOTOR_STEPS 400 47 | #define Z_MOTOR_STEPS 400 48 | 49 | //our library includes. 50 | #include 51 | #include 52 | #include 53 | #include 54 | #include 55 | #include 56 | #include 57 | #include 58 | 59 | ThermoplastExtruder extruder(EXTRUDER_MOTOR_DIR_PIN, EXTRUDER_MOTOR_SPEED_PIN, EXTRUDER_HEATER_PIN, 60 | EXTRUDER_FAN_PIN, EXTRUDER_THERMISTOR_PIN, VALVE_DIR_PIN, VALVE_ENABLE_PIN); 61 | 62 | CartesianBot bot = CartesianBot( 63 | 'x', X_MOTOR_STEPS, X_DIR_PIN, X_STEP_PIN, X_MIN_PIN, X_MAX_PIN, X_ENABLE_PIN, 64 | 'y', Y_MOTOR_STEPS, Y_DIR_PIN, Y_STEP_PIN, Y_MIN_PIN, Y_MAX_PIN, Y_ENABLE_PIN, 65 | 'z', Z_MOTOR_STEPS, Z_DIR_PIN, Z_STEP_PIN, Z_MIN_PIN, Z_MAX_PIN, Z_ENABLE_PIN 66 | ); 67 | 68 | void setup() 69 | { 70 | snap.begin(19200); 71 | 72 | //run any setup code we need. 73 | setup_cartesian_bot_snap_v1(); 74 | setup_extruder_snap_v1(); 75 | 76 | snap.debug(); 77 | Serial.println("BEGIN"); 78 | } 79 | 80 | void loop() 81 | { 82 | //do the loop commands. 83 | cartesian_bot_snap_v1_loop(); 84 | extruder.manageTemperature(); 85 | 86 | //process our commands 87 | if (snap.packetReady()) 88 | { 89 | //who is it for? 90 | byte dest = snap.getDestination(); 91 | 92 | //route the command to the proper object. 93 | if (dest == EXTRUDER_ADDRESS) 94 | process_thermoplast_extruder_snap_commands_v1(); 95 | else if(dest == X_ADDRESS || dest == Y_ADDRESS || dest == Z_ADDRESS) 96 | process_cartesian_bot_snap_commands_v1(); 97 | 98 | snap.releaseLock(); 99 | } 100 | else 101 | snap.receivePacket(); 102 | } 103 | -------------------------------------------------------------------------------- /Single_Arduino_SNAP_v2/Single_Arduino_SNAP_v2.pde: -------------------------------------------------------------------------------- 1 | /* 2 | Single_Arduino_SNAP_v2.pde - 2nd Generation RepRap Protocol 3 | 4 | History: 5 | * (0.1) Created initial version by Zach Smith. 6 | 7 | License: GPL v2.0 8 | */ 9 | 10 | //our library includes. 11 | #include 12 | #include 13 | 14 | void setup() 15 | { 16 | snap.begin(19200); 17 | 18 | init_steppers(); 19 | init_extruder(); 20 | init_process_snap(); 21 | } 22 | 23 | void loop() 24 | { 25 | extruder_manage_temperature(); 26 | process_snap_packet(); 27 | } 28 | -------------------------------------------------------------------------------- /Single_Arduino_SNAP_v2/_init.pde: -------------------------------------------------------------------------------- 1 | /**************************************************************************************** 2 | * digital i/o pin assignment 3 | * 4 | * this uses the undocumented feature of Arduino - pins 14-19 correspond to analog 0-5 5 | ****************************************************************************************/ 6 | 7 | //cartesian bot pins 8 | #define X_STEP_PIN 2 9 | #define X_DIR_PIN 3 10 | #define X_MIN_PIN 4 11 | #define X_MAX_PIN 9 12 | #define X_ENABLE_PIN 15 13 | #define Y_STEP_PIN 10 14 | #define Y_DIR_PIN 7 15 | #define Y_MIN_PIN 8 16 | #define Y_MAX_PIN 13 17 | #define Y_ENABLE_PIN 15 18 | #define Z_STEP_PIN 19 19 | #define Z_DIR_PIN 18 20 | #define Z_MIN_PIN 17 21 | #define Z_MAX_PIN 16 22 | #define Z_ENABLE_PIN 15 23 | 24 | //extruder pins 25 | #define EXTRUDER_MOTOR_SPEED_PIN 11 26 | #define EXTRUDER_MOTOR_DIR_PIN 12 27 | #define EXTRUDER_HEATER_PIN 6 28 | #define EXTRUDER_FAN_PIN 5 29 | #define EXTRUDER_THERMISTOR_PIN 0 30 | 31 | // Set to one if sensor outputs inverting (ie: 1 means open, 0 means closed) 32 | // RepRap opto endstops are *not* inverting. 33 | #define SENSORS_INVERTING 0 34 | 35 | // How many temperature samples to take. each sample takes about 100 usecs. 36 | #define TEMPERATURE_SAMPLES 5 -------------------------------------------------------------------------------- /Single_Arduino_SNAP_v2/extruder.pde: -------------------------------------------------------------------------------- 1 | // 2 | // Start of temperature lookup table 3 | // 4 | #define NUMTEMPS 20 5 | short temptable[NUMTEMPS][2] = { 6 | // { adc , temp } 7 | { 1 , 929 } , 8 | { 54 , 266 } , 9 | { 107 , 217 } , 10 | { 160 , 190 } , 11 | { 213 , 172 } , 12 | { 266 , 158 } , 13 | { 319 , 146 } , 14 | { 372 , 136 } , 15 | { 425 , 127 } , 16 | { 478 , 119 } , 17 | { 531 , 111 } , 18 | { 584 , 103 } , 19 | { 637 , 96 } , 20 | { 690 , 88 } , 21 | { 743 , 80 } , 22 | { 796 , 71 } , 23 | { 849 , 62 } , 24 | { 902 , 50 } , 25 | { 955 , 34 } , 26 | { 1008 , 2 } 27 | }; 28 | // 29 | // End of temperature lookup table 30 | // 31 | 32 | //these our the default values for the extruder. 33 | int extruder_speed = 128; 34 | int extruder_target_celsius = 0; 35 | int extruder_max_celsius = 0; 36 | byte extruder_heater_low = 64; 37 | byte extruder_heater_high = 255; 38 | 39 | void init_extruder() 40 | { 41 | //default to room temp. 42 | extruder_set_temperature(21); 43 | 44 | pinMode(EXTRUDER_MOTOR_DIR_PIN, OUTPUT); 45 | pinMode(EXTRUDER_MOTOR_SPEED_PIN, OUTPUT); 46 | pinMode(EXTRUDER_HEATER_PIN, OUTPUT); 47 | } 48 | 49 | void extruder_set_direction(byte direction) 50 | { 51 | digitalWrite(EXTRUDER_MOTOR_DIR_PIN, direction); 52 | } 53 | 54 | void extruder_set_speed(byte speed) 55 | { 56 | analogWrite(EXTRUDER_MOTOR_SPEED_PIN, speed); 57 | } 58 | 59 | void extruder_set_cooler(byte speed) 60 | { 61 | analogWrite(EXTRUDER_FAN_PIN, speed); 62 | } 63 | 64 | void extruder_set_temperature(int temp) 65 | { 66 | extruder_target_celsius = temp; 67 | extruder_max_celsius = (int)((float)temp * 1.1); 68 | } 69 | 70 | /** 71 | * Samples the temperature and converts it to degrees celsius. 72 | * Returns degrees celsius. 73 | */ 74 | int extruder_get_temperature() 75 | { 76 | if (EXTRUDER_THERMISTOR_PIN > -1) 77 | return extruder_read_thermistor(); 78 | else if (EXTRUDER_THERMOCOUPLE_PIN > -1) 79 | return extruder_read_thermocouple(); 80 | } 81 | 82 | /* 83 | * This function gives us the temperature from the thermistor in Celsius 84 | */ 85 | int extruder_read_thermistor() 86 | { 87 | int raw = extruder_sample_temperature(EXTRUDER_THERMISTOR_PIN); 88 | 89 | int celsius = 0; 90 | byte i; 91 | 92 | for (i=1; i raw) 95 | { 96 | celsius = temptable[i-1][1] + 97 | (raw - temptable[i-1][0]) * 98 | (temptable[i][1] - temptable[i-1][1]) / 99 | (temptable[i][0] - temptable[i-1][0]); 100 | 101 | if (celsius > 255) 102 | celsius = 255; 103 | 104 | break; 105 | } 106 | } 107 | 108 | // Overflow: We just clamp to 0 degrees celsius 109 | if (i == NUMTEMPS) 110 | celsius = 0; 111 | 112 | return celsius; 113 | } 114 | 115 | /* 116 | * This function gives us the temperature from the thermocouple in Celsius 117 | */ 118 | int extruder_read_thermocouple() 119 | { 120 | return ( 5.0 * extruder_sample_temperature(EXTRUDER_THERMOCOUPLE_PIN) * 100.0) / 1024.0; 121 | } 122 | 123 | /* 124 | * This function gives us an averaged sample of the analog temperature pin. 125 | */ 126 | int extruder_sample_temperature(byte pin) 127 | { 128 | int raw = 0; 129 | 130 | //read in a certain number of samples 131 | for (byte i=0; i= 16383) 65 | milli_delay = micro_delay / 1000; 66 | else 67 | milli_delay = 0; 68 | 69 | /* 70 | Serial.print("max:"); 71 | Serial.println(max_delta, DEC); 72 | Serial.print("xd:"); 73 | Serial.println(delta_steps.x, DEC); 74 | Serial.print("yd:"); 75 | Serial.println(delta_steps.y, DEC); 76 | Serial.print("zd:"); 77 | Serial.println(delta_steps.z, DEC); 78 | 79 | Serial.print("msec:"); 80 | Serial.println(millis, DEC); 81 | Serial.print("usec:"); 82 | Serial.println(micro_delay, DEC); 83 | */ 84 | //do our DDA line! 85 | do 86 | { 87 | x_can_step = can_step(X_MIN_PIN, X_MAX_PIN, current_steps.x, target_steps.x, x_direction); 88 | y_can_step = can_step(Y_MIN_PIN, Y_MAX_PIN, current_steps.y, target_steps.y, y_direction); 89 | z_can_step = can_step(Z_MIN_PIN, Z_MAX_PIN, current_steps.z, target_steps.z, z_direction); 90 | 91 | if (x_can_step) 92 | { 93 | x_counter += delta_steps.x; 94 | 95 | if (x_counter > 0) 96 | { 97 | do_step(X_STEP_PIN); 98 | x_counter -= max_delta; 99 | 100 | if (x_direction) 101 | current_steps.x++; 102 | else 103 | current_steps.x--; 104 | } 105 | } 106 | 107 | if (y_can_step) 108 | { 109 | y_counter += delta_steps.y; 110 | 111 | if (y_counter > 0) 112 | { 113 | do_step(Y_STEP_PIN); 114 | y_counter -= max_delta; 115 | 116 | if (y_direction) 117 | current_steps.y++; 118 | else 119 | current_steps.y--; 120 | } 121 | } 122 | 123 | if (z_can_step) 124 | { 125 | z_counter += delta_steps.z; 126 | 127 | if (z_counter > 0) 128 | { 129 | do_step(Z_STEP_PIN); 130 | z_counter -= max_delta; 131 | 132 | if (z_direction) 133 | current_steps.z++; 134 | else 135 | current_steps.z--; 136 | } 137 | } 138 | 139 | extruder_manage_temperature(); 140 | 141 | //wait for next step. 142 | if (milli_delay > 0) 143 | delay(milli_delay); 144 | else 145 | delayMicroseconds(micro_delay); 146 | } 147 | while (x_can_step || y_can_step || z_can_step); 148 | 149 | //set our points to be the same 150 | current_units.x = target_units.x; 151 | current_units.y = target_units.y; 152 | current_units.z = target_units.z; 153 | calculate_deltas(); 154 | } 155 | 156 | bool can_step(byte min_pin, byte max_pin, long current, long target, byte direction) 157 | { 158 | //stop us if we're on target 159 | if (target == current) 160 | return false; 161 | //stop us if we're at home and still going 162 | else if (read_switch(min_pin) && !direction) 163 | return false; 164 | //stop us if we're at max and still going 165 | else if (read_switch(max_pin) && direction) 166 | return false; 167 | 168 | //default to being able to step 169 | return true; 170 | } 171 | 172 | void do_step(byte step_pin) 173 | { 174 | digitalWrite(step_pin, HIGH); 175 | delayMicroseconds(5); 176 | digitalWrite(step_pin, LOW); 177 | } 178 | 179 | bool read_switch(byte pin) 180 | { 181 | //dual read as crude debounce 182 | 183 | if ( SENSORS_INVERTING ) 184 | return !digitalRead(pin) && !digitalRead(pin); 185 | else 186 | return digitalRead(pin) && digitalRead(pin); 187 | } 188 | 189 | void set_target(float x, float y, float z) 190 | { 191 | target.x = x; 192 | target.y = y; 193 | target.z = z; 194 | 195 | calculate_deltas(); 196 | } 197 | 198 | void set_position(float x, float y, float z) 199 | { 200 | current.x = x; 201 | current.y = y; 202 | current.z = z; 203 | 204 | calculate_deltas(); 205 | } 206 | 207 | void calculate_deltas() 208 | { 209 | //figure our deltas. 210 | delta.x = abs(target.x - current.x); 211 | delta.y = abs(target.y - current.y); 212 | delta.z = abs(target.z - current.z); 213 | 214 | //what is our direction 215 | x_direction = (target_units.x >= current_units.x); 216 | y_direction = (target_units.y >= current_units.y); 217 | z_direction = (target_units.z >= current_units.z); 218 | 219 | //set our direction pins as well 220 | digitalWrite(X_DIR_PIN, x_direction); 221 | digitalWrite(Y_DIR_PIN, y_direction); 222 | digitalWrite(Z_DIR_PIN, z_direction); 223 | } 224 | 225 | void disable_steppers() 226 | { 227 | //enable our steppers 228 | digitalWrite(X_ENABLE_PIN, LOW); 229 | digitalWrite(Y_ENABLE_PIN, LOW); 230 | digitalWrite(Z_ENABLE_PIN, LOW); 231 | } 232 | -------------------------------------------------------------------------------- /library/AnalogEncoder/AnalogEncoder.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "WConstants.h" 3 | #include "AnalogEncoder.h" 4 | 5 | AnalogEncoder::AnalogEncoder(int pin) 6 | { 7 | this->pin = pin; 8 | this->current_position = -1; 9 | this->last_position = -1; 10 | this->direction = -1; 11 | } 12 | 13 | //our interface methods 14 | void AnalogEncoder::readState() 15 | { 16 | this->last_position = this->current_position; 17 | this->current_position = analogRead(this->pin); 18 | 19 | if (this->current_position < 16) 20 | { 21 | if (this->last_position > 768) 22 | this->direction = 1; 23 | else 24 | this->direction = 0; 25 | } 26 | else if (this->current_position > 1008) 27 | { 28 | if (this->last_position < 256) 29 | this->direction = 0; 30 | else 31 | this->direction = 1; 32 | } 33 | else 34 | { 35 | if (this->current_position > this->last_position) 36 | this->direction = 1; 37 | else 38 | this->direction = 0; 39 | } 40 | } 41 | 42 | int AnalogEncoder::getPosition() 43 | { 44 | return this->current_position; 45 | } 46 | 47 | int AnalogEncoder::getDirection() 48 | { 49 | return this->direction; 50 | } 51 | 52 | int AnalogEncoder::version() 53 | { 54 | return 1; 55 | } 56 | -------------------------------------------------------------------------------- /library/AnalogEncoder/AnalogEncoder.h: -------------------------------------------------------------------------------- 1 | /* 2 | AnalogEncoder.h - RepRap Encoder library for Arduino 3 | 4 | This library is used to interface with an Austria Microsystems magnetic encoder in analog mode. 5 | 6 | History: 7 | * Created intiial library (0.1) by Zach Smith. 8 | 9 | */ 10 | 11 | // ensure this library description is only included once 12 | #ifndef AnalogEncoder_h 13 | #define AnalogEncoder_h 14 | 15 | // include types & constants of Wiring core API 16 | #include "WConstants.h" 17 | 18 | // library interface description 19 | class AnalogEncoder { 20 | public: 21 | 22 | // constructors: 23 | AnalogEncoder(); 24 | AnalogEncoder(int pin); 25 | 26 | //our interface methods 27 | void readState(); 28 | int getPosition(); 29 | int getDirection(); 30 | 31 | int version(); 32 | 33 | private: 34 | 35 | int pin; //the switch state pin. 36 | int current_position; //the current position on last read. 37 | int last_position; //the position before our current read. 38 | int direction; //the direction the encoder is moving. 39 | }; 40 | 41 | #endif 42 | -------------------------------------------------------------------------------- /library/AnalogEncoder/keywords.txt: -------------------------------------------------------------------------------- 1 | ####################################### 2 | # Syntax Coloring Map For Test 3 | ####################################### 4 | 5 | ####################################### 6 | # Datatypes (KEYWORD1) 7 | ####################################### 8 | 9 | LimitSwitch KEYWORD1 10 | 11 | ####################################### 12 | # Methods and Functions (KEYWORD2) 13 | ####################################### 14 | 15 | getState KEYWORD2 16 | readState KEYWORD2 17 | version KEYWORD2 18 | 19 | 20 | ###################################### 21 | # Instances (KEYWORD2) 22 | ####################################### 23 | 24 | 25 | ####################################### 26 | # Constants (LITERAL1) 27 | ####################################### 28 | 29 | -------------------------------------------------------------------------------- /library/CartesianBot/CartesianBot.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "WConstants.h" 3 | #include "CartesianBot.h" 4 | 5 | CartesianBot::CartesianBot( 6 | char x_id, int x_steps, byte x_dir_pin, byte x_step_pin, byte x_min_pin, byte x_max_pin, byte x_enable_pin, 7 | char y_id, int y_steps, byte y_dir_pin, byte y_step_pin, byte y_min_pin, byte y_max_pin, byte y_enable_pin, 8 | char z_id, int z_steps, byte z_dir_pin, byte z_step_pin, byte z_min_pin, byte z_max_pin, byte z_enable_pin 9 | ) : x(x_id, x_steps, x_dir_pin, x_step_pin, x_min_pin, x_max_pin, x_enable_pin), y(y_id, y_steps, y_dir_pin, y_step_pin, y_min_pin, y_max_pin, y_enable_pin), z(z_id, z_steps, z_dir_pin, z_step_pin, z_min_pin, z_max_pin, z_enable_pin) 10 | { 11 | this->setupTimerInterrupt(); 12 | this->disableTimerInterrupt(); 13 | this->clearQueue(); 14 | } 15 | 16 | byte CartesianBot::getQueueSize() 17 | { 18 | return this->size; 19 | } 20 | 21 | bool CartesianBot::isQueueEmpty() 22 | { 23 | return (this->size == 0); 24 | } 25 | 26 | bool CartesianBot::isQueueFull() 27 | { 28 | return (this->size == POINT_QUEUE_SIZE); 29 | } 30 | 31 | bool CartesianBot::queuePoint(Point &point) 32 | { 33 | if (this->isQueueFull()) 34 | return false; 35 | 36 | //queue up our point (at the old tail spot)! 37 | this->point_queue[this->tail] = point; 38 | 39 | //keep track 40 | this->size++; 41 | 42 | //move our tail to the next tail location 43 | this->tail++; 44 | if (this->tail == POINT_QUEUE_SIZE) 45 | this->tail = 0; 46 | 47 | return true; 48 | } 49 | 50 | struct Point CartesianBot::unqueuePoint() 51 | { 52 | //save our old head. 53 | byte oldHead = this->head; 54 | 55 | //move our head to the head for next time. 56 | this->head++; 57 | if (this->head == POINT_QUEUE_SIZE) 58 | this->head = 0; 59 | 60 | //keep track. 61 | this->size--; 62 | 63 | return this->point_queue[oldHead]; 64 | } 65 | 66 | void CartesianBot::clearQueue() 67 | { 68 | this->head = 0; 69 | this->tail = 0; 70 | this->size = 0; 71 | } 72 | 73 | void CartesianBot::getNextPoint() 74 | { 75 | Point p; 76 | 77 | if (!this->isQueueEmpty()) 78 | { 79 | p = this->unqueuePoint(); 80 | 81 | x.setTarget(p.x); 82 | y.setTarget(p.y); 83 | z.setTarget(p.z); 84 | } 85 | else 86 | { 87 | x.setTarget(x.current); 88 | y.setTarget(y.current); 89 | z.setTarget(z.current); 90 | } 91 | } 92 | 93 | void CartesianBot::calculateDDA() 94 | { 95 | //let us do the maths before stepping. 96 | this->disableTimerInterrupt(); 97 | 98 | //what is the biggest one? 99 | this->max_delta = max(x.delta, y.delta); 100 | this->max_delta = max(this->max_delta, z.delta); 101 | 102 | //calculate speeds for each axis. 103 | x.initDDA(this->max_delta); 104 | y.initDDA(this->max_delta); 105 | z.initDDA(this->max_delta); 106 | } 107 | 108 | bool CartesianBot::atHome() 109 | { 110 | return (x.atMin() && y.atMin() && z.atMin()); 111 | } 112 | 113 | void CartesianBot::readState() 114 | { 115 | x.readState(); 116 | y.readState(); 117 | z.readState(); 118 | } 119 | 120 | bool CartesianBot::atTarget() 121 | { 122 | return x.atTarget() && y.atTarget() && z.atTarget(); 123 | } 124 | 125 | void CartesianBot::setupTimerInterrupt() 126 | { 127 | //clear the registers 128 | TCCR1A = 0; 129 | TCCR1B = 0; 130 | TCCR1C = 0; 131 | TIMSK1 = 0; 132 | 133 | //waveform generation = 0100 = CTC 134 | TCCR1B &= ~(1<setTimerResolution(4); 147 | this->setTimerCeiling(65535); 148 | } 149 | 150 | void CartesianBot::enableTimerInterrupt() 151 | { 152 | //reset our timer to 0 for reliable timing TODO: is this needed? 153 | //TCNT1 = 0; 154 | 155 | //then enable our interrupt! 156 | TIMSK1 |= (1<disableTimerInterrupt(); 230 | this->setTimerCeiling(this->getTimerCeiling(delay)); 231 | this->setTimerResolution(this->getTimerResolution(delay)); 232 | //this->enableTimerInterrupt(); 233 | } 234 | 235 | unsigned int CartesianBot::getTimerCeiling(unsigned long delay) 236 | { 237 | // our slowest speed at our highest resolution ( (2^16-1) * 0.0625 usecs = 4095 usecs) 238 | if (delay <= 65535L) 239 | return (delay & 0xffff); 240 | // our slowest speed at our next highest resolution ( (2^16-1) * 0.5 usecs = 32767 usecs) 241 | else if (delay <= 524280L) 242 | return ((delay / 8) & 0xffff); 243 | // our slowest speed at our medium resolution ( (2^16-1) * 4 usecs = 262140 usecs) 244 | else if (delay <= 4194240L) 245 | return ((delay / 64) & 0xffff); 246 | // our slowest speed at our medium-low resolution ( (2^16-1) * 16 usecs = 1048560 usecs) 247 | else if (delay <= 16776960L) 248 | return (delay / 256); 249 | // our slowest speed at our lowest resolution ((2^16-1) * 64 usecs = 4194240 usecs) 250 | else if (delay <= 67107840L) 251 | return (delay / 1024); 252 | //its really slow... hopefully we can just get by with super slow. 253 | else 254 | return 65535; 255 | } 256 | 257 | byte CartesianBot::getTimerResolution(unsigned long delay) 258 | { 259 | // these also represent frequency: 1000000 / delay / 2 = frequency in hz. 260 | 261 | // our slowest speed at our highest resolution ( (2^16-1) * 0.0625 usecs = 4095 usecs (4 millisecond max)) 262 | // range: 8Mhz max - 122hz min 263 | if (delay <= 65535L) 264 | return 0; 265 | // our slowest speed at our next highest resolution ( (2^16-1) * 0.5 usecs = 32767 usecs (32 millisecond max)) 266 | // range:1Mhz max - 15.26hz min 267 | else if (delay <= 524280L) 268 | return 1; 269 | // our slowest speed at our medium resolution ( (2^16-1) * 4 usecs = 262140 usecs (0.26 seconds max)) 270 | // range: 125Khz max - 1.9hz min 271 | else if (delay <= 4194240L) 272 | return 2; 273 | // our slowest speed at our medium-low resolution ( (2^16-1) * 16 usecs = 1048560 usecs (1.04 seconds max)) 274 | // range: 31.25Khz max - 0.475hz min 275 | else if (delay <= 16776960L) 276 | return 3; 277 | // our slowest speed at our lowest resolution ((2^16-1) * 64 usecs = 4194240 usecs (4.19 seconds max)) 278 | // range: 7.812Khz max - 0.119hz min 279 | else if (delay <= 67107840L) 280 | return 4; 281 | //its really slow... hopefully we can just get by with super slow. 282 | else 283 | return 4; 284 | } 285 | -------------------------------------------------------------------------------- /library/CartesianBot/CartesianBot.h: -------------------------------------------------------------------------------- 1 | /* 2 | CartesianBot.h - RepRap Cartesian Bot library for Arduino 3 | 4 | This library is used to interface with a RepRap Cartesian Bot (3 axis X/Y/Z machine) 5 | 6 | Memory Usage Estimate: 8 + 12 * POINT_QUEUE_SIZE + 3 * LinearAxis usage. 7 | 8 | History: 9 | * (0.1) Ceated initial library by Zach Smith. 10 | * (0.2) Optimized for smaller size and speed by Zach Smith. 11 | * (0.3) Rewrote and refactored all code. Fixed major interrupt bug by Zach Smith. Special thanks to Marius Kintel for finding the bug. 12 | 13 | License: GPL v2.0 14 | */ 15 | 16 | // ensure this library description is only included once 17 | #ifndef CartesianBot_h 18 | #define CartesianBot_h 19 | 20 | //#include "HardwareSerial.h" 21 | #include "LinearAxis.h" 22 | #include "RepStepper.h" 23 | #include "WConstants.h" 24 | 25 | // how big do we want our point queue? 26 | #define POINT_QUEUE_SIZE 16 27 | 28 | // our point structure to make things nice. 29 | struct Point { 30 | int x; 31 | int y; 32 | int z; 33 | }; 34 | 35 | // library interface description 36 | class CartesianBot { 37 | public: 38 | 39 | // constructors: 40 | CartesianBot( 41 | char x_id, int x_steps, byte x_dir_pin, byte x_step_pin, byte x_min_pin, byte x_max_pin, byte x_enable_pin, 42 | char y_id, int y_steps, byte y_dir_pin, byte y_step_pin, byte y_min_pin, byte y_max_pin, byte y_enable_pin, 43 | char z_id, int z_steps, byte z_dir_pin, byte z_step_pin, byte z_min_pin, byte z_max_pin, byte z_enable_pin 44 | ); 45 | 46 | // our queue stuff 47 | bool queuePoint(Point &point); 48 | struct Point unqueuePoint(); 49 | void clearQueue(); 50 | bool isQueueFull(); 51 | bool isQueueEmpty(); 52 | byte getQueueSize(); 53 | 54 | //cartesian bot specific. 55 | void setTargetPoint(Point &point); 56 | void setCurrentPoint(Point &point); 57 | void getNextPoint(); 58 | void calculateDDA(); 59 | bool atTarget(); 60 | bool atHome(); 61 | 62 | //our interface methods 63 | void readState(); 64 | 65 | //our timer interrupt interface functions. 66 | void setupTimerInterrupt(); 67 | void enableTimerInterrupt(); 68 | void disableTimerInterrupt(); 69 | void setTimer(unsigned long delay); 70 | void setTimerResolution(byte r); 71 | void setTimerCeiling(unsigned int c); 72 | byte getTimerResolution(unsigned long delay); 73 | unsigned int getTimerCeiling(unsigned long delay); 74 | 75 | //our variables 76 | LinearAxis x; 77 | LinearAxis y; 78 | LinearAxis z; 79 | 80 | //for DDA stuff. 81 | int max_delta; 82 | 83 | //this is the mode we're currently in... started/stopped 84 | byte mode; 85 | 86 | private: 87 | 88 | //this is for our queue of points. 89 | byte head; 90 | byte tail; 91 | byte size; 92 | 93 | Point point_queue[POINT_QUEUE_SIZE]; 94 | }; 95 | 96 | #endif 97 | -------------------------------------------------------------------------------- /library/CartesianBot/keywords.txt: -------------------------------------------------------------------------------- 1 | ####################################### 2 | # Syntax Coloring Map For Test 3 | ####################################### 4 | 5 | ####################################### 6 | # Datatypes (KEYWORD1) 7 | ####################################### 8 | 9 | LimitSwitch KEYWORD1 10 | 11 | ####################################### 12 | # Methods and Functions (KEYWORD2) 13 | ####################################### 14 | 15 | getState KEYWORD2 16 | readState KEYWORD2 17 | version KEYWORD2 18 | 19 | 20 | ###################################### 21 | # Instances (KEYWORD2) 22 | ####################################### 23 | 24 | 25 | ####################################### 26 | # Constants (LITERAL1) 27 | ####################################### 28 | 29 | -------------------------------------------------------------------------------- /library/CartesianBot_SNAP_v1/CartesianBot_SNAP_v1.cpp: -------------------------------------------------------------------------------- 1 | #include "CartesianBot_SNAP_v1.h" 2 | #include 3 | #include "HardwareSerial.h" 4 | 5 | /********************************** 6 | * Global variable instantiations 7 | **********************************/ 8 | 9 | byte x_notify = 255; 10 | byte y_notify = 255; 11 | byte z_notify = 255; 12 | 13 | byte x_sync_mode = sync_none; 14 | byte y_sync_mode = sync_none; 15 | 16 | //our mode holder. 17 | byte bot_mode = MODE_PAUSE; 18 | byte x_mode = MODE_PAUSE; 19 | byte y_mode = MODE_PAUSE; 20 | byte z_mode = MODE_PAUSE; 21 | 22 | SIGNAL(SIG_OUTPUT_COMPARE1A) 23 | { 24 | if (bot_mode == MODE_DDA) 25 | interruptDDA(); 26 | else if (bot_mode == MODE_HOMERESET) 27 | interruptHomeReset(); 28 | else if (bot_mode == MODE_SEEK) 29 | interruptSeek(); 30 | else if (bot_mode == MODE_FIND_MIN) 31 | interruptFindMin(); 32 | else if (bot_mode == MODE_FIND_MAX) 33 | interruptFindMax(); 34 | else if (bot_mode == MODE_RUN) 35 | interruptRun(); 36 | else 37 | { 38 | bot.mode = MODE_PAUSE; 39 | bot.disableTimerInterrupt(); 40 | } 41 | } 42 | 43 | 44 | 45 | void interruptDDA() 46 | { 47 | if (bot.x.can_step) 48 | bot.x.ddaStep(bot.max_delta); 49 | 50 | if (bot.y.can_step) 51 | bot.y.ddaStep(bot.max_delta); 52 | } 53 | 54 | void interruptHomeReset() 55 | { 56 | if (x_mode == MODE_HOMERESET && !bot.x.atMin()) 57 | bot.x.stepper.pulse(); 58 | 59 | if (y_mode == MODE_HOMERESET && !bot.y.atMin()) 60 | bot.y.stepper.pulse(); 61 | 62 | if (z_mode == MODE_HOMERESET && !bot.z.atMin()) 63 | bot.z.stepper.pulse(); 64 | } 65 | 66 | void interruptSeek() 67 | { 68 | if (bot.x.can_step) 69 | bot.x.doStep(); 70 | 71 | if (bot.y.can_step) 72 | bot.y.doStep(); 73 | 74 | if (bot.z.can_step) 75 | bot.z.doStep(); 76 | } 77 | 78 | void interruptFindMin() 79 | { 80 | if (x_mode == MODE_FIND_MIN) 81 | { 82 | if (!bot.x.atMin()) 83 | bot.x.stepper.pulse(); 84 | } 85 | 86 | if (y_mode == MODE_FIND_MIN) 87 | { 88 | if (!bot.x.atMin()) 89 | bot.y.stepper.pulse(); 90 | } 91 | 92 | if (z_mode == MODE_FIND_MIN) 93 | { 94 | if (!bot.x.atMin()) 95 | bot.z.stepper.pulse(); 96 | } 97 | } 98 | 99 | void interruptFindMax() 100 | { 101 | if (x_mode == MODE_FIND_MAX) 102 | { 103 | //do a step if we're not there yet. 104 | if (!bot.x.atMax()) 105 | bot.x.doStep(); 106 | } 107 | 108 | if (y_mode == MODE_FIND_MAX) 109 | { 110 | //do a step if we're not there yet. 111 | if (!bot.y.atMax()) 112 | bot.y.doStep(); 113 | } 114 | 115 | if (z_mode == MODE_FIND_MAX) 116 | { 117 | //do a step if we're not there yet. 118 | if (!bot.z.atMax()) 119 | bot.z.doStep(); 120 | } 121 | } 122 | 123 | void interruptRun() 124 | { 125 | if (x_mode == MODE_RUN && bot.x.can_step) 126 | bot.x.stepper.pulse(); 127 | 128 | if (y_mode == MODE_RUN && bot.y.can_step) 129 | bot.y.stepper.pulse(); 130 | 131 | if (z_mode == MODE_RUN && bot.z.can_step) 132 | bot.z.stepper.pulse(); 133 | } 134 | 135 | void setup_cartesian_bot_snap_v1() 136 | { 137 | bot.setupTimerInterrupt(); 138 | bot.disableTimerInterrupt(); 139 | 140 | snap.addDevice(X_ADDRESS); 141 | snap.addDevice(Y_ADDRESS); 142 | snap.addDevice(Z_ADDRESS); 143 | } 144 | 145 | void cartesian_bot_snap_v1_loop() 146 | { 147 | bot.readState(); 148 | 149 | if (bot_mode == MODE_PAUSE) 150 | { 151 | x_mode = MODE_PAUSE; 152 | y_mode = MODE_PAUSE; 153 | z_mode = MODE_PAUSE; 154 | bot.disableTimerInterrupt(); 155 | 156 | return; 157 | } 158 | else if (bot_mode == MODE_DDA) 159 | { 160 | if (bot.atTarget()) 161 | { 162 | //stop us. 163 | bot_mode = MODE_PAUSE; 164 | x_mode = MODE_PAUSE; 165 | y_mode = MODE_PAUSE; 166 | z_mode = MODE_PAUSE; 167 | bot.disableTimerInterrupt(); 168 | 169 | if (x_notify != 255) 170 | notifyDDA(x_notify, X_ADDRESS, bot.x.current); 171 | if (y_notify != 255) 172 | notifyDDA(y_notify, Y_ADDRESS, bot.y.current); 173 | } 174 | } 175 | else if (bot_mode == MODE_HOMERESET) 176 | { 177 | if (x_mode == MODE_HOMERESET) 178 | { 179 | if (bot.x.atMin()) 180 | { 181 | x_mode = MODE_PAUSE; 182 | bot.x.setPosition(0); 183 | bot.x.setTarget(0); 184 | bot.x.stepper.setDirection(RS_FORWARD); 185 | 186 | if (x_notify != 255) 187 | notifyHomeReset(x_notify, X_ADDRESS); 188 | } 189 | } 190 | 191 | if (y_mode == MODE_HOMERESET) 192 | { 193 | if (bot.y.atMin()) 194 | { 195 | y_mode = MODE_PAUSE; 196 | bot.y.setPosition(0); 197 | bot.y.setTarget(0); 198 | bot.y.stepper.setDirection(RS_FORWARD); 199 | 200 | if (y_notify != 255) 201 | notifyHomeReset(y_notify, Y_ADDRESS); 202 | } 203 | } 204 | 205 | if (z_mode == MODE_HOMERESET) 206 | { 207 | if (bot.z.atMin()) 208 | { 209 | z_mode = MODE_PAUSE; 210 | bot.z.setPosition(0); 211 | bot.z.setTarget(0); 212 | bot.z.stepper.setDirection(RS_FORWARD); 213 | 214 | if (z_notify != 255) 215 | notifyHomeReset(z_notify, Z_ADDRESS); 216 | } 217 | } 218 | 219 | if (x_mode == MODE_PAUSE && y_mode == MODE_PAUSE && z_mode == MODE_PAUSE) 220 | { 221 | bot_mode = MODE_PAUSE; 222 | bot.disableTimerInterrupt(); 223 | } 224 | } 225 | else if (bot_mode == MODE_SEEK) 226 | { 227 | if (x_mode == MODE_SEEK) 228 | { 229 | if (!bot.x.can_step) 230 | { 231 | x_mode = MODE_PAUSE; 232 | 233 | if (x_notify != 255) 234 | notifySeek(x_notify, X_ADDRESS, (int)bot.x.current); 235 | } 236 | } 237 | 238 | if (y_mode == MODE_SEEK) 239 | { 240 | if (!bot.y.can_step) 241 | { 242 | y_mode = MODE_PAUSE; 243 | 244 | if (y_notify != 255) 245 | notifySeek(y_notify, Y_ADDRESS, (int)bot.y.current); 246 | } 247 | } 248 | 249 | if (z_mode == MODE_SEEK) 250 | { 251 | if (!bot.z.can_step) 252 | { 253 | z_mode = MODE_PAUSE; 254 | 255 | if (z_notify != 255) 256 | notifySeek(z_notify, Z_ADDRESS, (int)bot.z.current); 257 | } 258 | } 259 | 260 | if (x_mode == MODE_PAUSE && y_mode == MODE_PAUSE && z_mode == MODE_PAUSE) 261 | { 262 | bot_mode = MODE_PAUSE; 263 | bot.disableTimerInterrupt(); 264 | } 265 | } 266 | else if (bot_mode == MODE_FIND_MIN) 267 | { 268 | if (x_mode == MODE_FIND_MIN) 269 | { 270 | if (bot.x.atMin()) 271 | { 272 | bot.x.setPosition(0); 273 | bot.x.stepper.setDirection(RS_FORWARD); 274 | x_mode = MODE_FIND_MAX; 275 | bot_mode = MODE_FIND_MAX; 276 | } 277 | } 278 | 279 | if (y_mode == MODE_FIND_MIN) 280 | { 281 | if (bot.y.atMin()) 282 | { 283 | bot.y.setPosition(0); 284 | bot.y.stepper.setDirection(RS_FORWARD); 285 | y_mode = MODE_FIND_MAX; 286 | bot_mode = MODE_FIND_MAX; 287 | } 288 | } 289 | 290 | if (z_mode == MODE_FIND_MIN) 291 | { 292 | if (bot.z.atMin()) 293 | { 294 | bot.z.setPosition(0); 295 | bot.z.stepper.setDirection(RS_FORWARD); 296 | z_mode = MODE_FIND_MAX; 297 | bot_mode = MODE_FIND_MAX; 298 | } 299 | } 300 | } 301 | else if (bot_mode == MODE_FIND_MAX) 302 | { 303 | if (x_mode == MODE_FIND_MAX) 304 | { 305 | //are we there yet? 306 | if (bot.x.atMax()) 307 | { 308 | bot.x.max = bot.x.current; 309 | x_mode = MODE_PAUSE; 310 | bot.disableTimerInterrupt(); 311 | 312 | if (x_notify != 255) 313 | notifyCalibrate(x_notify, X_ADDRESS, bot.x.max); 314 | } 315 | } 316 | 317 | if (y_mode == MODE_FIND_MAX) 318 | { 319 | //are we there yet? 320 | if (bot.y.atMax()) 321 | { 322 | bot.y.max = bot.y.current; 323 | y_mode = MODE_PAUSE; 324 | bot.disableTimerInterrupt(); 325 | 326 | if (x_notify != 255) 327 | notifyCalibrate(x_notify, X_ADDRESS, bot.y.max); 328 | } 329 | } 330 | 331 | if (z_mode == MODE_FIND_MAX) 332 | { 333 | //are we there yet? 334 | if (bot.z.atMax()) 335 | { 336 | bot.z.max = bot.z.current; 337 | z_mode = MODE_PAUSE; 338 | bot.disableTimerInterrupt(); 339 | 340 | if (x_notify != 255) 341 | notifyCalibrate(x_notify, X_ADDRESS, bot.z.max); 342 | } 343 | } 344 | } 345 | } 346 | 347 | void process_cartesian_bot_snap_commands_v1() 348 | { 349 | byte cmd = snap.getByte(0); 350 | byte dest = snap.getDestination(); 351 | int position = 0; 352 | 353 | switch (cmd) 354 | { 355 | case CMD_VERSION: 356 | snap.startMessage(0, dest); 357 | snap.sendDataByte(CMD_VERSION); // Response type 0 358 | snap.sendDataByte(VERSION_MAJOR); 359 | snap.sendDataByte(VERSION_MINOR); 360 | snap.sendMessage(); 361 | break; 362 | 363 | case CMD_FORWARD: 364 | //okay, set our speed. 365 | if (dest == X_ADDRESS) 366 | { 367 | bot.x.stepper.setDirection(RS_FORWARD); 368 | x_mode = MODE_RUN; 369 | } 370 | else if (dest == Y_ADDRESS) 371 | { 372 | bot.y.stepper.setDirection(RS_FORWARD); 373 | y_mode = MODE_RUN; 374 | } 375 | else if (dest == Z_ADDRESS) 376 | { 377 | bot.z.stepper.setDirection(RS_FORWARD); 378 | z_mode = MODE_RUN; 379 | } 380 | bot_mode = MODE_RUN; 381 | 382 | //emulate PIC timer 383 | bot.setTimer(picTimerSimulate(snap.getByte(1))); 384 | break; 385 | 386 | case CMD_REVERSE: 387 | if (dest == X_ADDRESS) 388 | { 389 | bot.x.stepper.setDirection(RS_REVERSE); 390 | x_mode = MODE_RUN; 391 | } 392 | else if (dest == Y_ADDRESS) 393 | { 394 | bot.y.stepper.setDirection(RS_REVERSE); 395 | y_mode = MODE_RUN; 396 | } 397 | else if (dest == Z_ADDRESS) 398 | { 399 | bot.z.stepper.setDirection(RS_REVERSE); 400 | z_mode = MODE_RUN; 401 | } 402 | bot_mode = MODE_RUN; 403 | 404 | //emulate PIC timer 405 | bot.setTimer(picTimerSimulate(snap.getByte(1))); 406 | break; 407 | 408 | case CMD_SETPOS: 409 | position = snap.getInt(1); 410 | 411 | if (dest == X_ADDRESS) 412 | { 413 | bot.x.setPosition(position); 414 | bot.x.setTarget(position); 415 | } 416 | else if (dest == Y_ADDRESS) 417 | { 418 | bot.y.setPosition(position); 419 | bot.y.setTarget(position); 420 | } 421 | else if (dest == Z_ADDRESS) 422 | { 423 | bot.z.setPosition(position); 424 | bot.z.setTarget(position); 425 | } 426 | break; 427 | 428 | case CMD_GETPOS: 429 | if (dest == X_ADDRESS) 430 | position = bot.x.current; 431 | else if (dest == Y_ADDRESS) 432 | position = bot.y.current; 433 | else if (dest == Z_ADDRESS) 434 | position = bot.z.current; 435 | 436 | snap.startMessage(0, dest); 437 | snap.sendDataByte(CMD_GETPOS); 438 | snap.sendDataInt(position); 439 | snap.sendMessage(); 440 | break; 441 | 442 | case CMD_SEEK: 443 | // Goto position 444 | position = snap.getInt(2); 445 | 446 | //okay, set our speed. 447 | if (dest == X_ADDRESS) 448 | { 449 | x_mode = MODE_SEEK; 450 | bot.x.setTarget(position); 451 | } 452 | else if (dest == Y_ADDRESS) 453 | { 454 | y_mode = MODE_SEEK; 455 | bot.y.setTarget(position); 456 | } 457 | else if (dest == Z_ADDRESS) 458 | { 459 | z_mode = MODE_SEEK; 460 | bot.z.setTarget(position); 461 | } 462 | 463 | //emulate the PIC timer speeds 464 | bot.setTimer(picTimerSimulate(snap.getByte(1))); 465 | 466 | //get everything current. 467 | bot.readState(); 468 | 469 | //start our seek. 470 | bot_mode = MODE_SEEK; 471 | bot.enableTimerInterrupt(); 472 | 473 | break; 474 | 475 | case CMD_FREE: 476 | if (dest == X_ADDRESS) 477 | { 478 | bot.x.stepper.disable(); 479 | x_mode = MODE_PAUSE; 480 | } 481 | if (dest == Y_ADDRESS) 482 | { 483 | bot.y.stepper.disable(); 484 | y_mode = MODE_PAUSE; 485 | } 486 | if (dest == Z_ADDRESS) 487 | { 488 | bot.z.stepper.disable(); 489 | z_mode = MODE_PAUSE; 490 | } 491 | break; 492 | 493 | case CMD_NOTIFY: 494 | // Parameter is receiver of notification, or 255 if notification should be turned off 495 | if (dest == X_ADDRESS) 496 | x_notify = snap.getByte(1); 497 | if (dest == Y_ADDRESS) 498 | y_notify = snap.getByte(1); 499 | if (dest == Z_ADDRESS) 500 | z_notify = snap.getByte(1); 501 | break; 502 | 503 | case CMD_SYNC: 504 | // Set sync mode.. used to determine which direction to move slave stepper 505 | if (dest == X_ADDRESS) 506 | x_sync_mode = snap.getByte(1); 507 | if (dest == Y_ADDRESS) 508 | y_sync_mode = snap.getByte(1); 509 | break; 510 | 511 | case CMD_CALIBRATE: 512 | // Request calibration (search at given speed) 513 | if (dest == X_ADDRESS) 514 | x_mode = MODE_FIND_MIN; 515 | else if (dest == Y_ADDRESS) 516 | y_mode = MODE_FIND_MIN; 517 | else if (dest == Z_ADDRESS) 518 | z_mode = MODE_FIND_MIN; 519 | 520 | //emulate PIC speeds 521 | bot.setTimer(picTimerSimulate(snap.getByte(1))); 522 | 523 | //start our calibration. 524 | bot_mode = MODE_FIND_MIN; 525 | bot.enableTimerInterrupt(); 526 | 527 | break; 528 | 529 | case CMD_GETRANGE: 530 | if (dest == X_ADDRESS) 531 | position = bot.x.max; 532 | else if (dest == Y_ADDRESS) 533 | position = bot.y.max; 534 | else 535 | position = bot.z.max; 536 | 537 | //tell the host. 538 | snap.startMessage(0, dest); 539 | snap.sendDataByte(CMD_GETPOS); 540 | snap.sendDataInt(position); 541 | snap.sendMessage(); 542 | break; 543 | 544 | case CMD_DDA: 545 | int target; 546 | 547 | //get our coords. 548 | position = snap.getInt(2); 549 | target = snap.getInt(4); 550 | 551 | //which axis is leading? 552 | if (dest == X_ADDRESS) 553 | { 554 | bot.x.setTarget(position); 555 | 556 | //we can figure out the target based on the sync mode 557 | if (y_sync_mode == sync_inc) 558 | bot.y.setTarget(bot.y.current + target); 559 | else if (y_sync_mode == sync_dec) 560 | bot.y.setTarget(bot.y.current - target); 561 | else 562 | bot.y.setTarget(bot.y.current); 563 | } 564 | else if (dest == Y_ADDRESS) 565 | { 566 | bot.y.setTarget(position); 567 | 568 | //we can figure out the target based on the sync mode 569 | if (x_sync_mode == sync_inc) 570 | bot.x.setTarget(bot.x.current + target); 571 | else if (x_sync_mode == sync_dec) 572 | bot.x.setTarget(bot.x.current - target); 573 | else 574 | bot.x.setTarget(bot.x.current); 575 | } 576 | 577 | //set z's target to itself. 578 | bot.z.setTarget(bot.z.current); 579 | 580 | //set our speed. 581 | bot.setTimer(picTimerSimulate(snap.getByte(1))); 582 | 583 | //init our DDA stuff! 584 | bot.calculateDDA(); 585 | 586 | //start the dda! 587 | bot_mode = MODE_DDA; 588 | x_mode = MODE_DDA; 589 | y_mode = MODE_DDA; 590 | z_mode = MODE_DDA; 591 | bot.enableTimerInterrupt(); 592 | 593 | break; 594 | 595 | case CMD_FORWARD1: 596 | if (dest == X_ADDRESS) 597 | bot.x.forward1(); 598 | else if (dest == Y_ADDRESS) 599 | bot.y.forward1(); 600 | else if (dest == Z_ADDRESS) 601 | bot.z.forward1(); 602 | break; 603 | 604 | case CMD_BACKWARD1: 605 | if (dest == X_ADDRESS) 606 | bot.x.reverse1(); 607 | else if (dest == Y_ADDRESS) 608 | bot.y.reverse1(); 609 | else if (dest == Z_ADDRESS) 610 | bot.z.reverse1(); 611 | break; 612 | 613 | case CMD_SETPOWER: 614 | //doesnt matter because power is handled by the stepper driver board! 615 | break; 616 | 617 | case CMD_GETSENSOR: 618 | snap.startMessage(0, dest); 619 | snap.sendDataByte(CMD_GETSENSOR); 620 | // Dummy values to satisfy PIC emulation 621 | snap.sendDataInt(0); 622 | snap.sendMessage(); 623 | break; 624 | 625 | case CMD_HOMERESET: 626 | 627 | if (dest == X_ADDRESS) 628 | { 629 | //configure our axis 630 | bot.x.stepper.setDirection(RS_REVERSE); 631 | 632 | //tell our axis to go home. 633 | x_mode = MODE_HOMERESET; 634 | } 635 | else if (dest == Y_ADDRESS) 636 | { 637 | //configure our axis 638 | bot.y.stepper.setDirection(RS_REVERSE); 639 | 640 | //tell our axis to go home. 641 | y_mode = MODE_HOMERESET; 642 | } 643 | else if (dest == Z_ADDRESS) 644 | { 645 | //configure our axis 646 | bot.z.stepper.setDirection(RS_REVERSE); 647 | 648 | //tell our axis to go home. 649 | z_mode = MODE_HOMERESET; 650 | } 651 | 652 | //emulate PIC timer stuff 653 | bot.setTimer(picTimerSimulate(snap.getByte(1))); 654 | 655 | //starts our home reset mode. 656 | bot_mode = MODE_HOMERESET; 657 | bot.enableTimerInterrupt(); 658 | break; 659 | 660 | case CMD_DEVICE_TYPE: 661 | snap.startMessage(0, dest); 662 | snap.sendDataByte(CMD_DEVICE_TYPE); 663 | snap.sendDataByte(DEVICE_TYPE); 664 | snap.sendMessage(); 665 | break; 666 | } 667 | } 668 | 669 | void notifyHomeReset(byte to, byte from) 670 | { 671 | snap.startMessage(to, from); 672 | snap.sendDataByte(CMD_HOMERESET); 673 | snap.sendMessage(); 674 | } 675 | 676 | void notifyCalibrate(byte to, byte from, int position) 677 | { 678 | snap.startMessage(to, from); 679 | snap.sendDataByte(CMD_CALIBRATE); 680 | snap.sendDataInt(position); 681 | snap.sendMessage(); 682 | } 683 | 684 | void notifySeek(byte to, byte from, int position) 685 | { 686 | snap.startMessage(to, from); 687 | snap.sendDataByte(CMD_SEEK); 688 | snap.sendDataInt(position); 689 | snap.sendMessage(); 690 | } 691 | 692 | void notifyDDA(byte to, byte from, int position) 693 | { 694 | snap.startMessage(to, from); 695 | snap.sendDataByte(CMD_DDA); 696 | snap.sendDataInt(position); 697 | snap.sendMessage(); 698 | } 699 | -------------------------------------------------------------------------------- /library/CartesianBot_SNAP_v1/CartesianBot_SNAP_v1.h: -------------------------------------------------------------------------------- 1 | /* 2 | CartesianBot_SNAP_v1.h - Cartesian Bot SNAP Communications library for Arduino 3 | 4 | This library implements/emulates v1 of the RepRap LinearAxis communications protocol. 5 | Technically, the protocol was designed around the idea of one board per axis, each with 6 | its own address and microcontroller. This library emulates 3 of these boards: X, Y, and Z 7 | on one Arduino. 8 | 9 | More information on the protocol here: http://reprap.org/bin/view/Main/StepperMotorController 10 | 11 | Memory Usage Estimate: 11 bytes + CartesianBot 12 | 13 | History: 14 | * (0.1) Created intial library by Zach Smith. 15 | * (0.2) Optimized library for better performance by Zach Smith. 16 | * (0.3) Rewrote and refactored all code. Fixed major interrupt bug by Zach Smith. 17 | * (0.4) Changed timer/speed setting to properly emulate PICs. Also fixed forward/reverse commands by Zach Smith. 18 | 19 | License: GPL v2.0 20 | */ 21 | 22 | #ifndef CARTESIAN_BOT_SNAP_V1_H 23 | #define CARTESIAN_BOT_SNAP_V1_H 24 | 25 | //all our includes. 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | //this guy actually processes the v1 SNAP commands. 32 | void setup_cartesian_bot_snap_v1(); 33 | void process_cartesian_bot_snap_commands_v1(); 34 | void cartesian_bot_snap_v1_loop(); 35 | 36 | //these are our functions for handling the interrupt. 37 | void interruptDDA(); 38 | void interruptSeek(); 39 | void interruptHomeReset(); 40 | void interruptFindMin(); 41 | void interruptFindMax(); 42 | void interruptRun(); 43 | 44 | //notification functions to let the host know whats up. 45 | void notifyHomeReset(byte to, byte from); 46 | void notifyCalibrate(byte to, byte from, int position); 47 | void notifySeek(byte to, byte from, int position); 48 | void notifyDDA(byte to, byte from, int position); 49 | 50 | extern CartesianBot bot; 51 | 52 | // 53 | // Version information 54 | // 55 | #define VERSION_MAJOR 1 56 | #define VERSION_MINOR 0 57 | #define HOST_ADDRESS 0 58 | #define DEVICE_TYPE 0 59 | 60 | // 61 | // Linear Axis commands 62 | // 63 | #define CMD_VERSION 0 64 | #define CMD_FORWARD 1 65 | #define CMD_REVERSE 2 66 | #define CMD_SETPOS 3 67 | #define CMD_GETPOS 4 68 | #define CMD_SEEK 5 69 | #define CMD_FREE 6 70 | #define CMD_NOTIFY 7 71 | #define CMD_SYNC 8 72 | #define CMD_CALIBRATE 9 73 | #define CMD_GETRANGE 10 74 | #define CMD_DDA 11 75 | #define CMD_FORWARD1 12 76 | #define CMD_BACKWARD1 13 77 | #define CMD_SETPOWER 14 78 | #define CMD_GETSENSOR 15 79 | #define CMD_HOMERESET 16 80 | #define CMD_DEVICE_TYPE 255 81 | 82 | 83 | // Addresses for our linear axes. 84 | #define X_ADDRESS 2 85 | #define Y_ADDRESS 3 86 | #define Z_ADDRESS 4 87 | 88 | //modes for the cartesian bot. 89 | #define MODE_PAUSE 0 90 | #define MODE_SEEK 1 91 | #define MODE_DDA 2 92 | #define MODE_HOMERESET 3 93 | #define MODE_FIND_MIN 4 94 | #define MODE_FIND_MAX 5 95 | #define MODE_RUN 6 96 | 97 | // sync mode declarations 98 | #define sync_none 0 99 | #define sync_seek 1 100 | #define sync_inc 2 101 | #define sync_dec 3 102 | 103 | // Making this inline saves about 30 bytes (AB)... 104 | 105 | inline unsigned long picTimerSimulate(unsigned char fromSnap) 106 | { 107 | return (256 - fromSnap) * 4096UL; 108 | } 109 | 110 | #endif 111 | -------------------------------------------------------------------------------- /library/LinearAxis/LinearAxis.cpp: -------------------------------------------------------------------------------- 1 | #include "LinearAxis.h" 2 | #include "WConstants.h" 3 | 4 | LinearAxis::LinearAxis(char id, int steps, byte dir_pin, byte step_pin, byte min_pin, byte max_pin, byte enable_pin) : stepper(steps, dir_pin, step_pin, enable_pin) 5 | { 6 | this->id = id; 7 | this->current = 0; 8 | this->target = 0; 9 | this->max = 0; 10 | this->min_pin = min_pin; 11 | this->max_pin = max_pin; 12 | 13 | this->stepper.setDirection(RS_FORWARD); 14 | 15 | this->readState(); 16 | } 17 | 18 | void LinearAxis::readState() 19 | { 20 | //stop us if we're on target 21 | if (this->atTarget()) 22 | this->can_step = false; 23 | //stop us if we're at home and still going 24 | else if (this->atMin() && (this->stepper.direction == RS_REVERSE)) 25 | this->can_step = false; 26 | //stop us if we're at max and still going 27 | else if (this->atMax() && (this->stepper.direction == RS_FORWARD)) 28 | this->can_step = false; 29 | //default to being able to step 30 | else 31 | this->can_step = true; 32 | } 33 | 34 | bool LinearAxis::atMin() 35 | { 36 | return this->current <= 0; 37 | } 38 | 39 | bool LinearAxis::atMax() 40 | { 41 | return this->current >= this->max; 42 | } 43 | 44 | /* 45 | * Used for all axis, depending on stepper direction 46 | */ 47 | bool LinearAxis::atTarget() 48 | { 49 | if (this->stepper.direction == RS_FORWARD) 50 | return this->current >= this->target || this->atMax(); 51 | else 52 | return this->current <= this->target || this->atMin(); 53 | } 54 | 55 | void LinearAxis::doStep() 56 | { 57 | this->readState(); 58 | if (this->can_step) 59 | { 60 | if (this->stepper.direction == RS_FORWARD) 61 | this->forward1(); 62 | else 63 | this->reverse1(); 64 | } 65 | } 66 | 67 | void LinearAxis::forward1() 68 | { 69 | stepper.setDirection(RS_FORWARD); 70 | stepper.pulse(); 71 | 72 | this->current++; 73 | } 74 | 75 | void LinearAxis::reverse1() 76 | { 77 | stepper.setDirection(RS_REVERSE); 78 | stepper.pulse(); 79 | 80 | this->current--; 81 | } 82 | 83 | void LinearAxis::setPosition(long p) 84 | { 85 | this->current = p; 86 | 87 | //recalculate stuff. 88 | this->setTarget(this->target); 89 | } 90 | 91 | void LinearAxis::setTarget(long t) 92 | { 93 | this->target = t; 94 | 95 | if (this->target >= this->current) 96 | stepper.setDirection(RS_FORWARD); 97 | else 98 | stepper.setDirection(RS_REVERSE); 99 | 100 | this->delta = abs(this->target - this->current); 101 | } 102 | 103 | void LinearAxis::setMax(long v) 104 | { 105 | this->max = v; 106 | } 107 | 108 | void LinearAxis::initDDA(long max_delta) 109 | { 110 | this->counter = -max_delta/2; 111 | } 112 | 113 | void LinearAxis::ddaStep(long max_delta) 114 | { 115 | this->counter += this->delta; 116 | 117 | if (this->counter > 0) 118 | { 119 | this->doStep(); 120 | this->counter -= max_delta; 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /library/LinearAxis/LinearAxis.h: -------------------------------------------------------------------------------- 1 | /* 2 | LinearAxis.h - RepRap Linear Axis library for Arduino 3 | 4 | The interface for controlling a linear axis: stepper motor + min/max sensors + optional encoder 5 | 6 | Memory Usage Estimate: 25 + repstepper usage. 7 | 8 | History: 9 | * (0.1) Created library by Zach Smith. 10 | * (0.2) Optimized for less memory usage and faster performance 11 | * (0.3) Rewrote and refactored all code. Fixed major interrupt bug by Zach Smith. 12 | 13 | License: GPL v2.0 14 | */ 15 | 16 | // ensure this library description is only included once 17 | #ifndef LinearAxis_h 18 | #define LinearAxis_h 19 | 20 | #include 21 | 22 | // library interface description 23 | class LinearAxis { 24 | public: 25 | 26 | // constructors: 27 | LinearAxis(char id, int steps, byte dir_pin, byte step_pin, byte min_pin, byte max_pin, byte enable_pin); 28 | 29 | //these are our other object variables. 30 | RepStepper stepper; 31 | 32 | //various guys to interface with class 33 | void readState(); 34 | void doStep(); 35 | bool atMin(); 36 | bool atMax(); 37 | bool atTarget(); 38 | 39 | //various position things. 40 | void setPosition(long position); 41 | void setTarget(long t); 42 | void setMax(long v); 43 | void forward1(); 44 | void reverse1(); 45 | 46 | //dda functions 47 | void initDDA(long max_delta); 48 | void ddaStep(long max_delta); 49 | 50 | char id; //what is our id? x, y, z, etc. 51 | bool can_step; //are we capable of taking a step yet? 52 | 53 | long delta; //our delta for our DDA moves. 54 | long current; //this is our current position. 55 | long target; //this is our target position. 56 | long max; //this is our max coordinate. 57 | long counter; //this is our counter variable for dda. 58 | 59 | private: 60 | 61 | byte min_pin; 62 | byte max_pin; 63 | }; 64 | 65 | #endif 66 | -------------------------------------------------------------------------------- /library/RepStepper/RepStepper.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "RepStepper.h" 3 | 4 | /* 5 | * two-wire constructor. 6 | * Sets which wires should control the motor. 7 | */ 8 | RepStepper::RepStepper(int number_of_steps, byte dir_pin, byte step_pin, byte enable_pin) 9 | { 10 | //init our variables. 11 | this->setSpeed(0); 12 | 13 | //get our parameters 14 | this->number_of_steps = number_of_steps; 15 | this->step_pin = step_pin; 16 | this->direction_pin = dir_pin; 17 | this->enable_pin = enable_pin; 18 | 19 | // setup the pins on the microcontroller: 20 | pinMode(this->step_pin, OUTPUT); 21 | pinMode(this->direction_pin, OUTPUT); 22 | this->enable(); 23 | this->setDirection(RS_FORWARD); 24 | } 25 | 26 | /* 27 | Sets the speed in ticks per step 28 | */ 29 | void RepStepper::setSpeed(long speed) 30 | { 31 | step_delay = speed; 32 | 33 | if (step_delay > 0) 34 | rpm = 960000000UL / (step_delay * number_of_steps); 35 | else 36 | rpm = 0; 37 | } 38 | 39 | /* 40 | Sets the speed in revs per minute 41 | */ 42 | void RepStepper::setRPM(int new_rpm) 43 | { 44 | if (new_rpm == 0) 45 | { 46 | step_delay = 0; 47 | rpm = 0; 48 | } 49 | else 50 | { 51 | rpm = new_rpm; 52 | 53 | //lets use the highest precision possible... processor ticks. 54 | // 16MHZ = 16,000,000 ticks/sec * 60 seconds in a minute = 960,000,000 ticks / minute 55 | // take the total # of ticks / steps per rev / number of revolutions per minute = ticks per step 56 | step_delay = (960000000UL / number_of_steps) / rpm; 57 | } 58 | } 59 | 60 | void RepStepper::setSteps(int steps) 61 | { 62 | number_of_steps = steps; 63 | 64 | //recalculate our speed. 65 | this->setRPM(this->rpm); 66 | } 67 | 68 | void RepStepper::setDirection(bool direction) 69 | { 70 | digitalWrite(this->direction_pin, direction); 71 | delayMicroseconds(10); //make sure it stabilizes.. 72 | this->direction = direction; //save our direction. 73 | } 74 | 75 | int RepStepper::getMicros() 76 | { 77 | return step_delay / 16; 78 | } 79 | 80 | void RepStepper::enable() 81 | { 82 | if (this->enable_pin != 255) 83 | { 84 | digitalWrite(enable_pin, HIGH); 85 | delayMicroseconds(10); //make sure it stabilizes 86 | } 87 | 88 | enabled = true; 89 | } 90 | 91 | void RepStepper::disable() 92 | { 93 | if (this->enable_pin != 255) 94 | { 95 | digitalWrite(this->enable_pin, LOW); 96 | delayMicroseconds(10); //make sure it stabilizes 97 | } 98 | 99 | enabled = false; 100 | } 101 | 102 | //this sends a pulse to our stepper controller. 103 | void RepStepper::pulse() 104 | { 105 | digitalWrite(this->step_pin, HIGH); 106 | delayMicroseconds(5); //make sure it stabilizes... for opto isolated stepper drivers. 107 | digitalWrite(this->step_pin, LOW); 108 | } 109 | -------------------------------------------------------------------------------- /library/RepStepper/RepStepper.h: -------------------------------------------------------------------------------- 1 | /* 2 | RepStepper.h - RepRap Stepper library for Arduino 3 | 4 | This library interfaces with the RepRap Stepper Motor Driver and other standard stepper controllers 5 | that use the 2 wire Step/Direction interface. Loosely based on the Stepper library by Tom Igoe & others: http://www.arduino.cc/en/Reference/Stepper 6 | 7 | More information on the stepper driver circuit here: http://make.rrrf.org/smd 8 | 9 | Memory Usage Estimate: 13 bytes 10 | 11 | History: 12 | 13 | * (0.1) Forked library by Zach Smith. 14 | * (0.2) Optimizations to reduce code overhead by Zach Smith 15 | * (0.3) Added delays for optocoupled driver boards as well as variables to record enable/direction status. 16 | * (0.4) Rewrote and refactored all code. Fixed major interrupt bug by Zach Smith. 17 | 18 | License: GPL v2.0 19 | */ 20 | 21 | // ensure this library description is only included once 22 | #ifndef RepStepper_h 23 | #define RepStepper_h 24 | 25 | #include "WConstants.h" 26 | 27 | #define RS_FORWARD 1 28 | #define RS_REVERSE 0 29 | 30 | // library interface description 31 | class RepStepper { 32 | public: 33 | // constructors: 34 | RepStepper(int number_of_steps, byte dir_pin, byte step_pin, byte enable_pin); 35 | 36 | // various setters methods 37 | void setRPM(int rpm); 38 | void setSpeed(long speed); 39 | void setDirection(bool direction); 40 | void setSteps(int steps); 41 | 42 | int getMicros(); 43 | 44 | //various methods dealing with stepping. 45 | void pulse(); 46 | void enable(); 47 | void disable(); 48 | 49 | //various internal variables: READ ONLY! Do not set these directly. 50 | int rpm; // Speed in RPMs 51 | long step_delay; // delay between steps, in processor ticks, based on speed 52 | int number_of_steps; // total number of steps this motor can take 53 | bool enabled; //are we enabled? 54 | bool direction; //what is our direction? 55 | 56 | // motor pin numbers: 57 | byte step_pin; //the step signal pin. 58 | 59 | private: 60 | 61 | 62 | byte direction_pin; //the direction pin. 63 | byte enable_pin; //the enable pin. 64 | }; 65 | 66 | #endif 67 | -------------------------------------------------------------------------------- /library/RepStepper/keywords.txt: -------------------------------------------------------------------------------- 1 | ####################################### 2 | # Syntax Coloring Map For Test 3 | ####################################### 4 | 5 | ####################################### 6 | # Datatypes (KEYWORD1) 7 | ####################################### 8 | 9 | RepStepper KEYWORD1 10 | 11 | ####################################### 12 | # Methods and Functions (KEYWORD2) 13 | ####################################### 14 | 15 | setSpeed KEYWORD2 16 | setTarget KEYWORD2 17 | setDirection KEYWORD2 18 | step KEYWORD2 19 | canStep KEYWORD2 20 | version KEYWORD2 21 | 22 | 23 | ###################################### 24 | # Instances (KEYWORD2) 25 | ####################################### 26 | 27 | 28 | ####################################### 29 | # Constants (LITERAL1) 30 | ####################################### 31 | 32 | RS_FORWARD LITERAL1 33 | RS_REVERSE LITERAL1 -------------------------------------------------------------------------------- /library/SNAP/SNAP.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "SNAP.h" 3 | #include "WConstants.h" 4 | 5 | SNAP::SNAP() 6 | { 7 | //init our rx values 8 | this->rxState = SNAP_idle; 9 | this->rxFlags = 0; 10 | this->rxHDB1 = 0; 11 | this->rxHDB2 = 0; 12 | this->rxLength = 0; 13 | this->rxDestAddress = 0; 14 | this->rxSourceAddress = 0; 15 | this->rxCRC = 0; 16 | this->rxBufferIndex = 0; 17 | 18 | //clear our rx buffer. 19 | for (byte i=0; irxBuffer[i] = 0; 21 | 22 | //init our tx values 23 | this->txDestAddress = 0; 24 | this->txSourceAddress = 0; 25 | this->txLength = 0; 26 | this->txHDB2 = 0; 27 | this->txCRC = 0; 28 | 29 | //clear our tx buffer. 30 | for (byte i=0; itxBuffer[i] = 0; 32 | 33 | //init our device count. 34 | this->deviceCount = 0; 35 | } 36 | 37 | void SNAP::begin(long baud) 38 | { 39 | Serial.begin(baud); 40 | } 41 | 42 | void SNAP::receivePacket() 43 | { 44 | byte cmd; 45 | 46 | while (Serial.available() > 0 && !this->packetReady()) 47 | { 48 | cmd = Serial.read(); 49 | this->receiveByte(cmd); 50 | } 51 | } 52 | 53 | void SNAP::receiveByte(byte c) 54 | { 55 | if (this->rxFlags & serialErrorBit) 56 | { 57 | this->receiveError(); 58 | return; 59 | } 60 | 61 | 62 | switch (this->rxState) 63 | { 64 | case SNAP_idle: 65 | // In the idle state, we wait for a sync byte. If none is 66 | // received, we remain in this state. 67 | if (c == SNAP_SYNC) 68 | { 69 | this->rxState = SNAP_haveSync; 70 | this->rxFlags &= ~msgAbortedBit; //clear 71 | 72 | //this->debug(); 73 | //Serial.println("sync"); 74 | 75 | } 76 | //pass it along anyway. 77 | else 78 | this->transmit(c); 79 | break; 80 | 81 | case SNAP_haveSync: 82 | // In this state we are waiting for header definition bytes. First 83 | // HDB2. We currently insist that all packets meet our expected 84 | // format which is 1 byte destination address, 1 byte source 85 | // address, and no protocol specific bytes. The ACK/NAK bits may 86 | // be anything. 87 | this->rxHDB2 = c; 88 | if ((c & B11111100) != B01010000) 89 | { 90 | // Unsupported header. Drop it an reset 91 | this->rxFlags |= serialErrorBit; //set serialError 92 | this->rxFlags |= wrongByteErrorBit; 93 | this->receiveError(); 94 | } 95 | // All is well 96 | else 97 | { 98 | //do we want ack? 99 | if ((c & B00000011) == B00000001) 100 | this->rxFlags |= ackRequestedBit; //set ackRequested-Bit 101 | else 102 | this->rxFlags &= ~ackRequestedBit; //clear 103 | this->rxCRC = 0; 104 | 105 | this->computeRxCRC(c); 106 | 107 | this->rxState = SNAP_haveHDB2; 108 | 109 | //this->debug(); 110 | //Serial.println("hdb2"); 111 | } 112 | break; 113 | 114 | case SNAP_haveHDB2: 115 | // For HDB1, we insist on high bits are 0011 and low bits are the length 116 | // of the payload. 117 | this->rxHDB1 = c; 118 | if ((c & B11110000) != B00110000) 119 | { 120 | this->rxFlags |= serialErrorBit; //set serialError 121 | this->rxFlags |= wrongByteErrorBit; 122 | this->receiveError(); 123 | } 124 | else 125 | { 126 | // FIXME: This doesn't correspond to the SNAP specs since the length 127 | // should become non-linear after 8 bytes. The original reprap code 128 | // does the same thing though. kintel 20071120. 129 | this->rxLength = c & 0x0f; 130 | 131 | if (this->rxLength > RX_BUFFER_SIZE) 132 | this->rxLength = RX_BUFFER_SIZE; 133 | 134 | this->computeRxCRC(c); 135 | 136 | this->rxState = SNAP_haveHDB1; 137 | 138 | //this->debug(); 139 | //Serial.println("hdb1"); 140 | } 141 | break; 142 | 143 | case SNAP_haveHDB1: 144 | // We should be reading the destination address now 145 | if (!this->hasDevice(c)) 146 | { 147 | //this->debug(); 148 | //Serial.print("no device:"); 149 | //Serial.println(c); 150 | 151 | this->transmit(SNAP_SYNC); 152 | this->transmit(this->rxHDB2); 153 | this->transmit(this->rxHDB1); 154 | this->transmit(c); 155 | this->rxState = SNAP_haveDABPass; 156 | this->rxFlags &= ~ackRequestedBit; //clear 157 | this->rxFlags |= inTransmitMsgBit; 158 | } 159 | else 160 | { 161 | //save our address, as we may have multiple addresses on one arduino. 162 | this->rxDestAddress = c; 163 | 164 | this->computeRxCRC(c); 165 | this->rxState = SNAP_haveDAB; 166 | 167 | //this->debug(); 168 | //Serial.println("got dest"); 169 | } 170 | break; 171 | 172 | case SNAP_haveDAB: 173 | // We should be reading the source address now 174 | if (this->hasDevice(c)) 175 | { 176 | // If we receive a packet from ourselves, that means it went 177 | // around the ring and was never picked up, ie the device we 178 | // sent to is off-line or unavailable. 179 | 180 | // FIXME: Deal with this situation 181 | this->receiveError(); 182 | } 183 | 184 | /* 185 | // this may not be required.... we check this flag before accepting new packets... 186 | if (this->rxFlags & processingLockBit) 187 | { 188 | this->rxCRC = 0; 189 | 190 | //we have not finished the last order, reject (send a NAK) 191 | this->transmit(SNAP_SYNC); 192 | this->transmit(computeRxCRC(B01010011)); //HDB2: NAK 193 | this->transmit(computeRxCRC(B00110000)); // HDB1: 0 bytes, with 8 bit CRC 194 | this->transmit(computeRxCRC(this->rxSourceAddress)); // Return to sender 195 | this->transmit(computeRxCRC(this->rxDestAddress)); // From us 196 | this->transmit(this->rxCRC); // CRC 197 | 198 | this->rxFlags &= ~ackRequestedBit; //clear 199 | this->rxFlags |= msgAbortedBit; //set 200 | 201 | this->rxState = SNAP_idle; 202 | } 203 | */ 204 | 205 | this->rxSourceAddress = c; 206 | this->rxBufferIndex = 0; 207 | this->computeRxCRC(c); 208 | 209 | //this->debug(); 210 | //Serial.println("got source"); 211 | 212 | this->rxState = SNAP_readingData; 213 | break; 214 | 215 | case SNAP_readingData: 216 | rxBuffer[rxBufferIndex] = c; 217 | rxBufferIndex++; 218 | 219 | this->computeRxCRC(c); 220 | 221 | if (rxBufferIndex == this->rxLength) 222 | this->rxState = SNAP_dataComplete; 223 | break; 224 | 225 | case SNAP_dataComplete: 226 | // We should be receiving a CRC after data, and it 227 | // should match what we have already computed 228 | { 229 | //this->debug(); 230 | //Serial.println("data done"); 231 | 232 | byte hdb2 = B01010000; // 1 byte addresses 233 | 234 | if (c == this->rxCRC) 235 | { 236 | // All is good, so process the command. Rather than calling the 237 | // appropriate function directly, we just set a flag to say 238 | // something is ready for processing. Then in the main loop we 239 | // detect this and process the command. This allows further 240 | // comms processing (such as passing other tokens around the 241 | // ring) while we're actioning the command. 242 | 243 | hdb2 |= B00000010; 244 | this->rxFlags |= processingLockBit; //set processingLockBit 245 | } 246 | // CRC mismatch, so we will NAK the packet 247 | else 248 | hdb2 |= B00000011; 249 | 250 | // Send ACK or NAK back to source 251 | if (this->rxFlags & ackRequestedBit) 252 | { 253 | this->transmit(SNAP_SYNC); 254 | this->rxCRC = 0; 255 | this->transmit(this->computeRxCRC(hdb2)); 256 | this->transmit(this->computeRxCRC(B00110000)); // HDB1: 0 bytes, with 8 bit CRC 257 | this->transmit(this->computeRxCRC(this->rxSourceAddress)); // Return to sender 258 | this->transmit(this->computeRxCRC(this->rxDestAddress)); // From us 259 | this->transmit(this->rxCRC); // CRC 260 | this->rxFlags &= ~ackRequestedBit; // clear 261 | } 262 | } 263 | 264 | this->rxState = SNAP_idle; 265 | break; 266 | 267 | case SNAP_haveDABPass: 268 | //this->debug(); 269 | //Serial.println("dab pass"); 270 | 271 | this->transmit(c); // We will be reading source addr; pass it on 272 | 273 | // Increment data length by 1 so that we just copy the CRC 274 | // at the end as well. 275 | this->rxLength++; 276 | 277 | this->rxState = SNAP_readingDataPass; 278 | break; 279 | 280 | case SNAP_readingDataPass: 281 | 282 | // this->debug(); 283 | // Serial.println("data pass"); 284 | 285 | this->transmit(c); // This is a data byte; pass it on 286 | if (this->rxLength > 1) 287 | this->rxLength--; 288 | else 289 | { 290 | //init our rx values 291 | this->rxState = SNAP_idle; 292 | this->rxFlags = 0; 293 | this->rxHDB1 = 0; 294 | this->rxHDB2 = 0; 295 | this->rxLength = 0; 296 | this->rxDestAddress = 0; 297 | this->rxSourceAddress = 0; 298 | this->rxCRC = 0; 299 | this->rxBufferIndex = 0; 300 | 301 | //clear our rx buffer. 302 | for (byte i=0; irxBuffer[i] = 0; 304 | } 305 | break; 306 | 307 | default: 308 | //this->debug(); 309 | //Serial.println("no state!"); 310 | 311 | this->rxFlags |= serialErrorBit; //set serialError 312 | this->rxFlags |= wrongStateErrorBit; 313 | this->receiveError(); 314 | } 315 | } 316 | 317 | void SNAP::receiveError() 318 | { 319 | //init our rx values 320 | this->rxState = SNAP_idle; 321 | this->rxFlags = 0; 322 | this->rxHDB1 = 0; 323 | this->rxHDB2 = 0; 324 | this->rxLength = 0; 325 | this->rxDestAddress = 0; 326 | this->rxSourceAddress = 0; 327 | this->rxCRC = 0; 328 | this->rxBufferIndex = 0; 329 | 330 | //clear our rx buffer. 331 | for (byte i=0; irxBuffer[i] = 0; 333 | 334 | //this->debug(); 335 | //Serial.println("error"); 336 | } 337 | 338 | void SNAP::addDevice(byte c) 339 | { 340 | if (this->deviceCount >= MAX_DEVICE_COUNT) 341 | return; 342 | 343 | this->deviceAddresses[this->deviceCount] = c; 344 | this->deviceCount++; 345 | } 346 | 347 | void SNAP::startMessage(byte to, byte from) 348 | { 349 | //this->debug(); 350 | //Serial.println("msg start"); 351 | 352 | //initialize our addresses. 353 | this->txDestAddress = to; 354 | this->txSourceAddress = from; 355 | 356 | //initalize our variables. 357 | this->txLength = 0; 358 | this->txHDB2 = 0; 359 | this->txCRC = 0; 360 | 361 | //clear our buffer. 362 | for (byte i=0; itxBuffer[i] = 0; 364 | } 365 | 366 | /*! 367 | High level routine that queues a byte during construction of a packet. 368 | */ 369 | void SNAP::sendDataByte(byte c) 370 | { 371 | // Put byte into packet sending buffer. Don't calculated CRCs 372 | // yet as we don't have complete information. 373 | 374 | // Drop if trying to send too much 375 | if (this->txLength >= TX_BUFFER_SIZE) 376 | return; 377 | 378 | this->txBuffer[this->txLength] = c; 379 | this->txLength++; 380 | } 381 | 382 | void SNAP::sendDataInt(int i) 383 | { 384 | this->sendDataByte(i & 0xff); 385 | this->sendDataByte(i >> 8); 386 | } 387 | 388 | void SNAP::sendDataLong(long i) 389 | { 390 | this->sendDataByte(i & 0xff); 391 | this->sendDataByte(i >> 8); 392 | this->sendDataByte(i >> 16); 393 | this->sendDataByte(i >> 24); 394 | } 395 | 396 | 397 | /*! 398 | Create headers and synchronously transmit the message. 399 | */ 400 | void SNAP::sendMessage() 401 | { 402 | //this->debug(); 403 | //Serial.println("sendmsg"); 404 | 405 | this->txCRC = 0; 406 | 407 | //here is our header. 408 | this->transmit(SNAP_SYNC); 409 | this->transmit(this->computeTxCRC(B01010001)); // HDB2 - Request ACK 410 | 411 | // FIXME: This doesn't correspond to the SNAP specs since the length 412 | // should become non-linear after 8 bytes. The original reprap code 413 | // does the same thing though. kintel 20071120. 414 | this->transmit(this->computeTxCRC(B00110000 | this->txLength)); // HDB1 415 | this->transmit(this->computeTxCRC(this->txDestAddress)); // Destination 416 | this->transmit(this->computeTxCRC(this->txSourceAddress)); // Source (us) 417 | 418 | //payload. 419 | for (byte i=0; itxLength; i++) 420 | this->transmit(this->computeTxCRC(this->txBuffer[i])); 421 | 422 | this->transmit(this->txCRC); 423 | } 424 | 425 | bool SNAP::packetReady() 426 | { 427 | return (this->rxFlags & processingLockBit); 428 | } 429 | 430 | /*! 431 | Must be manually called by the main loop when the message payload 432 | has been consumed. 433 | */ 434 | void SNAP::releaseLock() 435 | { 436 | //init our rx values 437 | this->rxState = SNAP_idle; 438 | this->rxFlags = 0; 439 | this->rxHDB1 = 0; 440 | this->rxHDB2 = 0; 441 | this->rxLength = 0; 442 | this->rxDestAddress = 0; 443 | this->rxSourceAddress = 0; 444 | this->rxCRC = 0; 445 | this->rxBufferIndex = 0; 446 | 447 | //clear our rx buffer. 448 | for (byte i=0; irxBuffer[i] = 0; 450 | } 451 | 452 | bool SNAP::hasDevice(byte c) 453 | { 454 | for (int i=0; ideviceCount; i++) 455 | { 456 | if (this->deviceAddresses[i] == c) 457 | return true; 458 | } 459 | 460 | return false; 461 | } 462 | 463 | void SNAP::debug() 464 | { 465 | Serial.print('d'); 466 | } 467 | 468 | void SNAP::transmit(byte c) 469 | { 470 | Serial.print(c, BYTE); 471 | } 472 | 473 | /*! 474 | Incrementally adds b to crc computation and updates crc. 475 | returns \c. 476 | */ 477 | byte SNAP::computeCRC(byte b, byte crc) 478 | { 479 | byte i = b ^ crc; 480 | 481 | crc = 0; 482 | 483 | if (i & 1) crc ^= 0x5e; 484 | if (i & 2) crc ^= 0xbc; 485 | if (i & 4) crc ^= 0x61; 486 | if (i & 8) crc ^= 0xc2; 487 | if (i & 0x10) crc ^= 0x9d; 488 | if (i & 0x20) crc ^= 0x23; 489 | if (i & 0x40) crc ^= 0x46; 490 | if (i & 0x80) crc ^= 0x8c; 491 | 492 | return crc; 493 | } 494 | 495 | byte SNAP::computeRxCRC(byte b) 496 | { 497 | this->rxCRC = this->computeCRC(b, this->rxCRC); 498 | 499 | return b; 500 | } 501 | 502 | byte SNAP::computeTxCRC(byte b) 503 | { 504 | this->txCRC = this->computeCRC(b, this->txCRC); 505 | 506 | return b; 507 | } 508 | 509 | byte SNAP::getDestination() 510 | { 511 | return this->rxDestAddress; 512 | } 513 | 514 | byte SNAP::getByte(byte index) 515 | { 516 | return this->rxBuffer[index]; 517 | } 518 | 519 | int SNAP::getInt(byte index) 520 | { 521 | return (this->rxBuffer[index+1] << 8) + this->rxBuffer[index]; 522 | } 523 | 524 | // Preinstantiate Objects 525 | SNAP snap = SNAP(); 526 | -------------------------------------------------------------------------------- /library/SNAP/SNAP.h: -------------------------------------------------------------------------------- 1 | /* 2 | SNAP.h - RepRap SNAP Communications library for Arduino 3 | 4 | This library implements easy SNAP based communication with the RepRap host software 5 | with easy commands to enable receiving, sending, and passing along SNAP messages. 6 | 7 | History: 8 | * (0.1) Ported from PIC library by Zach Smith. 9 | * (0.2) Updated and fixed by the guys from Metalab in Austra (kintel and wizard23) 10 | * (0.3) Rewrote and refactored all code. Added separate buffers and variables for Rx/Tx by Zach Smith. 11 | 12 | License: GPL v2.0 13 | */ 14 | 15 | #ifndef SNAP_h 16 | #define SNAP_h 17 | 18 | // include types & constants of Wiring core API 19 | #include "WConstants.h" 20 | #include "HardwareSerial.h" 21 | 22 | //how many devices we have on this meta device 23 | #define MAX_DEVICE_COUNT 5 // size of our array to store virtual addresses 24 | #define TX_BUFFER_SIZE 16 // Transmit buffer size. 25 | #define RX_BUFFER_SIZE 16 // Receive buffer size. 26 | #define HOST_ADDRESS 0 // address of the host. 27 | 28 | //our sync packet value. 29 | #define SNAP_SYNC 0x54 30 | 31 | //The defines below are for error checking and such. 32 | //Bit0 is for serialError-flag for checking if an serial error has occured, 33 | // if set, we will reset the communication 34 | //Bit1 is set if we are currently transmitting a message, that means bytes of 35 | // a message have been put in the transmitBuffer, but the message is not 36 | // finished. 37 | //Bit2 is set if we are currently building a send-message 38 | //Bit3 is set if we are busy with the last command and have to abort the message 39 | //Bit4 is set when we have a wrong uartState 40 | //Bit5 is set when we receive a wrong byte 41 | //Bit6 is set if we have to acknowledge a received message 42 | //Bit7 is set if we have received a message for local processing 43 | #define serialErrorBit B00000001 44 | #define inTransmitMsgBit B00000010 45 | #define inSendQueueMsgBit B00000100 46 | #define msgAbortedBit B00001000 47 | #define wrongStateErrorBit B00010000 48 | #define wrongByteErrorBit B00100000 49 | #define ackRequestedBit B01000000 50 | #define processingLockBit B10000000 51 | 52 | //these are the states for processing a packet. 53 | enum SNAP_states 54 | { 55 | SNAP_idle = 0x30, 56 | SNAP_haveSync, 57 | SNAP_haveHDB2, 58 | SNAP_haveHDB1, 59 | SNAP_haveDAB, 60 | SNAP_readingData, 61 | SNAP_dataComplete, 62 | 63 | // The *Pass states below represent states where 64 | // we should just be passing the data on to the next node. 65 | // This is either because we bailed out, or because the 66 | // packet wasn't destined for us. 67 | SNAP_haveHDB2Pass, 68 | SNAP_haveHDB1Pass, 69 | SNAP_haveDABPass, 70 | SNAP_readingDataPass 71 | }; 72 | 73 | class SNAP 74 | { 75 | public: 76 | SNAP(); 77 | 78 | void begin(long baud); 79 | void addDevice(byte b); 80 | 81 | void receivePacket(); 82 | void receiveByte(byte b); 83 | bool packetReady(); 84 | 85 | byte getDestination(); 86 | byte getByte(byte index); 87 | int getInt(byte index); // get 16 bits 88 | 89 | void startMessage(byte to, byte from); 90 | void sendDataByte(byte c); 91 | void sendDataInt(int data); 92 | void sendDataLong(long data); 93 | void sendMessage(); 94 | 95 | void debug(); 96 | 97 | void releaseLock(); 98 | 99 | private: 100 | void receiveError(); 101 | bool hasDevice(byte b); 102 | void transmit(byte c); 103 | 104 | //our crc functions. 105 | byte computeCRC(byte b, byte crc); 106 | byte computeRxCRC(byte c); 107 | byte computeTxCRC(byte c); 108 | 109 | //these are variables for the packet we're currently receiving. 110 | byte rxState; // Current SNAP packet state 111 | byte rxFlags; // flags for checking status of the serial-communication 112 | byte rxHDB1; // 1st header byte 113 | byte rxHDB2; // 2nd header byte 114 | byte rxLength; // Length of packet being received 115 | byte rxDestAddress; // Destination of packet being received (us) 116 | byte rxSourceAddress; // Source of packet being received 117 | byte rxCRC; // Incrementally calculated CRC value 118 | byte rxBufferIndex; // Current receive buffer index 119 | byte rxBuffer[RX_BUFFER_SIZE]; // Receive buffer 120 | 121 | //these are the variables for the packet we're currently transmitting. 122 | byte txHDB2; // 2nd header byte (1st header byte doesnt change!) 123 | byte txLength; // transmit packet length 124 | byte txDestAddress; // transmit packet destination 125 | byte txSourceAddress; // transmit packet source (us) 126 | byte txCRC; // incrementally calculated CRC value 127 | byte txBuffer[TX_BUFFER_SIZE]; // Last packet data, for auto resending on a NAK 128 | 129 | // the address of our internal device sending message 130 | byte deviceAddresses[MAX_DEVICE_COUNT]; 131 | byte deviceCount; 132 | }; 133 | 134 | //global variable declaration. 135 | extern SNAP snap; 136 | 137 | #endif 138 | -------------------------------------------------------------------------------- /library/ThermoplastExtruder/ThermistorTable.h: -------------------------------------------------------------------------------- 1 | #ifndef THERMISTOR_TABLE 2 | #define THERMISTOR_TABLE 3 | 4 | // Thermistor lookup table for RepRap Temperature Sensor Boards (http://make.rrrf.org/ts) 5 | // Made with createTemperatureLookup.py (http://svn.reprap.org/trunk/reprap/firmware/Arduino/utilities/createTemperatureLookup.py) 6 | // ./createTemperatureLookup.py --r0=100000 --t0=25 --r1=0 --r2=4700 --beta=4066 --max-adc=1023 7 | // r0: 100000 8 | // t0: 25 9 | // r1: 0 10 | // r2: 4700 11 | // beta: 4066 12 | // max adc: 1023 13 | #define NUMTEMPS 20 14 | short temptable[NUMTEMPS][2] = { 15 | {1, 841}, 16 | {54, 255}, 17 | {107, 209}, 18 | {160, 184}, 19 | {213, 166}, 20 | {266, 153}, 21 | {319, 142}, 22 | {372, 132}, 23 | {425, 124}, 24 | {478, 116}, 25 | {531, 108}, 26 | {584, 101}, 27 | {637, 93}, 28 | {690, 86}, 29 | {743, 78}, 30 | {796, 70}, 31 | {849, 61}, 32 | {902, 50}, 33 | {955, 34}, 34 | {1008, 3} 35 | }; 36 | 37 | #endif 38 | -------------------------------------------------------------------------------- /library/ThermoplastExtruder/Thermistor_r0_100000_t0_25_r1_0_r2_4700_beta_3960.h: -------------------------------------------------------------------------------- 1 | #ifndef THERMISTOR_TABLE 2 | #define THERMISTOR_TABLE 3 | 4 | // Thermistor lookup table for RepRap Temperature Sensor Boards (http://make.rrrf.org/ts) 5 | // Made with createTemperatureLookup.py (http://svn.reprap.org/trunk/reprap/firmware/Arduino/utilities/createTemperatureLookup.py) 6 | // ./createTemperatureLookup.py --r0=100000 --t0=25 --r1=0 --r2=4700 --beta=3960 --max-adc=1023 7 | // r0: 100000 8 | // t0: 25 9 | // r1: 0 10 | // r2: 4700 11 | // beta: 3960 12 | // max adc: 1023 13 | #define NUMTEMPS 20 14 | short temptable[NUMTEMPS][2] = { 15 | {1, 929}, 16 | {54, 266}, 17 | {107, 217}, 18 | {160, 190}, 19 | {213, 172}, 20 | {266, 158}, 21 | {319, 146}, 22 | {372, 136}, 23 | {425, 127}, 24 | {478, 119}, 25 | {531, 111}, 26 | {584, 103}, 27 | {637, 96}, 28 | {690, 88}, 29 | {743, 80}, 30 | {796, 71}, 31 | {849, 62}, 32 | {902, 50}, 33 | {955, 34}, 34 | {1008, 2} 35 | }; 36 | 37 | #endif 38 | -------------------------------------------------------------------------------- /library/ThermoplastExtruder/Thermistor_r0_100000_t0_25_r1_0_r2_4700_beta_4066.h: -------------------------------------------------------------------------------- 1 | #ifndef THERMISTOR_TABLE 2 | #define THERMISTOR_TABLE 3 | 4 | // Thermistor lookup table for RepRap Temperature Sensor Boards (http://make.rrrf.org/ts) 5 | // Made with createTemperatureLookup.py (http://svn.reprap.org/trunk/reprap/firmware/Arduino/utilities/createTemperatureLookup.py) 6 | // ./createTemperatureLookup.py --r0=100000 --t0=25 --r1=0 --r2=4700 --beta=4066 --max-adc=1023 7 | // r0: 100000 8 | // t0: 25 9 | // r1: 0 10 | // r2: 4700 11 | // beta: 4066 12 | // max adc: 1023 13 | #define NUMTEMPS 20 14 | short temptable[NUMTEMPS][2] = { 15 | {1, 841}, 16 | {54, 255}, 17 | {107, 209}, 18 | {160, 184}, 19 | {213, 166}, 20 | {266, 153}, 21 | {319, 142}, 22 | {372, 132}, 23 | {425, 124}, 24 | {478, 116}, 25 | {531, 108}, 26 | {584, 101}, 27 | {637, 93}, 28 | {690, 86}, 29 | {743, 78}, 30 | {796, 70}, 31 | {849, 61}, 32 | {902, 50}, 33 | {955, 34}, 34 | {1008, 3} 35 | }; 36 | 37 | #endif 38 | -------------------------------------------------------------------------------- /library/ThermoplastExtruder/Thermistor_r0_10000_t0_25_r1_680_r2_1600_beta_3480.h: -------------------------------------------------------------------------------- 1 | #ifndef THERMISTOR_TABLE 2 | #define THERMISTOR_TABLE 3 | 4 | // Thermistor lookup table for RepRap Temperature Sensor Boards (http://make.rrrf.org/ts) 5 | // Made with createTemperatureLookup.py (http://svn.reprap.org/trunk/reprap/firmware/Arduino/utilities/createTemperatureLookup.py) 6 | // ./createTemperatureLookup.py --r0=10000 --t0=25 --r1=680 --r2=1600 --beta=3480 --max-adc=315 7 | // r0: 10000 8 | // t0: 25 9 | // r1: 680 10 | // r2: 1600 11 | // beta: 3480 12 | // max adc: 315 13 | #define NUMTEMPS 20 14 | short temptable[NUMTEMPS][2] = { 15 | {1, 922}, 16 | {17, 327}, 17 | {33, 260}, 18 | {49, 225}, 19 | {65, 202}, 20 | {81, 184}, 21 | {97, 169}, 22 | {113, 156}, 23 | {129, 145}, 24 | {145, 134}, 25 | {161, 125}, 26 | {177, 115}, 27 | {193, 106}, 28 | {209, 96}, 29 | {225, 87}, 30 | {241, 76}, 31 | {257, 64}, 32 | {273, 50}, 33 | {289, 29}, 34 | {305, -45} 35 | }; 36 | 37 | #endif 38 | -------------------------------------------------------------------------------- /library/ThermoplastExtruder/Thermistor_r0_10000_t0_25_r1_680_r2_1600_beta_3964.h: -------------------------------------------------------------------------------- 1 | #ifndef THERMISTOR_TABLE 2 | #define THERMISTOR_TABLE 3 | 4 | // Thermistor lookup table for RepRap Temperature Sensor Boards (http://make.rrrf.org/ts) 5 | // Made with createTemperatureLookup.py (http://svn.reprap.org/trunk/reprap/firmware/Arduino/utilities/createTemperatureLookup.py) 6 | // ./createTemperatureLookup.py --r0=10000 --t0=25 --r1=680 --r2=1600 --beta=3964 --max-adc=305 7 | // r0: 10000 8 | // t0: 25 9 | // r1: 680 10 | // r2: 1600 11 | // beta: 3964 12 | // max adc: 305 13 | #define NUMTEMPS 19 14 | short temptable[NUMTEMPS][2] = { 15 | {1, 601}, 16 | {17, 260}, 17 | {33, 213}, 18 | {49, 187}, 19 | {65, 170}, 20 | {81, 156}, 21 | {97, 144}, 22 | {113, 134}, 23 | {129, 125}, 24 | {145, 117}, 25 | {161, 109}, 26 | {177, 101}, 27 | {193, 94}, 28 | {209, 86}, 29 | {225, 78}, 30 | {241, 69}, 31 | {257, 59}, 32 | {273, 46}, 33 | {289, 28} 34 | }; 35 | 36 | #endif -------------------------------------------------------------------------------- /library/ThermoplastExtruder/ThermoplastExtruder.cpp: -------------------------------------------------------------------------------- 1 | #include "WConstants.h" 2 | #include "ThermoplastExtruder.h" 3 | 4 | // Pick up the thermistor table from the file - makes it easier to customise 5 | // the code for different thermistors. 6 | 7 | #include "ThermistorTable.h" 8 | 9 | /*! 10 | motor_dir_pin must be a digital output. 11 | motor_pwm_pin and heater_pin must be PWM capable outputs. 12 | thermistor_pin must be an analog input. 13 | */ 14 | ThermoplastExtruder::ThermoplastExtruder(byte motor_dir_pin, byte motor_pwm_pin, 15 | byte heater_pin, byte cooler_pin, byte thermistor_pin, byte valve_dir_pin, 16 | byte valve_enable_pin) 17 | { 18 | this->motor_dir_pin = motor_dir_pin; 19 | this->motor_pwm_pin = motor_pwm_pin; 20 | this->valve_dir_pin = valve_dir_pin; 21 | this->valve_enable_pin = valve_enable_pin; 22 | this->heater_pin = heater_pin; 23 | this->cooler_pin = cooler_pin; 24 | this->thermistor_pin = thermistor_pin; 25 | 26 | pinMode(this->motor_dir_pin, OUTPUT); 27 | pinMode(this->motor_pwm_pin, OUTPUT); 28 | pinMode(this->heater_pin, OUTPUT); 29 | pinMode(this->valve_dir_pin, OUTPUT); 30 | pinMode(this->valve_enable_pin, OUTPUT); 31 | 32 | this->getTemperature(); 33 | this->setSpeed(0); 34 | this->setDirection(true); 35 | 36 | //init our temp stuff. 37 | this->target_celsius = 0; 38 | this->max_celsius = 0; 39 | this->heater_low = 0; 40 | this->heater_high = 0; 41 | } 42 | 43 | /*! 44 | Sets the motor speed from 0-255 (0 is off). 45 | */ 46 | void ThermoplastExtruder::setSpeed(byte speed) 47 | { 48 | this->motor_pwm = speed; 49 | analogWrite(this->motor_pwm_pin, this->motor_pwm); 50 | } 51 | 52 | void ThermoplastExtruder::setCooler(byte speed) 53 | { 54 | this->cooler_pwm = speed; 55 | analogWrite(this->cooler_pin, this->cooler_pwm); 56 | } 57 | 58 | /*! 59 | Sets the motor direction (true = forward, false = backward) 60 | */ 61 | void ThermoplastExtruder::setDirection(bool dir) 62 | { 63 | this->motor_dir = dir; 64 | digitalWrite(this->motor_dir_pin, this->motor_dir); 65 | } 66 | 67 | /*! 68 | Pulse the valve to open or close it. dir == true: open; dir == false: closed 69 | */ 70 | void ThermoplastExtruder::setValve(bool dir, byte pulse_time) 71 | { 72 | digitalWrite(this->valve_dir_pin, dir); 73 | digitalWrite(this->valve_enable_pin, 1); 74 | delay(2*(int)pulse_time); 75 | digitalWrite(this->valve_enable_pin, 0); 76 | } 77 | 78 | void ThermoplastExtruder::setTemperature(int temp) 79 | { 80 | this->target_celsius = temp; 81 | this->max_celsius = (int)((float)temp * 1.1); 82 | } 83 | 84 | /** 85 | * Samples the temperature and converts it to degrees celsius. 86 | * Returns degrees celsius. 87 | */ 88 | int ThermoplastExtruder::getTemperature() 89 | { 90 | this->raw_temperature = analogRead(thermistor_pin); 91 | this->current_celsius = this->calculateTemperatureFromRaw(this->raw_temperature); 92 | 93 | return this->current_celsius; 94 | } 95 | 96 | /** 97 | * Samples the temperature and converts it to degrees celsius. 98 | * Returns degrees celsius. 99 | */ 100 | int ThermoplastExtruder::calculateTemperatureFromRaw(int raw) 101 | { 102 | int celsius = 0; 103 | byte i; 104 | 105 | for (i=1; i raw) 108 | { 109 | celsius = temptable[i-1][1] + 110 | (raw - temptable[i-1][0]) * 111 | (temptable[i][1] - temptable[i-1][1]) / 112 | (temptable[i][0] - temptable[i-1][0]); 113 | 114 | if (celsius > 255) 115 | celsius = 255; 116 | 117 | break; 118 | } 119 | } 120 | 121 | // Overflow: We just clamp to 0 degrees celsius 122 | if (i == NUMTEMPS) 123 | celsius = 0; 124 | 125 | return celsius; 126 | } 127 | 128 | /*! 129 | Manages motor and heater based on measured temperature: 130 | o If temp is too low, don't start the motor 131 | o Adjust the heater power to keep the temperature at the target 132 | */ 133 | void ThermoplastExtruder::manageTemperature() 134 | { 135 | //make sure we know what our temp is. 136 | this->getTemperature(); 137 | 138 | //put the heater into high mode if we're not at our target. 139 | if (current_celsius < target_celsius) 140 | { 141 | analogWrite(heater_pin, heater_high); 142 | } 143 | //put the heater on low if we're at our target. 144 | else if (current_celsius < max_celsius) 145 | { 146 | analogWrite(heater_pin, heater_low); 147 | } 148 | //turn the heater off if we're above our max. 149 | else 150 | { 151 | analogWrite(heater_pin, 0); 152 | } 153 | } 154 | -------------------------------------------------------------------------------- /library/ThermoplastExtruder/ThermoplastExtruder.h: -------------------------------------------------------------------------------- 1 | /* 2 | ThermoplastExtruder.h - RepRap Thermoplastic Extruder library for Arduino 3 | 4 | This library is used to read, control, and handle a thermoplastic extruder. 5 | 6 | More information at: http://reprap.org/bin/view/Main/RepRapOneDarwinThermoplastExtruder 7 | 8 | Memory Usage Estimate: 18 bytes 9 | 10 | History: 11 | * (0.1) Created intial library by Zach Smith. 12 | * (0.2) Initial rework by Marius Kintel 13 | * (0.3) Updated and optimized by Zach Smith 14 | * (0.4) Updated with new default values for 100K thermistor. 15 | * (0.3) Rewrote and refactored all code by Zach Smith. 16 | 17 | 18 | License: GPL v2.0 19 | */ 20 | 21 | #ifndef THERMOPLASTEXTRUDER_H 22 | #define THERMOPLASTEXTRUDER_H 23 | 24 | #include "WConstants.h" 25 | 26 | class ThermoplastExtruder 27 | { 28 | public: 29 | ThermoplastExtruder(byte motor_dir_pin, byte motor_pwm_pin, byte heater_pin, 30 | byte cooler_pin, byte thermistor_pin, byte valve_dir_pin, 31 | byte valve_enable_pin); 32 | 33 | // various setters methods: 34 | void setSpeed(byte speed); 35 | void setDirection(bool dir); 36 | void setCooler(byte speed); 37 | 38 | //temparature control 39 | void setTemperature(int temp); 40 | int getTemperature(); 41 | int calculateTemperatureFromRaw(int raw); 42 | void manageTemperature(); 43 | 44 | // Open and close the valve 45 | void setValve(bool dir, byte pulse_time); 46 | 47 | //variables for easy access. 48 | byte heater_low; // Low heater, for when we're at our temp, 0-255 49 | byte heater_high; // High heater, for when we're below our temp, 0-255 50 | int target_celsius; // Our target temperature 51 | int max_celsius; // Our max temperature 52 | 53 | private: 54 | 55 | //pin numbers: 56 | byte motor_pwm_pin; // motor PWM pin 57 | byte motor_dir_pin; // motor direction pin 58 | byte valve_enable_pin; // valve enable pin 59 | byte valve_dir_pin; // valve direction pin 60 | byte heater_pin; // heater PWM pin 61 | byte thermistor_pin; // thermistor analog input pin 62 | byte cooler_pin; // cooler fan PWM pin 63 | 64 | //extruder variables 65 | bool motor_dir; // Motor direction (true = forward, false = backward) 66 | byte motor_pwm; // Speed in PWM, 0-255 67 | byte cooler_pwm; // Fan speed in PWM, 0-255 68 | int current_celsius; // Our current temperature 69 | int raw_temperature; // our raw temperature reading. 70 | }; 71 | 72 | #endif 73 | -------------------------------------------------------------------------------- /library/ThermoplastExtruder/keywords.txt: -------------------------------------------------------------------------------- 1 | ####################################### 2 | # Syntax Coloring Map For Test 3 | ####################################### 4 | 5 | ####################################### 6 | # Datatypes (KEYWORD1) 7 | ####################################### 8 | 9 | RepStepper KEYWORD1 10 | 11 | ####################################### 12 | # Methods and Functions (KEYWORD2) 13 | ####################################### 14 | 15 | setSpeed KEYWORD2 16 | setTarget KEYWORD2 17 | setDirection KEYWORD2 18 | step KEYWORD2 19 | canStep KEYWORD2 20 | version KEYWORD2 21 | 22 | 23 | ###################################### 24 | # Instances (KEYWORD2) 25 | ####################################### 26 | 27 | 28 | ####################################### 29 | # Constants (LITERAL1) 30 | ####################################### 31 | 32 | RS_FORWARD LITERAL1 33 | RS_REVERSE LITERAL1 -------------------------------------------------------------------------------- /library/ThermoplastExtruder_SNAP_v1/ThermoplastExtruder_SNAP_v1.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | // 4 | // Variables from host software 5 | // 6 | byte vRefFactor = 7; 7 | byte tempScaler = 4; 8 | int currentPos = 0; 9 | 10 | //this guys sets us up. 11 | void setup_extruder_snap_v1() 12 | { 13 | snap.addDevice(EXTRUDER_ADDRESS); 14 | 15 | //init to defaults in java software. 16 | vRefFactor = 7; 17 | tempScaler = 4; 18 | currentPos = 0; 19 | } 20 | 21 | //this guy actually processes the commands. 22 | void process_thermoplast_extruder_snap_commands_v1() 23 | { 24 | byte cmd = snap.getByte(0); 25 | 26 | switch (cmd) 27 | { 28 | // tell the host what version we are. 29 | case CMD_VERSION: 30 | snap.startMessage(0, EXTRUDER_ADDRESS); 31 | snap.sendDataByte(CMD_VERSION); 32 | snap.sendDataByte(VERSION_MAJOR); 33 | snap.sendDataByte(VERSION_MINOR); 34 | snap.sendMessage(); 35 | break; 36 | 37 | // move motor forward. 38 | case CMD_FORWARD: 39 | extruder.setDirection(1); 40 | extruder.setSpeed(snap.getByte(1)); 41 | break; 42 | 43 | // move motor backward. 44 | case CMD_REVERSE: 45 | extruder.setDirection(0); 46 | extruder.setSpeed(snap.getByte(1)); 47 | break; 48 | 49 | // Open the valve 50 | case CMD_VALVEOPEN: 51 | extruder.setValve(1, snap.getByte(1)); 52 | break; 53 | 54 | // Close the valve 55 | case CMD_VALVECLOSE: 56 | extruder.setValve(0, snap.getByte(1)); 57 | break; 58 | 59 | // dunno what this is supposed to do... 60 | case CMD_SETPOS: 61 | currentPos = snap.getInt(1); 62 | break; 63 | 64 | // dunno what this is supposed to do either... 65 | case CMD_GETPOS: 66 | //send some Bogus data so the Host software is happy 67 | snap.startMessage(0, EXTRUDER_ADDRESS); 68 | snap.sendDataByte(CMD_GETPOS); 69 | snap.sendDataInt(currentPos); 70 | snap.sendMessage(); 71 | break; 72 | 73 | // we also cant really do this. 74 | case CMD_SEEK: 75 | //debug.println("n/i: seek"); 76 | break; 77 | 78 | // Free motor. There is no torque hold for a DC motor, so all we do is switch off 79 | case CMD_FREE: 80 | extruder.setSpeed(0); 81 | break; 82 | 83 | // this is also a mystery... we cant really do this either. 84 | case CMD_NOTIFY: 85 | //debug.println("n/i: notify"); 86 | break; 87 | 88 | // are we out of filament? 89 | case CMD_ISEMPTY: 90 | // We don't know so we say we're not empty 91 | snap.startMessage(0, EXTRUDER_ADDRESS); 92 | snap.sendDataByte(CMD_ISEMPTY); 93 | snap.sendDataByte(0); 94 | snap.sendMessage(); 95 | break; 96 | 97 | // set our heater and target information 98 | case CMD_SETHEAT: 99 | //extruder.heater_low = snap.getByte(1); 100 | //extruder.heater_high = snap.getByte(2); 101 | extruder.heater_low = 64; 102 | extruder.heater_high = 255; 103 | extruder.target_celsius = calculateTemperatureForPicTemp(snap.getByte(3)); 104 | extruder.max_celsius = calculateTemperatureForPicTemp(snap.getByte(4)); 105 | break; 106 | 107 | // tell the host software how hot we are. 108 | case CMD_GETTEMP: 109 | //TODO: is delay needed? 110 | delay(100); 111 | snap.startMessage(0, EXTRUDER_ADDRESS); 112 | snap.sendDataByte(CMD_GETTEMP); 113 | snap.sendDataByte(calculatePicTempForCelsius(extruder.getTemperature())); 114 | snap.sendDataByte(extruder.getTemperature()); //dunno what this is for... its how it is in the old firmware too. 115 | snap.sendMessage(); 116 | break; 117 | 118 | // turn our fan on/off. 119 | case CMD_SETCOOLER: 120 | extruder.setCooler(snap.getByte(1)); 121 | break; 122 | 123 | // used for temp conversion. 124 | case CMD_SETVREF: 125 | vRefFactor = snap.getByte(1); 126 | break; 127 | 128 | // used for temp conversion. 129 | case CMD_SETTEMPSCALER: 130 | tempScaler = snap.getByte(1); 131 | break; 132 | 133 | case CMD_DEVICE_TYPE: 134 | snap.startMessage(0, EXTRUDER_ADDRESS); 135 | snap.sendDataByte(CMD_DEVICE_TYPE); 136 | snap.sendDataByte(DEVICE_TYPE); 137 | snap.sendMessage(); 138 | break; 139 | 140 | } 141 | snap.releaseLock(); 142 | } 143 | 144 | /*************** 145 | * This is code for doing reading conversions since the Arduino does the temp readings via straight analog reads. 146 | ***************/ 147 | 148 | int calculateTemperatureForPicTemp(int picTemp) 149 | { 150 | int scale = 1 << (tempScaler+1); 151 | double clock = 4000000.0 / (4.0 * (double)scale); // hertz 152 | double vRef = 0.25 * 5.0 + 5.0 * vRefFactor / 32.0; // volts 153 | double T = (double)picTemp / clock; // seconds 154 | double resistance = -T / (log(1 - vRef / 5.0) * CAPACITOR); // ohms 155 | 156 | return (int)((1.0 / (1.0 / ABSOLUTE_ZERO + log(resistance/RZ) / BETA)) - ABSOLUTE_ZERO); 157 | } 158 | 159 | /** 160 | * Calculates an expected PIC Temperature expected for a 161 | * given resistance 162 | * @param resistance 163 | * @return 164 | */ 165 | int calculatePicTempForCelsius(int temperature) 166 | { 167 | double resistance = RZ * exp(BETA * (1/(temperature + ABSOLUTE_ZERO) - 1/ABSOLUTE_ZERO)); 168 | int scale = 1 << (tempScaler+1); 169 | double clock = 4000000.0 / (4.0 * scale); // hertz 170 | double vRef = 0.25 * 5.0 + 5.0 * vRefFactor / 32.0; // volts 171 | double T = -resistance * (log(1 - vRef / 5.0) * CAPACITOR); 172 | 173 | int pictemp = (int)(T * clock); 174 | 175 | //prevent tempscaling taking us to crazy heights. 176 | if (pictemp <= 0) 177 | pictemp = 1; 178 | if (pictemp >= 255) 179 | pictemp = 255; 180 | 181 | return pictemp; 182 | } 183 | -------------------------------------------------------------------------------- /library/ThermoplastExtruder_SNAP_v1/ThermoplastExtruder_SNAP_v1.h: -------------------------------------------------------------------------------- 1 | /* 2 | ThermoplastExtruder_SNAP_v1.h - Thermoplastic Extruder SNAP Communications library for Arduino 3 | 4 | This library implements/emulates v1 of the RepRap Thermoplastic Extruder communications protocol. 5 | The initial protocol was designed around measuring temperature by the amount of time 6 | it takes to charge a capacitor through the thermistor. In order to maintain compatibility, 7 | the Arduino takes its analog reading and converts it into the value a PIC would return. 8 | 9 | More information on the protocol here: http://reprap.org/bin/view/Main/ExtruderController 10 | 11 | Memory Usage Estimate: 5 - 50? + ThermoplastExtruder 12 | 13 | History: 14 | * (0.1) Created intial library by Zach Smith. 15 | * (0.2) Updated to emulate PIC based temperature measuring. 16 | * (0.3) Updated with new values from Steve DeGroof (http://forums.reprap.org/read.php?70,8034) 17 | * (0.4) Rewrote and refactored all code. Fixed major interrupt bug by Zach Smith. 18 | 19 | 20 | License: GPL v2.0 21 | */ 22 | 23 | #ifndef THERMOPLAST_EXTRUDER_SNAP_V1H 24 | #define THERMOPLAST_EXTRUDER_SNAP_V1_H 25 | 26 | // 27 | // constants for temp/pic temp conversion. from reprap.properties.dist 28 | // 29 | #define BETA 550.0 30 | #define CAPACITOR 0.000003 31 | #define RZ 4837 32 | #define ABSOLUTE_ZERO 273.15 33 | 34 | //our include files. 35 | #include 36 | #include 37 | #include 38 | 39 | // 40 | // Various processing commands. 41 | // 42 | void setup_extruder_snap_v1(); 43 | void process_thermoplast_extruder_snap_commands_v1(); 44 | 45 | // 46 | // Conversion commands 47 | // 48 | int calculateTemperatureForPicTemp(int picTemp); 49 | int calculatePicTempForCelsius(int temperature); 50 | 51 | // 52 | // Version information 53 | // 54 | #define VERSION_MAJOR 1 55 | #define VERSION_MINOR 0 56 | #define EXTRUDER_ADDRESS 8 57 | #define DEVICE_TYPE 1 58 | 59 | // 60 | // Extruder commands 61 | // 62 | #define CMD_VERSION 0 63 | #define CMD_FORWARD 1 64 | #define CMD_REVERSE 2 65 | #define CMD_SETPOS 3 66 | #define CMD_GETPOS 4 67 | #define CMD_SEEK 5 68 | #define CMD_FREE 6 69 | #define CMD_NOTIFY 7 70 | #define CMD_ISEMPTY 8 71 | #define CMD_SETHEAT 9 72 | #define CMD_GETTEMP 10 73 | #define CMD_SETCOOLER 11 74 | #define CMD_VALVEOPEN 12 75 | #define CMD_VALVECLOSE 13 76 | #define CMD_PWMPERIOD 50 77 | #define CMD_PRESCALER 51 //apparently doesnt exist... 78 | #define CMD_SETVREF 52 79 | #define CMD_SETTEMPSCALER 53 80 | #define CMD_GETDEBUGINFO 54 //apparently doesnt exist... 81 | #define CMD_GETTEMPINFO 55 //apparently doesnt exist... 82 | #define CMD_DEVICE_TYPE 255 83 | 84 | extern ThermoplastExtruder extruder; 85 | 86 | #endif 87 | -------------------------------------------------------------------------------- /package_release: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | #init up 4 | VERSION=${1:-`date +%Y-%m-%d`} 5 | TO_DIR="reprap-arduino-firmware-$VERSION" 6 | 7 | #directory structure 8 | echo "Making Files..." 9 | mkdir -p "$TO_DIR" 10 | mkdir -p "$TO_DIR/snap" 11 | mkdir -p "$TO_DIR/gcode" 12 | 13 | echo "Exporting files..." 14 | svn export Single_Arduino_SNAP "$TO_DIR/snap/Single_Arduino_SNAP" 15 | svn export 3Axis_SNAP "$TO_DIR/snap/3Axis_SNAP" 16 | svn export Extruder_SNAP "$TO_DIR/snap/Extruder_SNAP" 17 | svn export library "$TO_DIR/library" 18 | svn export GCode_Interpreter "$TO_DIR/gcode/GCode_Interpreter" 19 | svn export GCode_Interpreter_Experimental "$TO_DIR/gcode/GCode_Interpreter_Experimental" 20 | 21 | cp README "$TO_DIR/" 22 | cp LICENSE "$TO_DIR/" 23 | 24 | #create our archive 25 | echo "Archiving..." 26 | zip -qr "$TO_DIR.zip" "$TO_DIR" 27 | 28 | #cleanup 29 | echo "Cleanup..." 30 | rm -rf "$TO_DIR" 31 | 32 | #done! 33 | echo "Release v$VERSION created as ${TO_DIR}.zip" 34 | -------------------------------------------------------------------------------- /utilities/createTemperatureLookup.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # 3 | # Creates a C code lookup table for doing ADC to temperature conversion 4 | # on a microcontroller 5 | # based on: http://hydraraptor.blogspot.com/2007/10/measuring-temperature-easy-way.html 6 | """Thermistor Value Lookup Table Generator 7 | 8 | Generates lookup to temperature values for use in a microcontroller in C format based on: 9 | http://hydraraptor.blogspot.com/2007/10/measuring-temperature-easy-way.html 10 | 11 | The main use is for Arduino programs that read data from the circuit board described here: 12 | http://make.rrrf.org/ts-1.0 13 | 14 | Usage: python createTemperatureLookup.py [options] 15 | 16 | Options: 17 | -h, --help show this help 18 | --r0=... thermistor rating where # is the ohm rating of the thermistor at t0 (eg: 10K = 10000) 19 | --t0=... thermistor temp rating where # is the temperature in Celsuis to get r0 (from your datasheet) 20 | --beta=... thermistor beta rating. see http://reprap.org/bin/view/Main/MeasuringThermistorBeta 21 | --r1=... R1 rating where # is the ohm rating of R1 (eg: 10K = 10000) 22 | --r2=... R2 rating where # is the ohm rating of R2 (eg: 10K = 10000) 23 | --num-temps=... the number of temperature points to calculate (default: 20) 24 | --max-adc=... the max ADC reading to use. if you use R1, it limits the top value for the thermistor circuit, and thus the possible range of ADC values 25 | """ 26 | 27 | from math import * 28 | import sys 29 | import getopt 30 | 31 | class Thermistor: 32 | "Class to do the thermistor maths" 33 | def __init__(self, r0, t0, beta, r1, r2): 34 | self.r0 = r0 # stated resistance, e.g. 10K 35 | self.t0 = t0 + 273.15 # temperature at stated resistance, e.g. 25C 36 | self.beta = beta # stated beta, e.g. 3500 37 | self.vadc = 5.0 # ADC reference 38 | self.vcc = 5.0 # supply voltage to potential divider 39 | self.k = r0 * exp(-beta / self.t0) # constant part of calculation 40 | 41 | if r1 > 0: 42 | self.vs = r1 * self.vcc / (r1 + r2) # effective bias voltage 43 | self.rs = r1 * r2 / (r1 + r2) # effective bias impedance 44 | else: 45 | self.vs = self.vcc # effective bias voltage 46 | self.rs = r2 # effective bias impedance 47 | 48 | def temp(self,adc): 49 | "Convert ADC reading into a temperature in Celcius" 50 | v = adc * self.vadc / 1024 # convert the 10 bit ADC value to a voltage 51 | r = self.rs * v / (self.vs - v) # resistance of thermistor 52 | return (self.beta / log(r / self.k)) - 273.15 # temperature 53 | 54 | def setting(self, t): 55 | "Convert a temperature into a ADC value" 56 | r = self.r0 * exp(self.beta * (1 / (t + 273.15) - 1 / self.t0)) # resistance of the thermistor 57 | v = self.vs * r / (self.rs + r) # the voltage at the potential divider 58 | return round(v / self.vadc * 1024) # the ADC reading 59 | 60 | def main(argv): 61 | 62 | r0 = 10000; 63 | t0 = 25; 64 | beta = 3947; 65 | r1 = 680; 66 | r2 = 1600; 67 | num_temps = int(20); 68 | max_adc = int(1023); 69 | 70 | try: 71 | opts, args = getopt.getopt(argv, "h", ["help", "r0=", "t0=", "beta=", "r1=", "r2=", "max-adc="]) 72 | except getopt.GetoptError: 73 | usage() 74 | sys.exit(2) 75 | 76 | for opt, arg in opts: 77 | if opt in ("-h", "--help"): 78 | usage() 79 | sys.exit() 80 | elif opt == "--r0": 81 | r0 = int(arg) 82 | elif opt == "--t0": 83 | t0 = int(arg) 84 | elif opt == "--beta": 85 | beta = int(arg) 86 | elif opt == "--r1": 87 | r1 = int(arg) 88 | elif opt == "--r2": 89 | r2 = int(arg) 90 | elif opt == "--max-adc": 91 | max_adc = int(arg) 92 | 93 | increment = int(max_adc/(num_temps-1)); 94 | 95 | t = Thermistor(r0, t0, beta, r1, r2) 96 | 97 | adcs = range(1, max_adc, increment); 98 | # adcs = [1, 20, 25, 30, 35, 40, 45, 50, 60, 70, 80, 90, 100, 110, 130, 150, 190, 220, 250, 300] 99 | first = 1 100 | 101 | print "// Thermistor lookup table for RepRap Temperature Sensor Boards (http://make.rrrf.org/ts)" 102 | print "// Made with createTemperatureLookup.py (http://svn.reprap.org/trunk/reprap/firmware/Arduino/utilities/createTemperatureLookup.py)" 103 | print "// ./createTemperatureLookup.py --r0=%s --t0=%s --r1=%s --r2=%s --beta=%s --max-adc=%s" % (r0, t0, r1, r2, beta, max_adc) 104 | print "// r0: %s" % (r0) 105 | print "// t0: %s" % (t0) 106 | print "// r1: %s" % (r1) 107 | print "// r2: %s" % (r2) 108 | print "// beta: %s" % (beta) 109 | print "// max adc: %s" % (max_adc) 110 | print "#define NUMTEMPS %s" % (len(adcs)) 111 | print "short temptable[NUMTEMPS][2] = {" 112 | 113 | counter = 0 114 | for adc in adcs: 115 | counter = counter +1 116 | if counter == len(adcs): 117 | print " {%s, %s}" % (adc, int(t.temp(adc))) 118 | else: 119 | print " {%s, %s}," % (adc, int(t.temp(adc))) 120 | print "};" 121 | 122 | def usage(): 123 | print __doc__ 124 | 125 | if __name__ == "__main__": 126 | main(sys.argv[1:]) --------------------------------------------------------------------------------