I am still not sure on everything you wish to support
Me either... Ideas and concepts evolve for me... I do not always have a clear vision when starting something.
I will say that I want to develop a Propeller based system that can be used for both 3D printing and CNC. The basics would include:
Motor support for four axes
GCODE input from SD or serial
LCD terminal, but support for a full blown terminal would be nice
Homing and overtravel switches for each axis, and supporting code to monitor them
ADC support for 3D printing applications or for CNC machinery that may need ADC support
IO support for a user defined GUI
As I see it, GUI and GCODE processing will most likely be unique for each each user, custom tailored to their individual needs. However the basics, such as GCODE parsing, motor control, switch provisions, ADC support, and GUI IO pin availability would be common for all users.
Each user will have different requirements for a GUI, as long as there is an ample amount of surplus IO, supporting various types of GUIs should not be a problem, except that custom code would have to be written to support the desired interface. The same holds true for GCODE processing, whereas processing for all 3D printers may be equivalent, and not require any changes, but in the case of CNC machinery, I can envision various GCODE processing schemes. For instance, as long as you have support for the previously mentioned items, and restrict various G commands for movement code, the rest of the processing is pretty much up for grabs, so custom processing can easily be achieved, by modifying existing processing code or creating new processing code. Various commands can activate anything that is configured in the processing code. Although there are common commands for common tasks, any command besides movement codes could be modified.
E.G.: M100 - Flash IR transmitter to a IR receiver on a different controller to run a specific process.
As long as there is a parser to read the commands, any processor could be modified to perform specific tasks. However as mentioned, and as you know, there are common GCODEs for common tasks. Modification of the processor and GCODE commands is entirely upto the user.
My goal is to enable movement through the use of stepper motors, with an ample amount of surplus pins for a custom GUI, as well as a surplus pin or two on the processing end for special processing needs. However for this particular project build, I will be writing GUI interface code and GCODE processing code for a 3D printing application. As long as the controller has the support for such changes, the GUI code and processing code can be modified for a wide variety of projects, besides 3D printing.
Sounds like a challenge, a big one.
As I get deeper into my rewrite I have found a lot of things to be more interesting than initially thought (for example support for a continous rotation servo, DC motor, or stepper for the filament feed on the extruder, all bound to conditional compilation, and being able to have the same exact control HW for all three possible configs).
Do to unforeseen limits in PropBASIC I am thinking about rewriting in C, still just a possible and I am playing with C a bit to figure it out.
Though you may want to think about doing what I did in PASM, and will do in C if I decide to go that way. That is do not use floating point at all, stick to integer.
You can convert the floating point text in the G-Code to integers of the forum of IVal = FVal << 8 with no trouble, and that gives a resolution of 1/256th which is more than enough, and easier truncation (in amount of code included), as well as eliminating a lot of library code as well as eliminating a lot of code to support floating point (should bring the size down quite a bit if you are using any floating point values). Just treat the shifted values as integers for calculation, they will provide a good fixed point representation (and remember the correct inversion of operation for values less than 256 (representing less than 1) in the shifted numbers).
Just a though I figured may help you.
At present what is the maximum pin usage? And have you thought about a simple command language to keep the G-Code all together in one Prop, just sending very simple already processed commands to any slaves?
Like I said earlier, I have totally given up on the one Propeller solution. For me, it just makes things to darn complicated and cramped. I want to be able to stretch.
As I get deeper into my rewrite I have found a lot of things to be more interesting than initially thought (for example support for a continous rotation servo, DC motor, or stepper for the filament feed on the extruder, all bound to conditional compilation, and being able to have the same exact control HW for all three possible configs).
I would have to agree that it is interesting, but also annoying, when troubleshooting the bugs In the past, I always avoided conditional compiling, except for things like unicode support, but after messing around with Teacup, I learned the true value of it.
I am thinking about rewriting in C
Yea, I read in your other thread where you said you were good at C..... I was very reluctant to start programming the Propeller in C and then I was kind of forced into it. Now I am glad that it happened, because I feel so much more productive. All I can say is go for it and I think you will be glad you did.
At present what is the maximum pin usage?
In my controllers current state, all pins are utilized, but I will be removing the Propeller Memory Board from the controller, which should open up 7 or 8 pins. However, I still have several switches that I want to add and I will need 2 pins for serial comms, so I will probably have a pin or two left over.
And have you thought about a simple command language to keep the G-Code all together in one Prop, just sending very simple already processed commands to any slaves?
I have done that in the past, for a very complicated machine, but for this particular project, with X, Y, and Z control, I figure I will stick with common GCODE for 3D printers. GCODE support has been a major issue with the Propeller for many years, and the problems always relate to memory. Although not verified, I would imagine that all prior attempts were made with a single Propeller design, with both the parser and processor on the same chip. By splitting the parser and the processor onto two different chips, I believe much more can be achieved with common GCODE.
I was saying process the G-Code and use a simpler command language to send commands to the slave propellers, thus saving code and data space in the slaves. That is the rout I ended up with the current work on my firmware (though at present only one Propeller, though it does have some pins reserved for communicating with a second propeller for future expansion).
I was saying process the G-Code and use a simpler command language to send commands to the slave propellers, thus saving code and data space in the slaves. That is the rout I ended up with the current work on my firmware (though at present only one Propeller, though it does have some pins reserved for communicating with a second propeller for future expansion).
Sorry for the misunderstanding.
I suppose in a round about kind of way, that is what I am doing.
The parser performs all the necessary calculations and fills a GCODE struct. The GCODE struct will then be sent to the other Propeller. Inside the GCODE struct, there is a member named "valid", which is just an array, showing which other members are valid. The processor will first read the "valid" member to determine the appropriate course of action. If it is determined that a G1 condition exists, the X, Y, Z, and E members will already contain the number of steps to be made, thus eliminating step calculations on the processing chip.
However, M codes will be handled on a much more individualized basis. For example, let's say that by examining the "valid" member of the GCODE struct, it is determined that the M and S fields are valid. Such as M = 104 S = 190, the processor would set a variable to 190 and the ADC cog would simply keep pulsing the extruder heating element until the proper temp was reached. It is worth noting, that many of the members of the GCODE struct, will be in numeric form instead of text, so they won't need to be translated by the processor.
As determined by a set of twenty (20) random moves on X and Y axes:
There is still a problem with the stepper drivers
or
there is too much friction in my actuators
During the first run, it actually appeared as though steps were gained, instead of lost, however at this point I am uncertain. I intend to slow the drivers down enough or insert a lengthy waitcnt to enable a determination of gained or lost steps.
EDIT: MY BAD.... Typed in the wrong maximum values for X and Y.... DUH
As determined by a set of twenty (20) random moves on X and Y axes:
There is still a problem with the stepper drivers
or
there is too much friction in my actuators
During the first run, it actually appeared as though steps were gained, instead of lost, however at this point I am uncertain. I intend to slow the drivers down enough or insert a lengthy waitcnt to enable a determination of gained or lost steps.
If I remember correctly you already posted your stepper code somewhere, though you have likely updated it since.
In reference to my last post, I used a wrong maximum value on both axes, so no wonder it was overtraveling I just tested with new maximum values and it worked just fine.
Would you mind posting that function?
Not at all.... Keep in mind that this driver is meant for an individual cog for simutaneous movement, however it can easily be modified to be run outside of a cog and for individual axis control. In fact, there are several versions of this driver floating around the forum, and the use of a particular driver would all depend upon your specific needs. If you need a different driver, just let me know what you want or what your needs are.
Additionally, this driver is setup for stepper drivers that have a step and a direction input pin. And keep in mind the high pulse width, this will be established by the driver manufacturer. The value of other various variables will be determined by the step per rev, microstep resolution, the speed at which the moment of inertia can be overcome, and the maximum speed for which you want to run and being physically and electrically possible.
#include "x_axis_driver.h"
#include "config.h"
#include "gcode_struct.h"
#include "NewParser.h"
/// cog variables
static int x_axis_cog = 0;
static int x_axis_stack[100];
volatile bool x_move_complete;
void x_axis_driver(void *par);
void x_axis_init()
{
if(x_axis_cog == 0)
{
x_axis_cog = 1 + cogstart(&x_axis_driver, NULL,
x_axis_stack, sizeof x_axis_stack);
}
}
/// stop x_axis cog
void x_axis_stop()
{
if(x_axis_cog > 0)
{
cogstop(x_axis_cog - 1);
x_axis_cog = 0;
}
}
void x_axis_driver(void *par)
{
int32_t x_counter;
// Set DIRA as an output.
DIRA |= 1 << X_DIRECTION;
do
{
if(app_move_now_x == true)
{
app_move_now_x = false;
// Set up the CTRMODE of Counter A for NCO/PWM single-ended.
CTRA = (4 << 26) | X_STEP;
// Set the value to be added to PHSA with every clock cycle.
FRQA = 1;
// Set DIRA as an output.
DIRA |= 1 << X_STEP;
// Set the OUTA register to match the desired direction of rotation.
if(current_gcode.x_dir == 0)
{
OUTA &= (~1 << X_DIRECTION);
}
else
{
OUTA |= 1 << X_DIRECTION;
}
// Get the current System Counter value.
x_counter = CNT;
// Ramp up the stepper motor a predetermined amount of steps
while(current_gcode.x_ramp_up_steps != 0)
{
// Send out a high pulse on the step pin for the desired duration.
PHSA = -X_PULSE_WIDTH;
// Wait for a specified period of time before sending another
// high pulse to the step pin.
waitcnt(x_counter += current_gcode.x_start_stop_speed -= current_gcode.x_ramp_inc_dec);
// Decrement ramp_up_steps
current_gcode.x_ramp_up_steps--;
}
// Run the stepper motor at the current speed for a predetermined amount of steps
while(current_gcode.x_running_steps != 0)
{
// Send out a high pulse on the step pin for the desired duration.
PHSA = -X_PULSE_WIDTH;
// Wait for a specified period of time before sending another
// high pulse to the step pin.
waitcnt(x_counter += current_gcode.x_start_stop_speed);
// Decrement running_steps
current_gcode.x_running_steps--;
}
// Ramp down the stepper motor a predetermined amount of steps
while(current_gcode.x_ramp_down_steps != 0)
{
// Send out a high pulse on the step pin for the desired duration.
PHSA = -X_PULSE_WIDTH;
// Wait for a specified period of time before sending another
// high pulse to the step pin.
waitcnt(x_counter += current_gcode.x_start_stop_speed += current_gcode.x_ramp_inc_dec);
// Decrement ramp_down_steps
current_gcode.x_ramp_down_steps--;
}
x_move_complete = true;
}
}
while(x_axis_cog > 0);
}
I am not sure how your code would run on my drivers, because they are pretty darn finicky. They require a minimun high pulse width of 1uS and they are 1/10 microsteppers. Any attempt to start out to fast, they just sit and complain
Anyhow, I figured I would give it a try, and this is how I set the pins, assuming this is what you were referring to:
private:
static const int s0 = 1<<23; // Pin 23 X Step
static const int d0 = 1<<22; // Pin 22 X Direction
static const int s1 = 1<<26; // Pin 26 Y Step
static const int d1 = 1<<27; // Pin 27 Y Direction
static const int s2 = 1<<1; // Pin 1 Z Step (Non-existent)
static const int d2 = 1<<2; // Pin 2 Z Direction (Non-existent)
Yup, those are the pins I meant. As for the pulse width, it's easy to change toward the bottom of the Bresenham.c file - There's a waitcnt there just before it clears the pins again. It's currently set to 100 which should be plenty. (80 cycles @ 80MHz would be 1us).
Do I need to drag in that previous upload of Motor.cpp?
Ah, damn - I removed that file to simplify everything, but it's probably still mentioned in the .side file. If you open BresenhamTest.side and remove the mentions of Motor.cpp and Motor.h that'll fix it. Otherwise, yes, you could just drop the ones from before in there and that'll work too, but they're not used in the code. Sorry about that. Was trying to make it simpler, not harder.
I removed that file to simplify everything, but it's probably still mentioned in the .side file
I am actually glad it happened, because now I know that "side" files can be edited with a text editor
Anyhow, I just tried to run it and my motors only complained
For my drivers, I basically need a 1uS high pulse width (which you already explained), and the low must be long enough to overtake inertia, which I currently have set at around 14000 cycles in my other stuff. Is there anyway I can set this value of 14000 as my clock offset? I ramp up by gradually decreasing 14000 and I ramp down by gradually increasing back to 14000.
The simplest way to change it is to change the Ticks value near the top of main().
I'm using:
int Ticks = 1600;
Try changing that to 16000 as a starting point, and then double it if it still doesn't work.
This test code doesn't have any of the setup code you'd normally have. That setup would look something like this:
int LargestMove = abs(xMove);
if( abs(yMove) > LargestMove ) LargestMove = abs(yMove);
if( abs(zMove) > LargestMove ) LargestMove = abs(zMove);
int Ticks = LargestMove * 4; // Do one principal axis step every 4 ticks - bigger values go slower
int m1Diff = xMove;
int m2Diff = yMove;
int m3Diff = zMove;
// Here you would call "SetupMove", and then run the actual move, or more likely, store
// the Ticks and motor deltas in a struct and pass them off to the Bresenham loop cog
Alternately, just change the waitcnt inside the main loop in BresenhamTest.c to this:
B.Tick();
waitcnt( 14000 + cnt );
It won't be exact, because that number isn't taking into account how much time is spent in the Tick() function, but it'll be pretty close.
With Ticks set to 16000 and both waitcnt(s) set to 80, it operated pretty darn smoothly, however I had a severe case of overtravel I tried changing the do-while loop into a for loop of maximum steps, but it still over-traveled.
Do you have ramping all figured out for using Bresenham?
Additionally, I was wondering if you read my earlier posts of the day, and what you thought about them.
The number of steps to take in the demo is just set by the three arguments to "SetupMove". I have it running continuously in one direction though, so you'd probably want to change that.
The code does a do { ... } while(1);
That means it loops forever, so it's doing exactly 1600 steps (200 * 8), and then immediately doing 1600 more, and again, and again...
A better demo for you would be this:
do {
// 1536 cycles
B.SetupMove( Ticks, m1Diff, m2Diff, m3Diff );
// 1729680 cycles for 1600 ticks, 320,000 of which is just waitcnt
// Excluding waitcnt, it's about 900 clocks per tick, or 220 PASM instruction cycles
while( !B.Done() )
{
B.Tick();
waitcnt( 100 + CNT );
}
// Now do the return move (just negates the move deltas)
B.SetupMove( Ticks, -m1Diff, -m2Diff, -m3Diff );
while( !B.Done() )
{
B.Tick();
waitcnt( 100 + CNT );
}
} while(1);
This will alternate - Forward by the step count, then reverse, and repeat that.
That probably makes more sense.
As for the other stuff, no I'm still at work and haven't had a chance to go through all of it yet. I also haven't quite figured out ramping for the Bresenham loop, though really, that's what the Motor.cpp code does. It's quite a bit more complicated though. I should see if there's a way to use something like a Bresenham algorithm for the delay itself... hmm...
Over the past couple of weeks, I have been hinting at the fact that I will be altering my current controller, to accommodate more switches, due to the removal of the Propeller Memory Card. This morning I updated my controller image to show the exact changes that I intend to make.
**NOTES:
1) If not used in a 3D printing application, pins 16, 17, and 18 can be considered spares for general purpose use.
2) The MCP23008 is not being utilized and provides an additional 8 GPIO pins.
3) Although defined above, pins 14 and 15 are spares.
4) Resistors have not been installed for serial communication on pins 8 and 9. The resistors will be placed on the master.
Oh, ok. I was thinking that you were using some form of amplifier, with separation (perhaps an opto coupler or similar) directly, my mistake in understanding.
My apologies...... My response was a little misleading......
The driver does not require NCO/PWM single-ended, because they can easily operate with two waitcnt(s) in a loop. The reason I use counters is because it was determined that a counter runs faster than two waitcnt(s) in a loop.
If you moved the "Valid" member above "gcode_fileline" you'd avoid clearing that one twice, as the memset I wrote above will currently include it.
For some odd reason, this was causing me some grief with my "prints", so until I set aside some time to straighten it out, I have reverted to the original memset(s) and placed the "valid" member back to it's original location. Wierd stuff I am sure it will work, and it is most likely a simple oversight, but at the moment, I am working on passing the struct.
@idbruce:
Knowing that you tackled this once already:
How would you go about translating my implementation of the 2D Bresenham line algorithm into 3D? Thank you in advanced.
Actually, I wish I had already tackled that......
In fact, I have not gone anywhere near that subject yet, and I probably won't, until I get the rest of the firmware complete.
However, my recommendation would be to study the open source firmware that is already out there. There are plenty of sources to choose from, RepRap, Teacup, I forget the others, but there are a bunch. However, I do believe that Teacup would be difficult to trace. I was looking at it a couple of times, but then figured there must be more straight forward source code available.
The passing of a GCODE_STRUCT from one Propeller to another Propeller is highly critical for my new plan, of controlling a 3D printer or other CNC machines, with two Propellers. So for the last several days, that is what I have been working on, although I have been merely working on a simulation. Today I finally achieved a working example, which can be found here: http://forums.parallax.com/showthread.php/160833-C-Testing-Serial-Protocol-And-Simulating-Inter-Propeller-Communication
EDIT: Please note that the simulation program does not include the entire GCODE_STRUCT, but it includes most it.
Propeller 1) GCODE Parser, Motor Control Algorithms, and GUI (And I believe the GUI might be pushing the limits)
Propeller 2) Machine Controller, GCODE processor, and perhaps LCD.
Hi Bruce,
I know, it's a bit late for a major design change. But reading about all the effort you put into this project really makes me worry. All the difficulties partitioning the task into two propellers, all those limitations on memory, performance, integer math precision, communication speed...
Is it really necessary to save the last $ squezing everything into two propellers? I agree, If you plan to sell a 3D-printer for the same price as a laser printer then every cent counts. But how many printers do you want to build? Is saving some $ really worth the development time you spend?
I think you could do it much faster if you took a RaspberryPi for the GUI and to do all the computations and a propeller to generate the time critical signals for the steppers and the rest of the IO stuff. On the RasPi you have abundance of memory, access to network and USB sticks. You can use floating point math.
I don't argue against the propeller. But you should think about using it only for those thing it can do well: interfacing to hardware and realtime tasks.
Of course you know that you are not the first to suggest the RaspberryPi
To be perfectly honest, it is not just about the money, there are several issues that keep me trudging forward.
1) Money
2) Parts and peripherals already purchased
3) Time spent planning and implementing (I simply refuse to throw it all in the garbage)
4) The Propeller deserves a fair shot at CNC control
5) The Propeller needs more CNC support
6) I am 100% confident that it can be done with two Propellers
7) It is now a vendetta
8) End game.... Dual Propeller CNC controller (Not just about a single 3D printer)
I have worked too long and hard to throw the towel in now, especially when I just solved the main piece of the puzzle (I think).
I am now going to beat those two Propellers into submission and bend them to do my will.
Nothing has really changed, I still need and want what I need and want. The only difference is that I have come to the realization that my wants and needs will not work with a single Propeller design. As mentioned earlier, I should have gone with my first instinct, and planned for a dual Propeller design in the first place. Now that would have saved me a lot of time and grief.
I figure the necessary modifications to the main controller board should perhaps take me a day or two to complete, and setting up the other board should perhaps take a day. So for three more days of drudgery, I believe I will have the electronics for a fairly nice CNC controller and interface. Of course the remaining problem will be the firmware, but we need a solution, or at least I do.
Of course you know that you are not the first to suggest the RaspberryPi
To be perfectly honest, it is not just about the money, there are several issues that keep me trudging forward.
1) Money
2) Parts and peripherals already purchased
3) Time spent planning and implementing (I simply refuse to throw it all in the garbage)
4) The Propeller deserves a fair shot at CNC control
5) The Propeller needs more CNC support
6) I am 100% confident that it can be done with two Propellers
7) It is now a vendetta
8) End game.... Dual Propeller CNC controller (Not just about a single 3D printer)
I have worked too long and hard to throw the towel in now, especially when I just solved the main piece of the puzzle (I think).
I am now going to beat those two Propellers into submission and bend them to do my will.
Nothing has really changed, I still need and want what I need and want. The only difference is that I have come to the realization that my wants and needs will not work with a single Propeller design. As mentioned earlier, I should have gone with my first instinct, and planned for a dual Propeller design in the first place. Now that would have saved me a lot of time and grief.
I figure the necessary modifications to the main controller board should perhaps take me a day or two to complete, and setting up the other board should perhaps take a day. So for three more days of drudgery, I believe I will have the electronics for a fairly nice CNC controller and interface. Of course the remaining problem will be the firmware, but we need a solution, or at least I do.
It is interesting that you have gone with a two Prop design, and are determined to finish it up with a simple 2 Propeller design.
I am moving forward with a single propeller design, with the goal of making it as universal as possible with a single Propeller, thus lowering the barrier to entry for others. I am determined to succeed at a nearly universal firmware with a single Propeller.
I figure that expansion beyond 30 controlling pins can come after the Prop2 is released, or just a Prop one that has the B ports (giving 64GPIO).
I actually started out with a Raspberry Pi model B. I switched to the Propeller in response to the fact that there are not enough GPIO's on the RPI Model B, and I will make it fit in the 30 available GPIO's on the Prop (I am using 20GPIO at the moment, which would have fit with the RPI model . Though I am thinking about ordering a B+ as it has more GPIO, just to see if I can do it under RISC OS .
It is interesting that you have gone with a two Prop design, and are determined to finish it up with a simple 2 Propeller design.
I am moving forward with a single propeller design, with the goal of making it as universal as possible with a single Propeller, thus lowering the barrier to entry for others. I am determined to succeed at a nearly universal firmware with a single Propeller.
I figure that expansion beyond 30 controlling pins can come after the Prop2 is released, or just a Prop one that has the B ports (giving 64GPIO).
I actually started out with a Raspberry Pi model B. I switched to the Propeller in response to the fact that there are not enough GPIO's on the RPI Model B, and I will make it fit in the 30 available GPIO's on the Prop (I am using 20GPIO at the moment, which would have fit with the RPI model . Though I am thinking about ordering a B+ as it has more GPIO, just to see if I can do it under RISC OS .
I do hope that you will succeed.
I wish you success as well.
When it comes to the two Propeller design, there is also another consideration. As it pertains to the controller board, shown in Post #75, there is a MCP23008 IC. This chip was intended to be the resting place for my user interface board, shown below, but the IC has now just become a source for 8 extra GPIO. Additionally, the same controller board was intended to hold the Propeller Memory Board, which will now be removed to accommodate the extra homing and limit switches that I wanted in the first place.
The Propeller Memory Card and the user interface board will now be moved to other Propeller, thus taking the burden away from the main controller, and allowing more code space for extra G and M commands. By keeping the Propeller Memory Card, I still have access to a lot of memory, although I am still not sure how that will all work out. And the user interface board will no longer require an MCP23008 to interface, and will be wired directly to the IO pins on the other Propeller. Just for the user interface and the Propeller Memory Card, I need 18 IO pins, but that gives me a lot of memory, 8 push buttons, and 3 LEDs, with one of those LEDs being directly wired to VDD.
Also as mentioned, by splitting the parser and the processor onto two different chips, I should also open up even more room for G and M command support. When I get finished with the necessary modifications, I believe I will have the stretching room that I mentioned in a previous post.
As I see it, we both have very different goals, but in many ways similar goals. I hope we can both learn from each others trial and errors.
The controller modifications are well underway and they are going much better than anticipated. If I get real ambitious, I am sure that I can have my two Propeller controller setup by sometime later today, providing my local Radio Shack still has 10K resistors still available, when they open up later this morning. I am really looking forward to having these two Propeller Proto Boards side by side, working together to achieve a common goal
As time permits, I will also now be splitting the firmware into two sections, based upon which Propeller the code will be running under. Last night, I started working on the command and movement queue for the processing Propeller, and I suppose making that fully functional would be the next step in my firmware development process.
For those who have not been following along, the parsing Propeller will accept GCODE from either a serial source or an SD card file. For each instruction received, the parser will perform any necessary calculations and organize all data within a GCODE_STRUCT. This filled and organized struct will then be passed serially to the processing Propeller. When the struct arrives at the processing Propeller, it will be added to a processing queue, having a predetermined amount of commands and movements that it can hold. This queue will then be processed in a first in first out manner.
The controller modifications are well underway and they are going much better than anticipated. If I get real ambitious, I am sure that I can have my two Propeller controller setup by sometime later today, providing my local Radio Shack still has 10K resistors still available, when they open up later this morning. I am really looking forward to having these two Propeller Proto Boards side by side, working together to achieve a common goal
As time permits, I will also now be splitting the firmware into two sections, based upon which Propeller the code will be running under. Last night, I started working on the command and movement queue for the processing Propeller, and I suppose making that fully functional would be the next step in my firmware development process.
For those who have not been following along, the parsing Propeller will accept GCODE from either a serial source or an SD card file. For each instruction received, the parser will perform any necessary calculations and organize all data within a GCODE_STRUCT. This filled and organized struct will then be passed serially to the processing Propeller. When the struct arrives at the processing Propeller, it will be added to a processing queue, having a predetermined amount of commands and movements that it can hold. This queue will then be processed in a first in first out manner.
After I wrote my post, I stayed up a while longer working on the processing queue, so I am getting a very late start. I still have not made it to Radio Shack and it will most likely be a while before I do. Odds are that working on the controller is going to be a late night project, but when I get finished, I will take a few photos.
Comments
As I get deeper into my rewrite I have found a lot of things to be more interesting than initially thought (for example support for a continous rotation servo, DC motor, or stepper for the filament feed on the extruder, all bound to conditional compilation, and being able to have the same exact control HW for all three possible configs).
Do to unforeseen limits in PropBASIC I am thinking about rewriting in C, still just a possible and I am playing with C a bit to figure it out.
Though you may want to think about doing what I did in PASM, and will do in C if I decide to go that way. That is do not use floating point at all, stick to integer.
You can convert the floating point text in the G-Code to integers of the forum of IVal = FVal << 8 with no trouble, and that gives a resolution of 1/256th which is more than enough, and easier truncation (in amount of code included), as well as eliminating a lot of library code as well as eliminating a lot of code to support floating point (should bring the size down quite a bit if you are using any floating point values). Just treat the shifted values as integers for calculation, they will provide a good fixed point representation (and remember the correct inversion of operation for values less than 256 (representing less than 1) in the shifted numbers).
Just a though I figured may help you.
At present what is the maximum pin usage? And have you thought about a simple command language to keep the G-Code all together in one Prop, just sending very simple already processed commands to any slaves?
Like I said earlier, I have totally given up on the one Propeller solution. For me, it just makes things to darn complicated and cramped. I want to be able to stretch.
I would have to agree that it is interesting, but also annoying, when troubleshooting the bugs In the past, I always avoided conditional compiling, except for things like unicode support, but after messing around with Teacup, I learned the true value of it.
Yea, I read in your other thread where you said you were good at C..... I was very reluctant to start programming the Propeller in C and then I was kind of forced into it. Now I am glad that it happened, because I feel so much more productive. All I can say is go for it and I think you will be glad you did.
In my controllers current state, all pins are utilized, but I will be removing the Propeller Memory Board from the controller, which should open up 7 or 8 pins. However, I still have several switches that I want to add and I will need 2 pins for serial comms, so I will probably have a pin or two left over.
I have done that in the past, for a very complicated machine, but for this particular project, with X, Y, and Z control, I figure I will stick with common GCODE for 3D printers. GCODE support has been a major issue with the Propeller for many years, and the problems always relate to memory. Although not verified, I would imagine that all prior attempts were made with a single Propeller design, with both the parser and processor on the same chip. By splitting the parser and the processor onto two different chips, I believe much more can be achieved with common GCODE.
I was saying process the G-Code and use a simpler command language to send commands to the slave propellers, thus saving code and data space in the slaves. That is the rout I ended up with the current work on my firmware (though at present only one Propeller, though it does have some pins reserved for communicating with a second propeller for future expansion).
Sorry for the misunderstanding.
I suppose in a round about kind of way, that is what I am doing.
The parser performs all the necessary calculations and fills a GCODE struct. The GCODE struct will then be sent to the other Propeller. Inside the GCODE struct, there is a member named "valid", which is just an array, showing which other members are valid. The processor will first read the "valid" member to determine the appropriate course of action. If it is determined that a G1 condition exists, the X, Y, Z, and E members will already contain the number of steps to be made, thus eliminating step calculations on the processing chip.
However, M codes will be handled on a much more individualized basis. For example, let's say that by examining the "valid" member of the GCODE struct, it is determined that the M and S fields are valid. Such as M = 104 S = 190, the processor would set a variable to 190 and the ADC cog would simply keep pulsing the extruder heating element until the proper temp was reached. It is worth noting, that many of the members of the GCODE struct, will be in numeric form instead of text, so they won't need to be translated by the processor.
There is still a problem with the stepper drivers
orthere is too much friction in my actuators
During the first run, it actually appeared as though steps were gained, instead of lost, however at this point I am uncertain. I intend to slow the drivers down enough or insert a lengthy waitcnt to enable a determination of gained or lost steps.
EDIT: MY BAD.... Typed in the wrong maximum values for X and Y.... DUH
Would you mind posting that function?
In reference to my last post, I used a wrong maximum value on both axes, so no wonder it was overtraveling I just tested with new maximum values and it worked just fine.
Not at all.... Keep in mind that this driver is meant for an individual cog for simutaneous movement, however it can easily be modified to be run outside of a cog and for individual axis control. In fact, there are several versions of this driver floating around the forum, and the use of a particular driver would all depend upon your specific needs. If you need a different driver, just let me know what you want or what your needs are.
Additionally, this driver is setup for stepper drivers that have a step and a direction input pin. And keep in mind the high pulse width, this will be established by the driver manufacturer. The value of other various variables will be determined by the step per rev, microstep resolution, the speed at which the moment of inertia can be overcome, and the maximum speed for which you want to run and being physically and electrically possible.
One other thing, this is the only driver I have ported to C.. If you need a SPIN version, I have that also.
Yup, those are the pins I meant. As for the pulse width, it's easy to change toward the bottom of the Bresenham.c file - There's a waitcnt there just before it clears the pins again. It's currently set to 100 which should be plenty. (80 cycles @ 80MHz would be 1us).
Ah, damn - I removed that file to simplify everything, but it's probably still mentioned in the .side file. If you open BresenhamTest.side and remove the mentions of Motor.cpp and Motor.h that'll fix it. Otherwise, yes, you could just drop the ones from before in there and that'll work too, but they're not used in the code. Sorry about that. Was trying to make it simpler, not harder.
J
I am actually glad it happened, because now I know that "side" files can be edited with a text editor
Anyhow, I just tried to run it and my motors only complained
For my drivers, I basically need a 1uS high pulse width (which you already explained), and the low must be long enough to overtake inertia, which I currently have set at around 14000 cycles in my other stuff. Is there anyway I can set this value of 14000 as my clock offset? I ramp up by gradually decreasing 14000 and I ramp down by gradually increasing back to 14000.
I'm using:
Try changing that to 16000 as a starting point, and then double it if it still doesn't work.
This test code doesn't have any of the setup code you'd normally have. That setup would look something like this:
Alternately, just change the waitcnt inside the main loop in BresenhamTest.c to this:
It won't be exact, because that number isn't taking into account how much time is spent in the Tick() function, but it'll be pretty close.
With Ticks set to 16000 and both waitcnt(s) set to 80, it operated pretty darn smoothly, however I had a severe case of overtravel I tried changing the do-while loop into a for loop of maximum steps, but it still over-traveled.
Do you have ramping all figured out for using Bresenham?
Additionally, I was wondering if you read my earlier posts of the day, and what you thought about them.
The code does a do { ... } while(1);
That means it loops forever, so it's doing exactly 1600 steps (200 * 8), and then immediately doing 1600 more, and again, and again...
A better demo for you would be this:
This will alternate - Forward by the step count, then reverse, and repeat that.
That probably makes more sense.
As for the other stuff, no I'm still at work and haven't had a chance to go through all of it yet. I also haven't quite figured out ramping for the Bresenham loop, though really, that's what the Motor.cpp code does. It's quite a bit more complicated though. I should see if there's a way to use something like a Bresenham algorithm for the delay itself... hmm...
J
The pin assignments are as follows:
#define Z_DISABLE 0
#define Z_STEP 1
#define Z_DIRECTION 2
#define SERIAL_LCD 3
#define X_HOMING 4
#define Y_HOMING 5
#define Z_HOMING 6
#define E_HOMING 7
#define INTER_PROP_TX 8
#define INTER_PROP_RX 9
#define X_LIMIT 10
#define Y_LIMIT 11
#define Z_LIMIT 12
#define E_LIMIT 13
#define SPARE_IO_14 14
#define SPARE_IO_15 15
#define PLATFORM_HEATER 16 (Goes To Daughter Board)
#define EXTRUDER_HEATER 17 (Goes To Daughter Board)
#define EXTRUDER_FAN 18 (Goes To Daughter Board)
#define E_DIRECTION 19
#define E_STEP 20
#define E_DISABLE 21
#define X_DIRECTION 22
#define X_STEP 23
#define X_DISABLE 24
#define Y_DISABLE 25
#define Y_STEP 26
#define Y_DIRECTION 27
#define I2C_SCL 28
#define I2C_SDA 29
#define CONTROLLER_TX 30
#define CONTROLLER_RX 31
**NOTES:
1) If not used in a 3D printing application, pins 16, 17, and 18 can be considered spares for general purpose use.
2) The MCP23008 is not being utilized and provides an additional 8 GPIO pins.
3) Although defined above, pins 14 and 15 are spares.
4) Resistors have not been installed for serial communication on pins 8 and 9. The resistors will be placed on the master.
It is not the steppers that require PWM, but actually the stepper drivers. I use Gecko G251X(s) to drive my motors. Here is the product information page: http://www.geckodrive.com/geckodrive-step-motor-drives/g251x.html
My apologies...... My response was a little misleading......
The driver does not require NCO/PWM single-ended, because they can easily operate with two waitcnt(s) in a loop. The reason I use counters is because it was determined that a counter runs faster than two waitcnt(s) in a loop.
For some odd reason, this was causing me some grief with my "prints", so until I set aside some time to straighten it out, I have reverted to the original memset(s) and placed the "valid" member back to it's original location. Wierd stuff I am sure it will work, and it is most likely a simple oversight, but at the moment, I am working on passing the struct.
Just a heads up.
Knowing that you tackled this once already:
How would you go about translating my implementation of the 2D Bresenham line algorithm into 3D? Thank you in advanced.
Actually, I wish I had already tackled that......
In fact, I have not gone anywhere near that subject yet, and I probably won't, until I get the rest of the firmware complete.
However, my recommendation would be to study the open source firmware that is already out there. There are plenty of sources to choose from, RepRap, Teacup, I forget the others, but there are a bunch. However, I do believe that Teacup would be difficult to trace. I was looking at it a couple of times, but then figured there must be more straight forward source code available.
EDIT: Please note that the simulation program does not include the entire GCODE_STRUCT, but it includes most it.
Hi Bruce,
I know, it's a bit late for a major design change. But reading about all the effort you put into this project really makes me worry. All the difficulties partitioning the task into two propellers, all those limitations on memory, performance, integer math precision, communication speed...
Is it really necessary to save the last $ squezing everything into two propellers? I agree, If you plan to sell a 3D-printer for the same price as a laser printer then every cent counts. But how many printers do you want to build? Is saving some $ really worth the development time you spend?
I think you could do it much faster if you took a RaspberryPi for the GUI and to do all the computations and a propeller to generate the time critical signals for the steppers and the rest of the IO stuff. On the RasPi you have abundance of memory, access to network and USB sticks. You can use floating point math.
I don't argue against the propeller. But you should think about using it only for those thing it can do well: interfacing to hardware and realtime tasks.
Of course you know that you are not the first to suggest the RaspberryPi
To be perfectly honest, it is not just about the money, there are several issues that keep me trudging forward.
1) Money
2) Parts and peripherals already purchased
3) Time spent planning and implementing (I simply refuse to throw it all in the garbage)
4) The Propeller deserves a fair shot at CNC control
5) The Propeller needs more CNC support
6) I am 100% confident that it can be done with two Propellers
7) It is now a vendetta
8) End game.... Dual Propeller CNC controller (Not just about a single 3D printer)
I have worked too long and hard to throw the towel in now, especially when I just solved the main piece of the puzzle (I think).
I am now going to beat those two Propellers into submission and bend them to do my will.
Nothing has really changed, I still need and want what I need and want. The only difference is that I have come to the realization that my wants and needs will not work with a single Propeller design. As mentioned earlier, I should have gone with my first instinct, and planned for a dual Propeller design in the first place. Now that would have saved me a lot of time and grief.
I figure the necessary modifications to the main controller board should perhaps take me a day or two to complete, and setting up the other board should perhaps take a day. So for three more days of drudgery, I believe I will have the electronics for a fairly nice CNC controller and interface. Of course the remaining problem will be the firmware, but we need a solution, or at least I do.
I am moving forward with a single propeller design, with the goal of making it as universal as possible with a single Propeller, thus lowering the barrier to entry for others. I am determined to succeed at a nearly universal firmware with a single Propeller.
I figure that expansion beyond 30 controlling pins can come after the Prop2 is released, or just a Prop one that has the B ports (giving 64GPIO).
I actually started out with a Raspberry Pi model B. I switched to the Propeller in response to the fact that there are not enough GPIO's on the RPI Model B, and I will make it fit in the 30 available GPIO's on the Prop (I am using 20GPIO at the moment, which would have fit with the RPI model . Though I am thinking about ordering a B+ as it has more GPIO, just to see if I can do it under RISC OS .
I do hope that you will succeed.
I wish you success as well.
When it comes to the two Propeller design, there is also another consideration. As it pertains to the controller board, shown in Post #75, there is a MCP23008 IC. This chip was intended to be the resting place for my user interface board, shown below, but the IC has now just become a source for 8 extra GPIO. Additionally, the same controller board was intended to hold the Propeller Memory Board, which will now be removed to accommodate the extra homing and limit switches that I wanted in the first place.
The Propeller Memory Card and the user interface board will now be moved to other Propeller, thus taking the burden away from the main controller, and allowing more code space for extra G and M commands. By keeping the Propeller Memory Card, I still have access to a lot of memory, although I am still not sure how that will all work out. And the user interface board will no longer require an MCP23008 to interface, and will be wired directly to the IO pins on the other Propeller. Just for the user interface and the Propeller Memory Card, I need 18 IO pins, but that gives me a lot of memory, 8 push buttons, and 3 LEDs, with one of those LEDs being directly wired to VDD.
Also as mentioned, by splitting the parser and the processor onto two different chips, I should also open up even more room for G and M command support. When I get finished with the necessary modifications, I believe I will have the stretching room that I mentioned in a previous post.
As I see it, we both have very different goals, but in many ways similar goals. I hope we can both learn from each others trial and errors.
As time permits, I will also now be splitting the firmware into two sections, based upon which Propeller the code will be running under. Last night, I started working on the command and movement queue for the processing Propeller, and I suppose making that fully functional would be the next step in my firmware development process.
For those who have not been following along, the parsing Propeller will accept GCODE from either a serial source or an SD card file. For each instruction received, the parser will perform any necessary calculations and organize all data within a GCODE_STRUCT. This filled and organized struct will then be passed serially to the processing Propeller. When the struct arrives at the processing Propeller, it will be added to a processing queue, having a predetermined amount of commands and movements that it can hold. This queue will then be processed in a first in first out manner.
After I wrote my post, I stayed up a while longer working on the processing queue, so I am getting a very late start. I still have not made it to Radio Shack and it will most likely be a while before I do. Odds are that working on the controller is going to be a late night project, but when I get finished, I will take a few photos.