Closed Wallacoloo closed 9 years ago
In terms of concurrently scheduling multiple sources of OutputEvents, we have a few options:
AxisStepper
into the ioDrivers
tuple and move the logic in motionPlanner::_nextStep
into the state, having it operate over all IoDrivers
.OutputEvent
stream with streams from each IoDriver.Advantages of Option 1:
ioDrivers
tuple allows for easy g-code control of them (selectively enable/disable axis). This can still be done with the other option though.Disadvantages of Option 1:
ioDrivers
tuple with the motionPlanner, which is slightly undesireable. But it also gives other IoDrivers the opportunity to listen for motion events.Advantages of Option 2:
Although Option 1 at first seems the cleaner choice to me, that bolded bullet point hints at an inconsistency. The transformation times could be achieved by wrapping the actual AxisSteppers inside another object that abstracts this, but at this point it seems as if I'm trying to make AxisSteppers fit a role they weren't meant to fit.
I will likely proceed with Option 2 sometime within the next 2 weeks.
Servos are now implemented in devel, though M-code control of them has not been added.
To use a servo, you must instantiate it and put it in the ioDrivers tuple. This can be done by returning it directly from Machine::getIoDrivers()
, or, the CoordMap can instantiate it as a member variable and return a reference to it in its CoordMap::getDependentIoDrivers()
function (useful if it's used in a homing/auto-level routine).
M-code control of them is now implemented in devel (M280 P<index> S<angle in degrees>
). The index refers to the Nth Servo in existence, rather than the Nth IoDriver. So if the State's IoDrivers are tuple<Fan, Hotend, Servo0, Fan, Servo1>
, then M280 P0
refers to Servo0, and M280 P1
refers to Servo1.
See the current cartesian machine for how to instantiate a Servo (refer to the getIoDrivers()
function).
To see what the parameters mean, refer to servo.h
Note that Servos can be created by the CoordMap's getDependentIoDrivers function (useful when the servos are used for bed leveling, homing, etc).
Servos are controlled by periodically sending a pulse of a specified length. The length of that pulse determines the position at which the servo should be placed, and the servo will attempt to stay at that location until it receives another pulse Typical pulse lengths vary from 1ms to 2ms for the full control range and the pulses must occur between 40-200 times per second.
There are multiple ways to generate these pulses:
Each has notable downsides. If we use PWM, it requires that the underlying hardware is capable of sustaining PWM cycles of at least about 10 ms (100 Hz) in length. It also requires a slight rework of the HardwareScheduler API (with a fixed-length buffer-based PWM system like PWM via DMA, the user can't just ask for 100Hz and expect to get it - the period must be an exact divisor of the buffer length).
If we do this via scheduling OutputEvents, then we have to deal with concurrent scheduling of motor steps and servo controls. In a way, we already deal with concurrent scheduling, in the form of scheduling multiple AxisSteppers side-by-side, and that turns out to be rather trivial. This could be generalized to concurrently scheduling all IoDrivers - just implement the method,
getNextOutputEvent()
.I think using OutputEvents is the better, and more future-proof choice here. The downside is that would require a great deal more refactoring.