This shows you the differences between two versions of the page.
| Both sides previous revision Previous revision Next revision | Previous revision | ||
|
oak:tutorials:stepper_motor [2017/01/14 16:19] Rover#18 |
oak:tutorials:stepper_motor [2017/01/14 16:52] Rover#18 minor edits in the remote commanding description |
||
|---|---|---|---|
| Line 5: | Line 5: | ||
| {{ :oak:tutorials:oak_stepper_motor_setup.jpg?direct&500 | Oak commanding stepper motor via A4988 driver. A 6-wire 2-phase unipolar stepper motor is shown here, with its coil center tap leads (white/yellow) unconnected. The A4988 driver (red) is upside-down in this photo, showing the backside of the board, which is opposite of the view shown in the Fritzing diagram. The motor is powered from a common 12V DC wall wart transformer, with a 68uF cap connected at the jack. }} | {{ :oak:tutorials:oak_stepper_motor_setup.jpg?direct&500 | Oak commanding stepper motor via A4988 driver. A 6-wire 2-phase unipolar stepper motor is shown here, with its coil center tap leads (white/yellow) unconnected. The A4988 driver (red) is upside-down in this photo, showing the backside of the board, which is opposite of the view shown in the Fritzing diagram. The motor is powered from a common 12V DC wall wart transformer, with a 68uF cap connected at the jack. }} | ||
| - | This lesson teaches you how to: | + | **This lesson teaches you how to:** |
| * Control a stepper motor using an [[https://www.pololu.com/file/download/A4988.pdf?file_id=0J450|A4988]] stepper motor driver, | * Control a stepper motor using an [[https://www.pololu.com/file/download/A4988.pdf?file_id=0J450|A4988]] stepper motor driver, | ||
| * Expose functions and variables to the Particle Cloud, for remote commanding via either [[http://digistu.mp/oakterm|OakTerm]], the Particle mobile app, or a [[https://digistump.com/wiki/oak/tutorials/stepper_motor?do=edit#stepper_controller_web_interface|custom web interface]]. | * Expose functions and variables to the Particle Cloud, for remote commanding via either [[http://digistu.mp/oakterm|OakTerm]], the Particle mobile app, or a [[https://digistump.com/wiki/oak/tutorials/stepper_motor?do=edit#stepper_controller_web_interface|custom web interface]]. | ||
| Line 148: | Line 148: | ||
| const int pinStep = 1; | const int pinStep = 1; | ||
| const int pinDirection = 0; | const int pinDirection = 0; | ||
| - | const int durationStepPulseMs = 1; //ms | + | const int durationStepPulseMicroseconds = 100; //us |
| const int maxStepsPerSec = 4; | const int maxStepsPerSec = 4; | ||
| Line 179: | Line 179: | ||
| Particle.variable("direction",stepDirection); | Particle.variable("direction",stepDirection); | ||
| Particle.variable("do_motion",doMotion); | Particle.variable("do_motion",doMotion); | ||
| - | Particle.variable("step_period",stepPeriodMs); | + | Particle.variable("stepperiod",stepPeriodMs); |
| - | Particle.variable("step_wait",waitBetweenStepsMs); | + | |
| } | } | ||
| Line 191: | Line 190: | ||
| if( doMotion && stepSpeed>0 && (stepDirection==-1 || stepDirection==1) ){ | if( doMotion && stepSpeed>0 && (stepDirection==-1 || stepDirection==1) ){ | ||
| doOneStep(); // send one pulse to the A4988 STEP pin | doOneStep(); // send one pulse to the A4988 STEP pin | ||
| - | delay(waitBetweenStepsMs); // pause here until it's time to send the next tick | + | |
| + | // Pause here until it's time to send the next pulse | ||
| + | // To be more precise, we would account for cpu time and step pulse duration, | ||
| + | // both of which should be small relative to the step period until you get up | ||
| + | // to speeds over 500 steps per second. Future builds should correct this. | ||
| + | delay(stepPeriodMs); | ||
| // Otherwise, pause briefly before checking again | // Otherwise, pause briefly before checking again | ||
| Line 217: | Line 221: | ||
| - | // setSpeed expects one argument: steps per second | + | // setSpeed expects one argument: steps per second, between -1000 and 1000 |
| // The steps per second argument is received as a string but may indicate | // The steps per second argument is received as a string but may indicate | ||
| // integer or fractional, positive or negative (i.g. "-100", "10", "0.25") | // integer or fractional, positive or negative (i.g. "-100", "10", "0.25") | ||
| Line 229: | Line 233: | ||
| sprintf(outStr, "Unable to convert \"%s\" to float", strStepsPerSecond.c_str()); | sprintf(outStr, "Unable to convert \"%s\" to float", strStepsPerSecond.c_str()); | ||
| Particle.publish("setSpeed() error", outStr); | Particle.publish("setSpeed() error", outStr); | ||
| + | stepSpeed = 0; | ||
| + | return -1; | ||
| + | } | ||
| + | // Reject speeds over 1000 steps/sec: | ||
| + | if (stepSpeed<-1000 || stepSpeed>1000){ | ||
| + | Particle.publish("setSpeed() error", "speed must be between -1000.0 and 1000.0 steps/sec"); | ||
| stepSpeed = 0; | stepSpeed = 0; | ||
| return -1; | return -1; | ||
| Line 245: | Line 255: | ||
| digitalWrite(pinDirection, (stepDirection>0) ? HIGH : LOW ); | digitalWrite(pinDirection, (stepDirection>0) ? HIGH : LOW ); | ||
| | | ||
| - | // Calculate step period (ms between steps) and prescribe wait time between steps: | + | // Calculate step period (ms between steps): |
| stepPeriodMs = (stepSpeed==0) ? 1000 : 1000/stepSpeed; //ms | stepPeriodMs = (stepSpeed==0) ? 1000 : 1000/stepSpeed; //ms | ||
| - | waitBetweenStepsMs = stepPeriodMs - durationStepPulseMs; // wait = period - pulseduration | ||
| | | ||
| return stepPeriodMs; | return stepPeriodMs; | ||
| Line 282: | Line 291: | ||
| void doOneStep(){ | void doOneStep(){ | ||
| digitalWrite(pinStep, HIGH); // start step pulse | digitalWrite(pinStep, HIGH); // start step pulse | ||
| - | delay(durationStepPulseMs); // hold step pulse | + | delayMicroseconds(durationStepPulseMicroseconds); // hold step pulse |
| digitalWrite(pinStep, LOW); // stop step pulse | digitalWrite(pinStep, LOW); // stop step pulse | ||
| } | } | ||
| Line 292: | Line 301: | ||
| * **motion(start)** starts motion, if you previously configured speed and direction. | * **motion(start)** starts motion, if you previously configured speed and direction. | ||
| * **motion(stop)** stops motion. | * **motion(stop)** stops motion. | ||
| - | * **setspeed(**[stepsPerSecond]**)** sets the motor speed in steps per second. | + | * **setspeed**(stepsPerSecond) sets the motor speed in steps per second. |
| - | * This accepts floating point values. For example, value 0.5 steps 1 step per 2 seconds. | + | * Accepts floating point values between -1000 and 1000. |
| - | * You can command a different speed while the motor is running. | + | * Example: speed of 0.5 steps/sec will step once per 2 seconds. |
| - | * setdir(-1 or 1) sets motor direction. | + | * Negative values set direction negative. |
| - | * Whether 1 corresponds to CW or CCW depends on which coil you hooked up to A and B. | + | * You can command a different speed while the motor is running. |
| - | * You can command a different direction while the motor is running. | + | * **setdir**(-1 or 1) sets motor direction. |
| + | * Whether 1 corresponds to CW or CCW depends on which coil you hooked up to A and B. | ||
| + | * You can command a different direction while the motor is running. | ||
| Line 316: | Line 327: | ||
| <form action="https://api.particle.io/v1/devices/MY_DEVICE_ID/setspeed" method="POST" target="replyFrame"> | <form action="https://api.particle.io/v1/devices/MY_DEVICE_ID/setspeed" method="POST" target="replyFrame"> | ||
| <input type="hidden" name="access_token" value="MY_ACCESS_TOKEN" /> | <input type="hidden" name="access_token" value="MY_ACCESS_TOKEN" /> | ||
| - | Set speed (-2000.0:2000.0): | + | Set speed (-1000.0 : 1000.0): |
| <input type="text" name="speed" value=""> | <input type="text" name="speed" value=""> | ||
| <input type="submit" value="Submit"> | <input type="submit" value="Submit"> | ||
| Line 372: | Line 383: | ||
| As noted in the stepper motor overview above, stepper motors can only reach a finite set of positions. A stepper motor with 200 steps/rev, for example, can only position within 0.9° from an arbitrary target position, when operated in full-step mode. If you require better accuracy, consider researching and experimenting with [[https://en.wikipedia.org/wiki/Stepper_motor#Microstepping|micro-stepping]]. The A4988 facilitates micro-stepping to 1/16th-step resolution, and enabling this function is quite simple. If you want to use 1/4, 1/8, or 1/16th step sizes exclusively, then you can configure the A4988 for this with 1, 2, or 3 additional jumpers or resistors, respecively. If you want to toggle between step sizes, then connect 3 Oak GPIO pins to the A4988 MS1, MS2, and MS3 pins and update the sketch to manage these pins. | As noted in the stepper motor overview above, stepper motors can only reach a finite set of positions. A stepper motor with 200 steps/rev, for example, can only position within 0.9° from an arbitrary target position, when operated in full-step mode. If you require better accuracy, consider researching and experimenting with [[https://en.wikipedia.org/wiki/Stepper_motor#Microstepping|micro-stepping]]. The A4988 facilitates micro-stepping to 1/16th-step resolution, and enabling this function is quite simple. If you want to use 1/4, 1/8, or 1/16th step sizes exclusively, then you can configure the A4988 for this with 1, 2, or 3 additional jumpers or resistors, respecively. If you want to toggle between step sizes, then connect 3 Oak GPIO pins to the A4988 MS1, MS2, and MS3 pins and update the sketch to manage these pins. | ||
| - | + | Hope you found this useful! | |