CoreXY turns the X and Y motors to render a target position differently
than straight cartesian printer does. From the theory page on corexy.com,
where the motors are called A and B instead of X and Y:
dx = 1/2(dA + dB), dY = 1/2(dA - dB)
dA = dX + dY
dB = dX - dY
Accordingly, each step of a single motor results in half of a step in the
X or Y axis. To simplify this and not lose steps, make the pos[] array
hold 2*steps instead of single steps. Adjust back to single steps with
/2 where needed. Store 2*steps whenever writing to pos[] variables
which are not coreXY driven.
Since each step of X or Y (A or B) affects both X and Y position, send
updates to record_pin for all axes instead of only the "affected" axis.
The function record_pin will ignore reports for pins which did not change
from the previous call. This also helps us keep from reporting duplicate
positions for half-steps in coreXY mode, too.
Provide a simulated, simplified representation of the action of
mechanical endstop switches which turn on and off at slightly
different amounts of pressure. When any axis moves past -10,
simulate endstop "on" condition. When the axis moves to 0,
simulate the endstop "off" condition.
This support allows the simulation of G28 (home) commands.
The simulator code is compiled with different definitions than the
rest of the code even when compiling the simulator. This was done
originally to satisfy the compiler, but it was the wrong way to go.
The result is that the main Teacup code may decide to do things one
way (X_INVERT_DIR, for example) but the simulator code will do
things a different way (no X_INVERT_DIR).
Fix this by including the board and printer definitions also in the
simulator code, and use a simple enum trick to give consistent
definitions to the needed PIN definitions, safely ignoring the ones
the config does not use.
This requires that we include simulator.h after 'config.h' in all cases.
Manage that by moving simulator.h from its previous home in arduino.h
into config_wrapper.h.
After this change we will be able to reliably communicate the expected
state of the endstop pins from the simulator.
Teach simulator to calculate temperatures for all possible ADC
values using the compiled-in temperature tables and report the
resulting conversion. Do no other run-time simulation; exit
after reporting the conversion results. Output is suitable for
gnuplot for example like this:
gnuplot --persist -e "plot '< ./sim -T0' u 1:2 with lines,
'< ./sim -T1' u 1:2 with lines"
We cheated before and sent the serial data in the simulator into
the G-code reporter so it could be line-buffered and then recorded
as comments in the trace-log. But this confuses the simulator
console output and is harder to manage. Revert to sending serial-out
data directly to the comment engine.
Also be less chatty about startup when connecting to a UART.
getopt_long() requires a null entry at the end of the longopts
array. It also reports an error already when some switch is
wrong, so just exit silently when we get an unexpected value.
Add simulator for SD card driver, plus add stubs for SPI and PFF
primarily to prevent the on-device code from being picked up by
the makefiles for the simulator.
Pure cosmetical change.
Performance check:
$ cd testcases
$ ./run-in-simulavr.sh short-moves.gcode smooth-curves.gcode triangle-odd.gcode
[...]
SIZES ATmega... '168 '328(P) '644(P) '1280
FLASH : 20518 bytes 144% 67% 33% 16%
RAM : 2188 bytes 214% 107% 54% 27%
EEPROM : 32 bytes 4% 2% 2% 1%
short-moves.gcode statistics:
LED on occurences: 838.
LED on time minimum: 302 clock cycles.
LED on time maximum: 713 clock cycles.
LED on time average: 308.72 clock cycles.
smooth-curves.gcode statistics:
LED on occurences: 8585.
LED on time minimum: 307 clock cycles.
LED on time maximum: 710 clock cycles.
LED on time average: 358.051 clock cycles.
triangle-odd.gcode statistics:
LED on occurences: 1636.
LED on time minimum: 302 clock cycles.
LED on time maximum: 708 clock cycles.
LED on time average: 330.322 clock cycles.
Simulator assumes a basic set of config pins. Most it ignores
and redefines. But the INVERT_DIR pins it did not, and these
could be useful to simulate. So teach Simulator to respect them.
Add a comment to the datalog output showing how it can be viewed with
gnuplot. It would be trivial to add this as a .plot script, but it's
even easier in the datalog output.
Teach simulator several command line options to control console output
of info messages, gcode traces, data_recorder output, etc.
Also move gcode output to sim_gcode instead of sending directly to
datarecorder.
If the recorder is initialized with a filename, write trace data
to that file. But if it is not initialized, don't complain and
don't write the data anywhere.
The simulator runs as a device simulator complete with serial port
so it can communicate with printer software like pronterface. But
often we just want to stream it a file of gcode commands and get
some output. Teach the simulator to take a regular file as input
and process it as a file of gcode commands if it is not a device.
Reduce the simulated timer to 1/10 actual time. There is no need
for the simulator to run at full speed for now, and some PCs may
not be able to attain real-time speed anyway due to PC clock
speed, scheduler slack or OS differences.
Maybe the simulated timer interrupt is not needed at all and some
cooperative timer interrupt could be used instead. Such a setup
may even run faster as it could also run >1.0x time when there is
nothing to do. This bears investigation later. For now, the
simulated timer interrupt seems more realistic and possibly valuable.
Cleanup datalog output a bit.
* Add close/flush on exit in case we have pending data
* Use hash for comment characters to be compatible with gnuplot
* Report x/y/z/e position in array
Next-interrupt-time calculations were made in 16-bit registers but
moved to 32-bit ones for convenience. But they forgot to round off
at 16-bits. Force the round-off so we do not wait forever.
Record simulation run-time data in file 'datalog.out' so it
can be analyzed after-the-fact or during the run.
This feature is evolving. Eventually it should be compatible with
some logic analyzer GUIs such as gtkwave or even gnuplot.
This code was accidentally removed long ago in a botched merge. This
patch recovers it and makes it build again. I've done minimal testing
and some necessary cleanup. It compiles and runs, but it probably still
has a few dust bunnies here and there.
I added registers and pin definitions to simulator.h and
simulator/simulator.c which I needed to match my Gen7-based config.
Other configs or non-AVR ports will need to define more or different
registers. Some registers are 16-bits, some are 8-bit, and some are just
constant values (enums). A more clever solution would read in the
chip-specific header and produce saner definitions which covered all
GPIOs. But this commit just takes the quick and easy path to support my
own hardware.
Most of this code originated in these commits:
commit cbf41dd4ad
Author: Stephan Walter <stephan@walter.name>
Date: Mon Oct 18 20:28:08 2010 +0200
document simulation
commit 3028b297f3
Author: Stephan Walter <stephan@walter.name>
Date: Mon Oct 18 20:15:59 2010 +0200
Add simulation code: use "make sim"
Additional tweaks:
Revert va_args processing for AVR, but keep 'int' generalization
for simulation. gcc wasn't lying. The sim really aborts without this.
Remove delay(us) from simulator (obsolete).
Improve the README.sim to demonstrate working pronterface connection
to sim. Also fix the build instructions.
Appease all stock configs.
Stub out intercom and shush usb_serial when building simulator.
Pretend to be all chip-types for config appeasement.
Replace sim_timer with AVR-simulator timer:
The original sim_timer and sim_clock provided direct replacements
for timer/clock.c in the main code. But when the main code changed,
simcode did not. The main clock.c was dropped and merged into timer.c.
Also, the timer.c now has movement calculation code in it in some
cases (ACCELERATION_TEMPORAL) and it would be wrong to teach the
simulator to do the same thing. Instead, teach the simulator to
emulate the AVR Timer1 functionality, reacting to values written to
OCR1A and OCR1B timer comparison registers.
Whenever OCR1A/B are changed, the sim_setTimer function needs to be
called. It is called automatically after a timer event, so changes
within the timer ISRs do not need to bother with this.
A C++ class could make this requirement go away by noticing the
assignment. On the other hand, a chip-agnostic timer.c would help
make the main code more portable. The latter cleanup is probably
better for us in the long run.