Giter VIP home page Giter VIP logo

dcservo's Introduction

dcservo

by misan

This project uses and Arduino (or similar) to create a closed-loop position control for a DC motor to act as a replacement of a stepper motor and its drive electronics. In order to be compatible with stepper logic controller accepts two inputs STEP and DIRECTION so an external trajectory controller can operate the motor as it would do with a stepper.

Screenshot

This code depends on the excellent Arduino PID library by Brett Beauregard: https://github.com/br3ttb/Arduino-PID-Library/

For easy configuration of PID parameters, serial port communication is used when adjusting them. PID values can be stored in EEPROM.

Servostrap project and Michael Ball's work sparked my curiosity to go create a simple solution for anyone to use.

I want to thank Brook Drum for his support on this project that started in here: https://www.youmagine.com/designs/dc-motor-closed-loop-control-software

Thanks to Mauro Manco for providing a NodeMCU. Now there is a version than can work with a ESP12E module, with support to accept commands over Wifi. Please note EEPROM storage code will not work in this platform :-(

Thanks to Robert Klauco for contributing the version for ATtiny85.

Allain Pelletier kindly provided the virtual end-stop feature code.

AMS provided free samples of magnetic encoder. Now the AS5600 encoder is supported for 12-bit/revolution resolution.

It is possible to detect endstops without the use of switches. If seeking an endstop upon reset is not necessary, this option can be commented out within setup(). It moves the motor in the negative direction at a lesser power level until an obstacle makes the error go up. This is the new endstop and a Zero offset can be added. Pin 4 is asserted if the position is now Zero or negative. Pin 4 is reset if the the position is positive. If the option A is active, the status of the home pin can be seen.

Two articles about the project were written for Circut Cellar Magazine and it is now freely available in the their website: https://circuitcellar.com/research-design-hub/projects/stepper-motor-emulator-part-1/ and https://circuitcellar.com/research-design-hub/projects/stepper-motor-emulator-part-2/

A video of hard homing can be seen https://youtu.be/kTUaKS-4Spc

Output stage

While an H-bridge is needed, there are many different choices out there, like L298, A4950, Monster Motor Shield, BTS7960, etc

Depending om your intended application the way the DC motor is control thrugh the H-bridge can be Sign-Magnitude drive http://modularcircuits.tantosonline.com/blog/articles/h-bridge-secrets/sign-magnitude-drive/ or Lock Anti-Phase drive http://www.modularcircuits.com/blog/articles/h-bridge-secrets/lock-anti-phase-drive/ though I have focus on the former, the latter may be preferred when braking action is important (like when a robot has to go downhill).

usage

Available serial commands: (lines end with CRLF or LF) 
P123.34 sets proportional term to 123.34
I123.34 sets integral term to 123.34
D123.34 sets derivative term to 123.34
? prints out current encoder, output and setpoint values
X123 sets the target destination for the motor to 123 encoder pulses
T will start a sequence of random destinations (between 0 and 2000) every 3 seconds. T again will disable that
Q will print out the current values of P, I and D parameters
W will store current values of P, I and D parameters into EEPROM
H will print this help message again
A will toggle on/off showing regulator status every second
L will execute homing

tuning tool

Written in Processing it allows you to see graphically the PID response to a step input while you can tune it by pressing capital P, I and D keys to increase values or p, i and d to lower them. Please have a look at this videos https://www.youtube.com/watch?v=uXnDwojRb1g and https://youtu.be/fusr9eTceEo Screenshot

trapezoidal motion profile

I reckon the evolution of this project is to offload motion profile generation off from main processor. In order to do that firmware needs to be able to achieve motion in a controlled way (which is key for joint axis movement). The first and simpler idea is to use a trapezoidal motion pattern.

New commands have been added for this feature:

F<max_velocity>
@<acceleration>
Y<destination> 

The latter is to perform the actual movement to an absolute destination, measured in encoder counts, using a trapezoidal speed motion pattern. No optimization effort in the math has yet been done.

You may want to check Paul's fork using Bluepill for handling three motors: https://github.com/paukstelis/dcservo

dcservo's People

Contributors

marcinanprofesjonalista avatar misan avatar pppalain avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

dcservo's Issues

Motor voltage and homing question

This is not specifically dcservo related, but it seems like there are some more general questions being asked here as well. Sorry if this is too off topic.

I'm using a scraped liquid handling robot (Tecan Freedom EVO75) to build a large 3D printer, primarily for the learning experience. Lots of reasons to not do it, so I'm doing it anyway! It original uses DC motors with closed loop servo control, though it uses custom motor drivers (the boards are also called DCSERVO). I've gotten the encoders working with dcservo, but I'm a bit stumped on the motor voltages. I don't have a way to trigger the motors from the original boards (that I have been able to figure out), but I can see that both Motor(+) and Motor(-) are at +10.7V. Any guesses if this would be the actual voltage at which the motors are run? The board is being fed 24V.

Second, how are most people handling homing with incremental encoders? Just end stops? Or is there a more clever way of finding position after a power cycle?

How to upload the PID Tuning tool

I am confused how to use the pid tuning tool. i plug in my arduino uno, and i open the pidtuning.pde sketch. when i try to upload it, i get the errors below. how do i properly upload and use the pid tool?

PIDtunningTool:9: error: 'import' does not name a type
import java.util.;
^
PIDtunningTool:10: error: 'import' does not name a type
import processing.serial.
;
^
PIDtunningTool:12: error: 'Serial' does not name a type
Serial myPort; // The serial port
^
/home/octo/Downloads/dcservo-master/PIDtunningTool/PIDtunningTool.pde: In function 'void setup()':
PIDtunningTool:19: error: 'size' was not declared in this scope
size(800, 400);
^
PIDtunningTool:21: error: 'PFont' was not declared in this scope
PFont myFont = createFont(PFont.list()[2], 14);
^
PIDtunningTool:22: error: 'myFont' was not declared in this scope
textFont(myFont);
^
PIDtunningTool:22: error: 'textFont' was not declared in this scope
textFont(myFont);
^
PIDtunningTool:23: error: 'frameRate' was not declared in this scope
frameRate(1);
^
PIDtunningTool:25: error: 'class HardwareSerial' has no member named 'list'
println(Serial.list());
^
PIDtunningTool:25: error: 'println' was not declared in this scope
println(Serial.list());
^
PIDtunningTool:26: error: 'class HardwareSerial' has no member named 'list'
String portName = Serial.list()[3];
^
PIDtunningTool:27: error: 'myPort' was not declared in this scope
myPort = new Serial(this, portName, 115200);
^
PIDtunningTool:27: error: expected type-specifier before 'Serial'
myPort = new Serial(this, portName, 115200);
^
/home/octo/Downloads/dcservo-master/PIDtunningTool/PIDtunningTool.pde: In function 'void draw()':
PIDtunningTool:31: error: 'strokeWeight' was not declared in this scope
strokeWeight(1);
^
PIDtunningTool:32: error: 'background' was not declared in this scope
background(255,100); stroke(255,0,0);
^
PIDtunningTool:32: error: 'stroke' was not declared in this scope
background(255,100); stroke(255,0,0);
^
PIDtunningTool:33: error: 'line' was not declared in this scope
line(0,400-333,600,400-333);
^
PIDtunningTool:38: error: 'myPort' was not declared in this scope
while(myPort.available()>0) print(char(myPort.read()));
^
PIDtunningTool:38: error: 'print' was not declared in this scope
while(myPort.available()>0) print(char(myPort.read()));
^
PIDtunningTool:41: error: 'myPort' was not declared in this scope
myPort.write('X');
^
PIDtunningTool:56: error: 'Scanner' was not declared in this scope
Scanner sc = new Scanner(s);
^
PIDtunningTool:59: error: 'sc' was not declared in this scope
while(sc.hasNextInt()) {
^
PIDtunningTool:62: error: 'point' was not declared in this scope
point(x++, 400-c);
^
/home/octo/Downloads/dcservo-master/PIDtunningTool/PIDtunningTool.pde: In function 'void keyPressed()':
PIDtunningTool:73: error: 'key' was not declared in this scope
if(key=='P') {
^
PIDtunningTool:75: error: 'myPort' was not declared in this scope
myPort.write('P');
^
PIDtunningTool:76: error: invalid operands of types 'const char [1]' and 'float' to binary 'operator+'
String out=""+kp; for(int i=0; i<out.length();i++) myPort.write(out.charAt(i));
^
PIDtunningTool:79: error: invalid operands of types 'const char [3]' and 'float' to binary 'operator+'
println("P="+kp);
^
PIDtunningTool:79: error: 'println' was not declared in this scope
println("P="+kp);
^
PIDtunningTool:81: error: 'key' was not declared in this scope
if(key=='p') {
^
PIDtunningTool:83: error: 'myPort' was not declared in this scope
myPort.write('P');
^
PIDtunningTool:84: error: invalid operands of types 'const char [1]' and 'float' to binary 'operator+'
String out=""+kp; for(int i=0; i<out.length();i++) myPort.write(out.charAt(i));
^
PIDtunningTool:87: error: invalid operands of types 'const char [3]' and 'float' to binary 'operator+'
println("P="+kp);
^
PIDtunningTool:87: error: 'println' was not declared in this scope
println("P="+kp);
^
PIDtunningTool:89: error: 'key' was not declared in this scope
if(key=='D')
^
PIDtunningTool:92: error: 'myPort' was not declared in this scope
myPort.write('D');
^
PIDtunningTool:93: error: invalid operands of types 'const char [1]' and 'float' to binary 'operator+'
String out=""+kd; for(int i=0; i<out.length();i++) myPort.write(out.charAt(i));
^
PIDtunningTool:96: error: invalid operands of types 'const char [3]' and 'float' to binary 'operator+'
println("D="+kd);
^
PIDtunningTool:96: error: 'println' was not declared in this scope
println("D="+kd);
^
PIDtunningTool:98: error: 'key' was not declared in this scope
if(key=='d') {
^
PIDtunningTool:100: error: 'myPort' was not declared in this scope
myPort.write('D');
^
PIDtunningTool:101: error: invalid operands of types 'const char [1]' and 'float' to binary 'operator+'
String out=""+kd; for(int i=0; i<out.length();i++) myPort.write(out.charAt(i));
^
PIDtunningTool:104: error: invalid operands of types 'const char [3]' and 'float' to binary 'operator+'
println("D="+kd);
^
PIDtunningTool:104: error: 'println' was not declared in this scope
println("D="+kd);
^
PIDtunningTool:106: error: 'key' was not declared in this scope
if(key=='I') {
^
PIDtunningTool:108: error: 'myPort' was not declared in this scope
myPort.write('I');
^
PIDtunningTool:109: error: invalid operands of types 'const char [1]' and 'float' to binary 'operator+'
String out=""+ki; for(int i=0; i<out.length();i++) myPort.write(out.charAt(i));
^
PIDtunningTool:112: error: invalid operands of types 'const char [3]' and 'float' to binary 'operator+'
println("I="+ki);
^
PIDtunningTool:112: error: 'println' was not declared in this scope
println("I="+ki);
^
PIDtunningTool:114: error: 'key' was not declared in this scope
if(key=='i') {
^
PIDtunningTool:116: error: 'myPort' was not declared in this scope
myPort.write('I');
^
PIDtunningTool:117: error: invalid operands of types 'const char [1]' and 'float' to binary 'operator+'
String out=""+ki; for(int i=0; i<out.length();i++) myPort.write(out.charAt(i));
^
PIDtunningTool:120: error: invalid operands of types 'const char [3]' and 'float' to binary 'operator+'
println("I="+ki);
^
PIDtunningTool:120: error: 'println' was not declared in this scope
println("I="+ki);
^
PIDtunningTool:122: error: 'key' was not declared in this scope
if(key=='W') {
^
PIDtunningTool:123: error: 'myPort' was not declared in this scope
myPort.write('W');
^
PIDtunningTool:126: error: 'println' was not declared in this scope
println("Values stored.");
^
PIDtunningTool:128: error: 'key' was not declared in this scope
if(key=='Q') {
^
PIDtunningTool:129: error: 'myPort' was not declared in this scope
myPort.write('Q');
^
PIDtunningTool:132: error: 'println' was not declared in this scope
println("Values requested.");
^
exit status 1
'import' does not name a type

ADNS-3050 Optical Sensor Version / RC Servo

This library is simply spetacular! If we could make it work with continuous rotation RC servos, without any additional hardware, it would be a dream coming true...

Also, what about using this library/sensor for an optical closed loop version?

https://github.com/Tom101222/Adns-3050-Optical-Sensor

This would provide a path to make a low cost robot platform that everyone of us could use, and open the door for this:

https://www.youtube.com/watch?v=ctIJdL9Bs94

Cheers from Portugal!

Modification a larger H-Bridge

Hello,
I'm attempting to adapt this for use with a larger H-Bridge (IBT-2) high current module.
The H-Bridge has right and left enable and pwm pins. I've changed the pin layout in the sketch to correspond with the wiring which makes the most sense in my system. I've been using these H-Bridges for a couple of years and usually have a decent grasp of their use, but it's late and I'm not making any headway.

#define encoder0PinA 8 // PD2;
#define encoder0PinB 9 // PC0;
#define M1 5 // RPWM on IBT-2
#define M2 6 // LPWM on IBT-2
#define ENABLE_1 4 R-EN on IBT-2
#define ENABLE_2 7 L-EN on IBT-2

I've attached my sketch which really has no changes with the exception of the addition of the enable pins and their being declared HIGH in the setup() function.

It's clearly late because I nearly forgot to include the problem. It's not working! :) I'm not getting any motion, it's compiling just fine and I've got serial comms but I'm not getting the HBridge to work correctly.

Any ideas, I'd really appreciate it?

Thank you,
Pierre

https://gist.github.com/PierreAuge/79c03b8b5e85f0df4993ff28212f97fb

ibt-2-input-ports

Trapezoidal speed motion pattern

Hi misan, I hope you are well. First of all, I wanted to congratulate you on the excellent work you have done.

You could explain roughly the advantages of using the trapezoidal speed motion pattern.

Thank you very much and greetings from Argentina

Encoder precision, poor in atmega328

Between the two interrupts available to count the quadrature signals on Atemga328, it is really too much work for this device. I found by adding a quadrature decoder component between the encoder and arduino, i was able to get precision from the highest speed at 24 volts tested with flauhauber micro geared motors with 512 point encoders. These motors were pulled from factory pick and place machines from a wafer production lab.

A quadrature signal simply sends too much information for arduino to keep up with, and have enough time left over to be useful for anything else, and struggles for timing to drive pwm accel curve for the output. With the decoder, it divided the encoder rise and fall edges and produced a common step and direction signal that the 2 interupts had time to handle.

I can not remember which one of the books I have my notes in for the project, after I find it I can show you the part # and some more facts of the test results.

I appreciate your work on the s curve calculation. i was trying (and failing) so much with it myself.

how can use STK681-050

hello
i have STK681-050 ic, Bidirectional DC Brush-Type Motor Driver (IO=5A).
this driver have 4 pin , INA, INB, INC, IND.
how can connect dcservo to this driver?
STK681-050.pdf
image_001

What type of steps/sec will this run?

No sure if this is the correct place to ask, but I am interested in what sort of (KHz) step rate this will run up to, specifically on the ESP8266, but also interested for Arduino

dc motor and servo and motor shield adafruit !!!!! plzz need help!!/:

i've been programming my robot with the adafruit v2 motor shield! everything works perfectly without the servo! but when i plug in the servo
the DC motors of my robot stops working and the servo keeps turning from 0 to 180 degree. and when i unplug the servo the DC motors of my robots starts to work perfectly .
so my DC motors doesn't work when i plug in the servo!
can someone explain to me what the problem!

plzz i really need help!!??

Adding a hard endstop detection

I am designing a 3d printer using these motors. I have no intention to add endstops. Here is an option I will be adding.

If motor is energized and the counter can no longer count because of a physical barrier. The controller can detect that to signal an endstop. This should reduce physical switches for each axis.

When an endstop request signal is detected motor should only be energized enough for motion.

proposed autodetect the minimum pwm needed for motion upon startup
proposed endstop request input pin. from an external controller such as Marlin
proposed endstop detect output pin. To controller such as marlin

Backlash correction?

I'm using geared motors and there is a reasonable amount of backlash. What is your thought on where best to implement this? It seems that we could fairly easily track direction from the pwm output and just look for cases when direction changes and modify the target position with +/- the number of encoder steps needed. This seems too easy, so I'm sure I'm missing some critical factor here!

Bad implementation of PWM overheating motor

I revisited the implementation of PWM after burning a motor (melting the 3d printed carriage) and getting a really bad electronic burning smell. It shouldn't have gotten that hot.
I am using the l298 and I noticed this from the datasheet:

if the motor is enabled and the outputs are both high or both low, the motor is in braking mode.
if the motor is disabled the motor coast.
I had in the past experimented with this but forgot about it.
The PWM pin should be the motor enable.
dynamic breaking should only be activated when error is 0.
otherwise the motor should be coasting.

so 3 pins are needed for correct operation. One PWM pin and two direction pins

The current implementations make the motor turn a bit and immediately break.
dynamic breaking makes the motor heat significantly. This is done at every pwm cycle (31khz)

This is something I had done a while ago but completely forgot.

Marlin I2C?

It seems like Marlin now has included quite a bit of I2C code for some of these Aus3D encoder/steppers. This got me thinking that it might be better moving forward for DC motors to do I2C to set/get encoder positions directly from the firmware with feedback from the motor control module to let the firmware know that each axis has completed its move. Is this ultimately the idea of the trapezoidal system?

Pro Micro pin reassignment?

Bit of a noob question: I want to free up pins 2 and 3 on the Pro Micro for I2C. If I put encoder interrupts on Pin 1 and Pin 7, what would need to change in encoderInt function? Port manipulations scare me.

Sudden reverse movement

Hi Misan.

Thanks for sharing your firmware with the world.

I have a problem with the code.
I have designed an extruder,tuned it using the tuning software, works like a charm. Commanding it from serial port works also.
But, when controlling from driver board via dir step interface, the motor suddenly reverses the output, before stopping and extruding like normal. It doesnt go back to where it reversed from, just going forward like nothing happened.
I checked position, target and PID output. Position and target were close together, all normal. PID was negative 255, so of course it was going backwards.
I'm debugging right now, but perhaps ypu have seen issues like this before? Thanks.

How to use PID tuning tool?

Hi,
I try to understand how to use PID tuning tool, but can not :( Start, I was open sketch in Process3. Then change usb port. In Arduino Uno I have "dcservo" sketch. When run sketch into Process3 my DC motor forward and backward, but not stable.
How can I change PID values?

Ad Stepper support

Hello Misan,
Steppers are cheap and have much more torque than DC Motors in same size, can you add option to output Step/Dir signal?
I think it would be a great new feature.
Could you ad "bluepill" support? it's a great board with many features like hardware AB decoder and can bus.

Feature Request: PID autotuning

It would be great to add to the program algorithm for the automatic calibration of PID.
Similar to the way it is implemented in Marlin.

little modification

Hi Misan,
I'm trying to use your arduino sketch, but I want to compile it for Arduino nano or Arduino pro.

And on my h-bridge board:http://www.ebay.fr/itm/Dual-Motor-Driver-Module-Board-H-bridge-DC-MOSFET-IRF3205-3-36V-10A-30A-TE589-/381782113555?hash=item58e3fcbd13:g:X9IAAOSwmLlX4uGE
there is only one PWM input, and one "pin dir". So to make the motor turn clockwise or reverse either I activate the pin dir, or I deactivate the pin dir. Is it possible to do this ? and how can i do this please ?
Thanks !

problem with my project.

Hello, i am new guy to write program. I am doing the project about the Robot goalkeeper. First, i would like to know if we use this code to make a closed loop dc motor, is it possible? second, I have incremental rotary encoder but i do not know how to change from potentiomenter to incremental encoder. Third, how abot the STEP and ENDSTOP. I use L298N and there was the 2 input and pwm channel for 1 motor.
Thank you

dcservo_pro_micro doesn't compile

Arduino IDE 1:1.0.5-dfsg2-2 reports:

arduino_pro_micro_servo_with_serial_interface.ino: In function ‘void countStep()’:
arduino_pro_micro_servo_with_serial_interface.ino:109:23: error: ‘PINF’ was not declared in this scope

I think replacing 'PINF' with 'analogRead(A0)' might fix this? For speed I'm going to change dir to digital 10 and do a digitalRead of that and see if that works.

dcservo.ino assigns long to byte

The "example" assigns "POS" as a byte, yet - assigns the LONG encoder position to this BYTE array.... Not sure how this actually would work

byte pos[1000]; int p=0;
volatile long encoder0Pos = 0;
double input=0, output=0, setpoint=0;

pos[p]=encoder0Pos; 

AMS Sensor.

You mentioned AS6500 as rotary encoder in Readme.md. Maybe a typo for AS5600 ?

nodemcu motordriver shield

Miguel,

I've got a few of these laying around (nodemcu v1 motor shield) they are a couple dollars and sport an l293dd full bridge driver with two 1.2amp peak DC output lines.

I've been wanting to implement your dcservo driver library on this thing for a bit to see how it would drive two little dcservos.

I'd like your help, I'm not much of a coder, but I'd be happy to send you a nodemcu with a shield for you to play with if you help me out.

Thanks Pierre

PId Tuning tool not displayng graph correctly

Hello,

I am currently working on modifying a old school milling machine, modifying it using grbl and your amazing code for the servos, I am using windshield wiper motors to move the axes, encoders from china and 3d printed encoder discs but i have hit a sinkhole:) these are the issues I am currently facing:

  • cant get the pid tuning tool to display correctly the graph( it shows only on the 1st square of the whole graph and slowly moves down, motors overheating from bad pid, and after moving say x axis, after it stops, starts jogging back and forward.
  • when lifting z all axes are going crazy
    I am using 3 arduino nano for driving 3 IBT_2 H bridges and a arduino nano running grbl.

Thank you very much for all the support provided.

Kind Regards,
Robert.
whatsapp image 2018-08-10 at 12 13 34
whatsapp image 2018-08-10 at 12 13 54 1
whatsapp image 2018-08-10 at 12 13 54 2
whatsapp image 2018-08-24 at 16 40 06
whatsapp image 2018-08-24 at 16 40 07
whatsapp image 2018-09-11 at 18 52 05

Replace INT with LONG

Hi.

I found out why my Z axis worked so erratically.
It was not due the frequency or missed pulses.
The problem is resolution.
As I have 4096 pulses per one rotation (and therefore 1mm of movement) I run out of INT space after 8mm in any direction.
Initially I changed the values for encoder0pos, but I also had to change it for target1.
I have no idea why, but the compiler for ATmega328 compiles INT with the same size as LONG - therefore testing the code on Arduino Mini Pro worked every time, but as soon as I ported the code to ATtiny85, I got this weird behavior.
Stupid error - it took me a month to find it :(
But now even my Z axis works flawlessly ;)
I can't give you pull request as I made so big mess with my code I have to clean it up quite a lot.

Can i use a encoder with step only instead of a quadrature encoder

Good day, many thanks for making your work public, i was wondering if it would be possible to use a step only encoder (no direction) with your project to control the position of large dc motor, ramps will still send its normal step and dir but the closed loop will only be on steps, is this possible?

many thanks
Tony

setting of P, I, D?

how can set best value of P, I, D for current motor?
and i use gearbox for DC motor, the best place for rotary encoder, connect after gearbox or direct connect to motor?

step pulse duration

hello.
I'm using GRBL with a vinyl cutter
and some times , with long travels , I've got some hard reset on the system.
Maybe it's the speed is too high
250steps/mm
max speed 20000mm/mn
accel : 300mm/s/s

Maybe it's because my motors take too much of current (speed too high)

but I wonder if this is not a problem of pulse duration for the DC drivers
the default value in GRBL is 10ms
is a realiste value for the dcservo or it need adjustement?

thanks

Incorrect output in 'S' command.

With the exception of the dcservoProMicro_trapezoidal.ino file, all the others have it wrong when responding the 'S' command.

The idea of that command is that you can monitor the execution of the last move ('X' command) which is useful for tuning purposes. However the command should provide a sample value of the encoder input every few milliseconds.

The error was that PID.Compute() call returns whether it calculate a new value or not, so each loop is not taking 1ms but an unspecified amount of time, possible lower many times.

A while loop can keep on calling PID.Compute() till it finally calculates a new output (because it was about time as 1ms passed) and this way make sure the loop runs once every 1ms, so each sample is now correct. I will fix that when I have a moment, but now you know about the problem and how to fix it.

Instructions for ESP

Can't get it to work on an nodemcu module.
changed the pins to #define, also led pin does not work on all esp modules with internal led command.
Would suggest to program the encoder input by default with _PULLUP function as that's what most encoders work with.
also how does the server work? serial only promts the first lines and no communication afterwards possible.
General //dokumentation inside program could help much.

atmega8 support..

I know it's possible to upload the sketch to atmega8, my question is, do I need to modify the code by any means?!

Thank you for your great effort.

Here in my town hundreds of printers - (inkjets the most) - are just wasted to the landfills, I am planning to collect it all, hack it, hook a cheap atmega8 on the two optical encoders along with the DC motors in it and a cheap l293d h-bridge IC and there it is!! a cheap, fast, closed loop motion system.

I plan to build cnc plotters out of it for the sake of speed!! 😇😉, also it will be a charity work, I will send to each school in town a nice diy plotter to teach the students what cnc technology can offer for us, it will be a great purpose out of those printers, instead of going to landfills, I hope some one will be inspired by this work.

Parts:
1 - inkjet printer. 1.qty
2 - L293D h-bridge 1.qty
3 - atmega8 1-2.qty -till now don't know for -sure.
4 - Arduino UNO (breadboard version along with SD card module) 1.qty
5 - some wood and MDF, nuts and bolts, bearings.

Price:
1- an inkjet printer is as I said before in hundreds here in my town, I can get some for free and some other I can buy at 1-2$ maximum.

2- i 've studied lot's of printers DC motors, all of them require less than 600mAh, so l293d IC is great cheap choice to drive them and it's price here in my town 1.5$.

3- the atmega8A-PU is 1.5$.

4- Arduino: a costume veroboard with atmega328P-PU, and SD card module for portability cost both 5.5$.

5- the wood blocks or/and MDF is used in small sizes, I bit I can get those for free or near free and with nuts and bolts sold per 3$ for 1KG, I guess it will be sufficient.

Total cost will be around/between 14.5$ - 20$ maximum per full working plotter.

For the h-bridge, I've managed to salvage many from laser printers -95% of laser printers have h-bridge ICs in it- , also available here by ten's, along with a minimum 2 solinoids per one printer, the solinoid well work as pen UP/DOWN mechanism. All this will further minimize the total cost per plotter. and Time?! I have a lot of it 😇☺.

Thank you again.
If my English is bad, forgive me.

Ira, from Syria.

Use with Cytron 13A Driver

Hello,
First things first, thank you for the brilliant work and making it available for all.
Now, I am thinking of using a larger, more powerful DC motor that may draw a lot more current than L298N can handle. I want to try the Cytron 13A driver. Unlike the L298 it doesn't have a IN1 and IN2 but has a PWM and DIR input. I am wondering if the following modification to the original work.

void pwmOut(int out) {
if(out<0) { digitalWrite(M1,0); analogWrite(M2,abs(out)); }
else { digitalWrite(M1,1); analogWrite(M2,abs(out)); }
}

where M1 connects to DIR and M2 to PWM. I believe it should work but I can't get my head around some other parts of the code to be really sure.

Thanks for your advice.

Best Regards
Vikram

missing includes ?

Hi,
looks like the includes:

include EEPROM.h

include PID_v1.h

Are missing in your repo.

DCservo for milling?

Hi Miguel,

a couple of weeks ago, i tried out your work with a linearsystem of an old colour printer and it wokred well. It is fanstastic - Now i am thinking about building a cnc Mill instead of an 3DPrinter with your servosolution.

And here is my question:
When marlin or chillipepr is sending steps and direktion to your arduino-servocontroller, I gues it is sending an amount of step signals in a certain direction in a specific time.
But it gets no feedback, and though it does not know whitch step the motor is performing and with whitch volocety it is mooving.

In case something is going wrong, and the linearsysthem is sticking somewhere, the PID-regulator would strengthen the power of the motor, to reach the position the axis is heading for.

When the resistence is overcome, the axis will move much faster to the defined position, than my feedrate would allow.

For a printer not a big deal, for a mill a problem.

Is there a posibility to let marlin or Chillipepper or maybe Keeflop knwo, that the DC-Servo is behind its job and than break down the whole work in process?

Is the DC servo following the commands from the CNC -Controler step by step? and is there a posibility to make the motor follow just one step with maximal force? - just like a steppermotor?

What is the servocontrol doing with the steps, which it could not process in the demandet time?
does it have a buffer or memory so an intelligence is working here, of which the cnc-controler(Marlin oder Chillipepper) has no clue of?

How could i control the maximum speed of the processed command to take care of the problem to exeed the maximal feedrate of my millingjob?

I know, these are a lot of questioins and maybe I am asking the wrong person, because you did this whole project not for milling but for printing -

Anyway, I am so impressed about your work, that I would love to use it instead of using Steppermotors.
Just because it is so cool, what you accomplished.

Great great respect:

And If you would have an idea for me - wonderful.

Thanks a lot

Greetings from Munic

Joachim

attiny85 pins

does motorpwm1 and 2 go to the h bridge? also, how do i get the P, I, and D values for tuning? why are there 2 encoders(a and b)?

PINF question (error)

Hi
i want to experiment with a arduino pro mini (or nano) with this code
so when i am using the dcServoProMicro.ino to compile i am getting this error :

void countStep(){ if (PINF&B10000000) target1--;else target1++; } // pin A0 represents direction == PF7 en Pro Micro ^ exit status 1 'PINF' was not declared in this scope

Ok this is because on arduino pro mini the pin ports registers are different

for AO pin (PINF in ProMicro) in ProMini would be PINC

so when i change that to the code i can compile without any arror

my question has to do if it is worth it to try that code with an arduino pro mini for low speed motor

not finishing sequence

Hi Misan,
first of all, great work ;)
But now i´m facing some strange behavior. My setup is a micro pro with 612fng and a faulhaber-dc-motor with quad-encoder. steps and DIR is sent from a Printrboard. So far I managed to get it working. My big problem now is, if I sent G0 X50, motor is driving to its position, but if I´m immediately sent G0 X0, the motor is not driving to position 50. It is only moving to ca. X14 and then turns back to X0.
The same is happening when i open a file with these orders.
Especially for milling I prefer to use equal sequences.
So my question, am I doing something wrong or is there a limitation in your code or what is the problem.
Maby you can help me.
But so far I can only say you are the man ;) who changed my life :) never thought to use my faulhabers :)
best regards
mcarosh

Hi I want to build this project below :

Hi ,
I want to build this project below :

http://www.brokking.net/yabr_main.html.

I want to use all same parts except instead of servo he is using I want to use following motors:

The label reads : Pittman LO-COG 9434j817-R1 6501033 rev. D 24VDC 400 CPR
It has built in hall sensor encoder. Info for this motor is not much on web but I found following link where there is some information:

http://hades.mech.northwestern.edu/images/5/50/Pittmangearmotor.pdf

pittman
pittman1

My question is can I use these motors using your software and L298N Dual Motor Controller Module?

If it is possible how to implement your code in his code ?

Are these motors comparable to NEMA17 or NEMA23 in torque measurement with your code?

Is it possible to build same project using ESP8266 microcontroller?

Code is below :

`//////////////////////////////////////////////////////////////////////////////////////
//Terms of use
///////////////////////////////////////////////////////////////////////////////////////
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
//THE SOFTWARE.
///////////////////////////////////////////////////////////////////////////////////////

#include <Wire.h> //Include the Wire.h library so we can communicate with the gyro

int gyro_address = 0x68; //MPU-6050 I2C address (0x68 or 0x69)
int acc_calibration_value = 1000; //Enter the accelerometer calibration value

//Various settings
float pid_p_gain = 15; //Gain setting for the P-controller (15)
float pid_i_gain = 1.5; //Gain setting for the I-controller (1.5)
float pid_d_gain = 30; //Gain setting for the D-controller (30)
float turning_speed = 30; //Turning speed (20)
float max_target_speed = 150; //Max target speed (100)

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//Declaring global variables
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
byte start, received_byte, low_bat;

int left_motor, throttle_left_motor, throttle_counter_left_motor, throttle_left_motor_memory;
int right_motor, throttle_right_motor, throttle_counter_right_motor, throttle_right_motor_memory;
int battery_voltage;
int receive_counter;
int gyro_pitch_data_raw, gyro_yaw_data_raw, accelerometer_data_raw;

long gyro_yaw_calibration_value, gyro_pitch_calibration_value;

unsigned long loop_timer;

float angle_gyro, angle_acc, angle, self_balance_pid_setpoint;
float pid_error_temp, pid_i_mem, pid_setpoint, gyro_input, pid_output, pid_last_d_error;
float pid_output_left, pid_output_right;

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//Setup basic functions
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void setup(){
Serial.begin(9600); //Start the serial port at 9600 kbps
Wire.begin(); //Start the I2C bus as master
TWBR = 12; //Set the I2C clock speed to 400kHz

//To create a variable pulse for controlling the stepper motors a timer is created that will execute a piece of code (subroutine) every 20us
//This subroutine is called TIMER2_COMPA_vect
TCCR2A = 0; //Make sure that the TCCR2A register is set to zero
TCCR2B = 0; //Make sure that the TCCR2A register is set to zero
TIMSK2 |= (1 << OCIE2A); //Set the interupt enable bit OCIE2A in the TIMSK2 register
TCCR2B |= (1 << CS21); //Set the CS21 bit in the TCCRB register to set the prescaler to 8
OCR2A = 39; //The compare register is set to 39 => 20us / (1s / (16.000.000MHz / 8)) - 1
TCCR2A |= (1 << WGM21); //Set counter 2 to CTC (clear timer on compare) mode

//By default the MPU-6050 sleeps. So we have to wake it up.
Wire.beginTransmission(gyro_address); //Start communication with the address found during search.
Wire.write(0x6B); //We want to write to the PWR_MGMT_1 register (6B hex)
Wire.write(0x00); //Set the register bits as 00000000 to activate the gyro
Wire.endTransmission(); //End the transmission with the gyro.
//Set the full scale of the gyro to +/- 250 degrees per second
Wire.beginTransmission(gyro_address); //Start communication with the address found during search.
Wire.write(0x1B); //We want to write to the GYRO_CONFIG register (1B hex)
Wire.write(0x00); //Set the register bits as 00000000 (250dps full scale)
Wire.endTransmission(); //End the transmission with the gyro
//Set the full scale of the accelerometer to +/- 4g.
Wire.beginTransmission(gyro_address); //Start communication with the address found during search.
Wire.write(0x1C); //We want to write to the ACCEL_CONFIG register (1A hex)
Wire.write(0x08); //Set the register bits as 00001000 (+/- 4g full scale range)
Wire.endTransmission(); //End the transmission with the gyro
//Set some filtering to improve the raw data.
Wire.beginTransmission(gyro_address); //Start communication with the address found during search
Wire.write(0x1A); //We want to write to the CONFIG register (1A hex)
Wire.write(0x03); //Set the register bits as 00000011 (Set Digital Low Pass Filter to ~43Hz)
Wire.endTransmission(); //End the transmission with the gyro

pinMode(2, OUTPUT); //Configure digital poort 2 as output
pinMode(3, OUTPUT); //Configure digital poort 3 as output
pinMode(4, OUTPUT); //Configure digital poort 4 as output
pinMode(5, OUTPUT); //Configure digital poort 5 as output
pinMode(13, OUTPUT); //Configure digital poort 6 as output

for(receive_counter = 0; receive_counter < 500; receive_counter++){ //Create 500 loops
if(receive_counter % 15 == 0)digitalWrite(13, !digitalRead(13)); //Change the state of the LED every 15 loops to make the LED blink fast
Wire.beginTransmission(gyro_address); //Start communication with the gyro
Wire.write(0x43); //Start reading the Who_am_I register 75h
Wire.endTransmission(); //End the transmission
Wire.requestFrom(gyro_address, 4); //Request 2 bytes from the gyro
gyro_yaw_calibration_value += Wire.read()<<8|Wire.read(); //Combine the two bytes to make one integer
gyro_pitch_calibration_value += Wire.read()<<8|Wire.read(); //Combine the two bytes to make one integer
delayMicroseconds(3700); //Wait for 3700 microseconds to simulate the main program loop time
}
gyro_pitch_calibration_value /= 500; //Divide the total value by 500 to get the avarage gyro offset
gyro_yaw_calibration_value /= 500; //Divide the total value by 500 to get the avarage gyro offset

loop_timer = micros() + 4000; //Set the loop_timer variable at the next end loop time

}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//Main program loop
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void loop(){
if(Serial.available()){ //If there is serial data available
received_byte = Serial.read(); //Load the received serial data in the received_byte variable
receive_counter = 0; //Reset the receive_counter variable
}
if(receive_counter <= 25)receive_counter ++; //The received byte will be valid for 25 program loops (100 milliseconds)
else received_byte = 0x00; //After 100 milliseconds the received byte is deleted

//Load the battery voltage to the battery_voltage variable.
//85 is the voltage compensation for the diode.
//Resistor voltage divider => (3.3k + 3.3k)/2.2k = 2.5
//12.5V equals ~5V @ Analog 0.
//12.5V equals 1023 analogRead(0).
//1250 / 1023 = 1.222.
//The variable battery_voltage holds 1050 if the battery voltage is 10.5V.
battery_voltage = (analogRead(0) * 1.222) + 85;

if(battery_voltage < 1050 && battery_voltage > 800){ //If batteryvoltage is below 10.5V and higher than 8.0V
digitalWrite(13, HIGH); //Turn on the led if battery voltage is to low
low_bat = 1; //Set the low_bat variable to 1
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//Angle calculations
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Wire.beginTransmission(gyro_address); //Start communication with the gyro
Wire.write(0x3F); //Start reading at register 3F
Wire.endTransmission(); //End the transmission
Wire.requestFrom(gyro_address, 2); //Request 2 bytes from the gyro
accelerometer_data_raw = Wire.read()<<8|Wire.read(); //Combine the two bytes to make one integer
accelerometer_data_raw += acc_calibration_value; //Add the accelerometer calibration value
if(accelerometer_data_raw > 8200)accelerometer_data_raw = 8200; //Prevent division by zero by limiting the acc data to +/-8200;
if(accelerometer_data_raw < -8200)accelerometer_data_raw = -8200; //Prevent division by zero by limiting the acc data to +/-8200;

angle_acc = asin((float)accelerometer_data_raw/8200.0)* 57.296; //Calculate the current angle according to the accelerometer

if(start == 0 && angle_acc > -0.5&& angle_acc < 0.5){ //If the accelerometer angle is almost 0
angle_gyro = angle_acc; //Load the accelerometer angle in the angle_gyro variable
start = 1; //Set the start variable to start the PID controller
}

Wire.beginTransmission(gyro_address); //Start communication with the gyro
Wire.write(0x43); //Start reading at register 43
Wire.endTransmission(); //End the transmission
Wire.requestFrom(gyro_address, 4); //Request 4 bytes from the gyro
gyro_yaw_data_raw = Wire.read()<<8|Wire.read(); //Combine the two bytes to make one integer
gyro_pitch_data_raw = Wire.read()<<8|Wire.read(); //Combine the two bytes to make one integer

gyro_pitch_data_raw -= gyro_pitch_calibration_value; //Add the gyro calibration value
angle_gyro += gyro_pitch_data_raw * 0.000031; //Calculate the traveled during this loop angle and add this to the angle_gyro variable

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//MPU-6050 offset compensation
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//Not every gyro is mounted 100% level with the axis of the robot. This can be cause by misalignments during manufacturing of the breakout board.
//As a result the robot will not rotate at the exact same spot and start to make larger and larger circles.
//To compensate for this behavior a VERY SMALL angle compensation is needed when the robot is rotating.
//Try 0.0000003 or -0.0000003 first to see if there is any improvement.

gyro_yaw_data_raw -= gyro_yaw_calibration_value; //Add the gyro calibration value
//Uncomment the following line to make the compensation active
//angle_gyro -= gyro_yaw_data_raw * 0.0000003; //Compensate the gyro offset when the robot is rotating

angle_gyro = angle_gyro * 0.9996 + angle_acc * 0.0004; //Correct the drift of the gyro angle with the accelerometer angle

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//PID controller calculations
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//The balancing robot is angle driven. First the difference between the desired angel (setpoint) and actual angle (process value)
//is calculated. The self_balance_pid_setpoint variable is automatically changed to make sure that the robot stays balanced all the time.
//The (pid_setpoint - pid_output * 0.015) part functions as a brake function.
pid_error_temp = angle_gyro - self_balance_pid_setpoint - pid_setpoint;
if(pid_output > 10 || pid_output < -10)pid_error_temp += pid_output * 0.015 ;

pid_i_mem += pid_i_gain * pid_error_temp; //Calculate the I-controller value and add it to the pid_i_mem variable
if(pid_i_mem > 400)pid_i_mem = 400; //Limit the I-controller to the maximum controller output
else if(pid_i_mem < -400)pid_i_mem = -400;
//Calculate the PID output value
pid_output = pid_p_gain * pid_error_temp + pid_i_mem + pid_d_gain * (pid_error_temp - pid_last_d_error);
if(pid_output > 400)pid_output = 400; //Limit the PI-controller to the maximum controller output
else if(pid_output < -400)pid_output = -400;

pid_last_d_error = pid_error_temp; //Store the error for the next loop

if(pid_output < 5 && pid_output > -5)pid_output = 0; //Create a dead-band to stop the motors when the robot is balanced

if(angle_gyro > 30 || angle_gyro < -30 || start == 0 || low_bat == 1){ //If the robot tips over or the start variable is zero or the battery is empty
pid_output = 0; //Set the PID controller output to 0 so the motors stop moving
pid_i_mem = 0; //Reset the I-controller memory
start = 0; //Set the start variable to 0
self_balance_pid_setpoint = 0; //Reset the self_balance_pid_setpoint variable
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//Control calculations
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
pid_output_left = pid_output; //Copy the controller output to the pid_output_left variable for the left motor
pid_output_right = pid_output; //Copy the controller output to the pid_output_right variable for the right motor

if(received_byte & B00000001){ //If the first bit of the receive byte is set change the left and right variable to turn the robot to the left
pid_output_left += turning_speed; //Increase the left motor speed
pid_output_right -= turning_speed; //Decrease the right motor speed
}
if(received_byte & B00000010){ //If the second bit of the receive byte is set change the left and right variable to turn the robot to the right
pid_output_left -= turning_speed; //Decrease the left motor speed
pid_output_right += turning_speed; //Increase the right motor speed
}

if(received_byte & B00000100){ //If the third bit of the receive byte is set change the left and right variable to turn the robot to the right
if(pid_setpoint > -2.5)pid_setpoint -= 0.05; //Slowly change the setpoint angle so the robot starts leaning forewards
if(pid_output > max_target_speed * -1)pid_setpoint -= 0.005; //Slowly change the setpoint angle so the robot starts leaning forewards
}
if(received_byte & B00001000){ //If the forth bit of the receive byte is set change the left and right variable to turn the robot to the right
if(pid_setpoint < 2.5)pid_setpoint += 0.05; //Slowly change the setpoint angle so the robot starts leaning backwards
if(pid_output < max_target_speed)pid_setpoint += 0.005; //Slowly change the setpoint angle so the robot starts leaning backwards
}

if(!(received_byte & B00001100)){ //Slowly reduce the setpoint to zero if no foreward or backward command is given
if(pid_setpoint > 0.5)pid_setpoint -=0.05; //If the PID setpoint is larger then 0.5 reduce the setpoint with 0.05 every loop
else if(pid_setpoint < -0.5)pid_setpoint +=0.05; //If the PID setpoint is smaller then -0.5 increase the setpoint with 0.05 every loop
else pid_setpoint = 0; //If the PID setpoint is smaller then 0.5 or larger then -0.5 set the setpoint to 0
}

//The self balancing point is adjusted when there is not forward or backwards movement from the transmitter. This way the robot will always find it's balancing point
if(pid_setpoint == 0){ //If the setpoint is zero degrees
if(pid_output < 0)self_balance_pid_setpoint += 0.0015; //Increase the self_balance_pid_setpoint if the robot is still moving forewards
if(pid_output > 0)self_balance_pid_setpoint -= 0.0015; //Decrease the self_balance_pid_setpoint if the robot is still moving backwards
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//Motor pulse calculations
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//To compensate for the non-linear behaviour of the stepper motors the folowing calculations are needed to get a linear speed behaviour.
if(pid_output_left > 0)pid_output_left = 405 - (1/(pid_output_left + 9)) * 5500;
else if(pid_output_left < 0)pid_output_left = -405 - (1/(pid_output_left - 9)) * 5500;

if(pid_output_right > 0)pid_output_right = 405 - (1/(pid_output_right + 9)) * 5500;
else if(pid_output_right < 0)pid_output_right = -405 - (1/(pid_output_right - 9)) * 5500;

//Calculate the needed pulse time for the left and right stepper motor controllers
if(pid_output_left > 0)left_motor = 400 - pid_output_left;
else if(pid_output_left < 0)left_motor = -400 - pid_output_left;
else left_motor = 0;

if(pid_output_right > 0)right_motor = 400 - pid_output_right;
else if(pid_output_right < 0)right_motor = -400 - pid_output_right;
else right_motor = 0;

//Copy the pulse time to the throttle variables so the interrupt subroutine can use them
throttle_left_motor = left_motor;
throttle_right_motor = right_motor;

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//Loop time timer
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//The angle calculations are tuned for a loop time of 4 milliseconds. To make sure every loop is exactly 4 milliseconds a wait loop
//is created by setting the loop_timer variable to +4000 microseconds every loop.
while(loop_timer > micros());
loop_timer += 4000;
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//Interrupt routine TIMER2_COMPA_vect
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
ISR(TIMER2_COMPA_vect){
//Left motor pulse calculations
throttle_counter_left_motor ++; //Increase the throttle_counter_left_motor variable by 1 every time this routine is executed
if(throttle_counter_left_motor > throttle_left_motor_memory){ //If the number of loops is larger then the throttle_left_motor_memory variable
throttle_counter_left_motor = 0; //Reset the throttle_counter_left_motor variable
throttle_left_motor_memory = throttle_left_motor; //Load the next throttle_left_motor variable
if(throttle_left_motor_memory < 0){ //If the throttle_left_motor_memory is negative
PORTD &= 0b11110111; //Set output 3 low to reverse the direction of the stepper controller
throttle_left_motor_memory *= -1; //Invert the throttle_left_motor_memory variable
}
else PORTD |= 0b00001000; //Set output 3 high for a forward direction of the stepper motor
}
else if(throttle_counter_left_motor == 1)PORTD |= 0b00000100; //Set output 2 high to create a pulse for the stepper controller
else if(throttle_counter_left_motor == 2)PORTD &= 0b11111011; //Set output 2 low because the pulse only has to last for 20us

//right motor pulse calculations
throttle_counter_right_motor ++; //Increase the throttle_counter_right_motor variable by 1 every time the routine is executed
if(throttle_counter_right_motor > throttle_right_motor_memory){ //If the number of loops is larger then the throttle_right_motor_memory variable
throttle_counter_right_motor = 0; //Reset the throttle_counter_right_motor variable
throttle_right_motor_memory = throttle_right_motor; //Load the next throttle_right_motor variable
if(throttle_right_motor_memory < 0){ //If the throttle_right_motor_memory is negative
PORTD |= 0b00100000; //Set output 5 low to reverse the direction of the stepper controller
throttle_right_motor_memory *= -1; //Invert the throttle_right_motor_memory variable
}
else PORTD &= 0b11011111; //Set output 5 high for a forward direction of the stepper motor
}
else if(throttle_counter_right_motor == 1)PORTD |= 0b00010000; //Set output 4 high to create a pulse for the stepper controller
else if(throttle_counter_right_motor == 2)PORTD &= 0b11101111; //Set output 4 low because the pulse only has to last for 20us
}
`

Please help me because I am very new to software.

Thanks.

Wifi Communication

Migel,

What protocol are you using to communicate with the ESP8266 wifi variant? I thought it was UDP but that's not working via netcat. I'm really baffled here.

Ok for more clarity, I'm using a nodemcu board. The serial output is fine, logs on to network and spits out an IP address, but udp connection just hangs.

Pierre

Resolution question

Hi,

Wanted to say this is an awesome project and I'll be trying it out as soon as the parts are properly shipped over!

And now onto my question:
I am curious about the max resolution achievable with this set up. The last dc motor driver I worked with could only be tuned to +/- 5 pulses max with the best pid settings. What kinda variation are you seeing when you tune in your PID settings?

Using lpd3806-600bm

Hello misan,

Is it possible to use a lpd3806 rotary encoder with your code?

Thank you.

Tiny speed improvement

Hi. I was checking your code for the AS5600 i2c encoder for ESP8266 and I noticed one tiny improvement.
Within the readTwoBytes() subroutine you are addressing one address byte of the AS5600 and requesting its value, while in the very next step you address the next address byte and request its value, too.
You can address the lower address first and request 2 bytes - the auto counter on AS5600 will increase the address pointer and you will save ~50% of i2c communication.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.