Commit 977d851b authored by Jake Read's avatar Jake Read
Browse files

big restructure for more heirarchy

parent 827b885a
# AutomataKit
# Distributed Dataflow Machine Controllers
AutomataKit is a collection of reconfigurable open hardware and software for machine-building, process development, and robotics projects.
**Status**
It uses a Distributed Dataflow Programming paradigm: hardware and software objects are all nodes in a graph, executing computing and physical tasks, together!
The project is ongoing. Circuit designs listed here are stable, but software across the board is undergoing a big shift: things are getting better. Currently aiming at March 1 *release* of dataflow-all-the-way-down.
[RuNDMC](https://gitlab.cba.mit.edu/jakeread/rndmc) serves a development environment for those graphs.
## What it Is
The *Distributed Dataflow Machine Controllers* project (pending a decent name) is a collection of reconfigurable open hardware and software for machine-building, process development, and robotics projects.
It uses a Distributed Dataflow Programming Paradigm: hardware and software objects are all nodes in a graph, executing computing and physical tasks, together!
[RuNDMC](https://gitlab.cba.mit.edu/jakeread/rndmc) serves a development environment for those graphs: and Integrated Development and Operation Environment (IDOE).
![atkapi](images/machine-with-atkapi.jpg)
# Machines Made with These Controllers
This means that *adding and removing hardware to a system is easy, and possible.* It also means that *re-writing machine controllers,* to accept new inputs, or deliver new outputs (material, or feedback) is easy. Machine controllers are transparent: their operating principles are obvious to their users, and so intelligent intervention (and modification!) of controllers is possible. We can re-use algorithms and processes that we have developed across many machine instantiations, and we can build custom systems with less overhead. Tools are pliable again, and under our control.
- [Mother Mother: a Machine Generalist](https://gitlab.cba.mit.edu/jakeread/reich)
## Machines Running DDMCs
- [Little Rascal](https://gitlab.cba.mit.edu/jakeread/littlerascal)
- [Mother Mother: a Machine Generalist](https://gitlab.cba.mit.edu/jakeread/mothermother)
- [Small Stress and Strain Machine (uSSM)](https://gitlab.cba.mit.edu/jakeread/ussm)
- [*A Machine* for playing *Music for Pieces of Wood* by Steve Reich by Jake Read](https://gitlab.cba.mit.edu/jakeread/reich)
- [MPVMachine](https://gitlab.cba.mit.edu/jakeread/mpvmachine)
- [SmallGantries](https://gitlab.cba.mit.edu/jakeread/smallgantries)
......@@ -20,20 +30,39 @@ It uses a Distributed Dataflow Programming paradigm: hardware and software objec
![endpoints](images/endpoints.jpg)
Endpoints are designed to be very simple: they receive minimum viable commands and keep minimal state required for operation. This way, system complexity can be organized in the particular application, not distributed throughout the system. For example, steppers receive very simple trapezoid motion segements to execute, and don't do much math except for counting steps.
When I say 'Endpoint' I mean the circuit boards (and computing) we expect to find at the edge of the network that we use to connect each of our modular controllers. I also mean: the modular controllers. These are the circuit boards that you seek.
### Mother Boards
I have started using 'Motherboards' with 'Daughters' - Mother Boards (of which I have only one so far) are home to Computing and Network Hardware: they are the minimum viable package needed to start having a Modular Controller. They feature one 60-pin (with 30 cpu pins connected) 'mezzanine' / 'board-to-board' connector.
[XMEGA Motherboard](https://gitlab.cba.mit.edu/jakeread/motherboard-xmega)
### Daughter Boards
Through the 60-pin mezzanine connector mentioned above, I connect the hardware-that-does-work. These are the gate-drivers, mosfets, sensing elements etc, that you need to actually do modular control.
[Router](https://gitlab.cba.mit.edu/jakeread/daughterboard-router)
[Stepper](https://gitlab.cba.mit.edu/jakeread/daughterboard-stepper)
!TODO migrate doc from BLDC, DC, Ultra, and Breadboard.
!TODO make heating board (also current sensing big current board)
- [ATKRouter](https://gitlab.cba.mit.edu/jakeread/atkrouter)
- [ATKStepper17](https://gitlab.cba.mit.edu/jakeread/atkstepper17)
- [ATKStepper23](https://gitlab.cba.mit.edu/jakeread/atkstepper23)
- [ATKBreadBoardBoard](https://gitlab.cba.mit.edu/jakeread/atkbreadboardboard)
- [ATKBLDCDriver](https://gitlab.cba.mit.edu/jakeread/atkbldcdriver)
# The Computing Contexts
Each of the computers participating in the control of these machines runs a *context* - contexts, while written in different languages and running on different platforms, share a set of messages they can use to describe their internals to one another - and they run the same *execution model* internally. This is the (simple) reconfiguration that allows us to build controllers whose execution can be understood (and modified) cohesively, despite their operation across a network, in physical space.
I call these 'DMCCs' - Distributed Machine Control Contexts. None are ready for use.
[Node.js DMCC](https://gitlab.cba.mit.edu/jakeread/dmcc-node)
[Browser DMCC: the IDOE, aka RuNDMC](https://gitlab.cba.mit.edu/jakeread/rndmc)
[XMEGA DMCC]
# The Network
To make individual motors and sensors modular, AutomataKit endpoints use a port-forwarding, source-routed network. This is *not a bus* and can be connected in a complete graph. All connections are full-duplex and include support for hardware clock synchronization.
To make individual motors and sensors modular, endpoints use a port-forwarding, source-routed network. This is *not a bus* and can be connected in a complete graph. All connections are full-duplex and include hardware for hardware clock synchronization.
Packets typically originate on the network over a usb-to-serial bridge, so you can interface with networked endpoints using any piece of software you can successfully use to open a COM port with: JavaScript, Python etc. The [AutomataKit Router](https://gitlab.cba.mit.edu/jakeread/atkrouter) includes one UBS-to-UART Bridge, which is treated as the 6th port on the router.
Packets typically originate on the network over a usb-to-serial bridge, so you can interface with networked endpoints using any piece of software you can successfully use to open a COM port with: JavaScript, Python etc. The [odb](https://gitlab.cba.mit.edu/jakeread/odb) includes one UBS-to-UART Bridge, for very simple interface. [XMEGA Motherboard](https://gitlab.cba.mit.edu/jakeread/motherboard-xmega) and XMEGA DMCC will offer a USB serial link.
The hardware (or 'PHY' layer) of the network is simple UART. That means that all the network is, is a few UART links between microcontrollers, and some C code that listens for incoming packets and forward messages according to the instructions in the packet. Critically, there are not *addresses* in the network, instead, packets themseleves carry routes: this is 'source routing' in network nomenclature.
......@@ -49,20 +78,6 @@ Bytes between the Length Byte and the *Packet Header End Delimiter* define the r
![packet typ](/images/apa-networking-diagrams-traversal.png)
# The Firmware
So far, the endpoints all have xmega microcontrollers at their heart. In particular, the ```XMEGA256A3U``` : the biggest, baddest xmega. We clock it at 48MHz. That said, this isn't a requirement - any microcontroller with a UART port can play.
Firmware can be found in each board's repository under the ```embedded/``` directory. Build, run and debug via the instructions [here](reproduction/firmware.md), or roll your own toolchain.
[typical main.c](https://gitlab.cba.mit.edu/jakeread/atkbreadboardboard/blob/master/embedded/atkbbb/atkbbb/main.c)
Packet handling is like this: [uartports](https://gitlab.cba.mit.edu/jakeread/atkbreadboardboard/blob/master/embedded/atkbbb/atkbbb/uartport.c) handle interrupts that pull incoming data into [ringbuffers](https://gitlab.cba.mit.edu/jakeread/atkbreadboardboard/blob/master/embedded/atkbbb/atkbbb/ringbuffer.c). These are scanned [with this structure](https://gitlab.cba.mit.edu/jakeread/atkbreadboardboard/blob/master/embedded/atkbbb/atkbbb/atkport.c) and then handled [with this one](https://gitlab.cba.mit.edu/jakeread/atkbreadboardboard/blob/master/embedded/atkbbb/atkbbb/atkhandler.c). Global things are kept in [this include file](https://gitlab.cba.mit.edu/jakeread/atkbreadboardboard/blob/master/embedded/atkbbb/atkbbb/hardware.h).
All in, probably there is too much pointing->through->things, as I understand this takes a cycle on each link.
As for DMA, the XMEGA has only four channels (if I understand correctly) so unless I get my hands dirty doing channel-management, the router isn't going to work (it has 6 ports, plus a usb link).
# Usage
## Wiring
......@@ -113,11 +128,4 @@ Once you've gotten your hands on / or built some ATK Hardware, you'll need to lo
If you'd like to make your own hardware for the network, I recommend using the [ATKBreadBoardBoard](https://gitlab.cba.mit.edu/jakeread/atkbreadboardboard) whose documentation also includes a 'daughter' board starter - this will let you plug some new circuitry right onto the available XMEGA pinouts, and use known-to-work programming, voltage regulation, and network interface hardware.
Along with this note, there's more detailed explanation in the link above.
# Development Notes
- the push now is to find backpressure in the network, and go for a four wire
- also / in that case, a router board with dma access (x usb on each chip) and maybe a rethink of the headboard / daughter lookout ... face-to-face so that single sided PNP is possible (usb on same side ... nice to port-in wherever) ... port on the 'other side' then ? or also on same side and SMD ?
- do big value bleed resistor on capacitor board
- do an ODB / CP2102n link
\ No newline at end of file
Along with this note, there's more detailed explanation in the link above.
\ No newline at end of file
//----------------------------------------- mkterminal
/*
small program for sending apa packets along a serial line
*/
// check that we have portname
if (process.argv.length < 3) {
logAdvice()
process.exit(-1)
}
if (process.argv[2] == '-h' || process.argv[2] == 'help') {
logAdvice()
process.exit(-1)
}
var SerialPort = require('serialport');
var ByteLengthParser = SerialPort.parsers.ByteLength;
var port = new SerialPort(process.argv[2], {
baudRate: 750000,
/* dataBits: 8,
parity: 'none',
flowControl: false,
*/
});
//----------------------------------------- readline
/*
key input from terminal
*/
const readline = require('readline');
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
rl.on('line', parseLineIn);
function parseLineIn(data) {
/*
packet like "packet port,port,etc,ptr,byte,byte,byte..."
does like "len,int,int,int,254?,byte,byte,byte,etc"
next do key:type:values
apa_end_addr_delimiter 255
apa_addr_pointer 254
apa_addr_flood 253
key_position_float 127
key_speed_float 128
key_position_steps 129
key_speed_steps 130
*/
if (data.includes('packet')) {
var argstring = data.split(' ')[1]; // everything following 'packet '
var args = argstring.split(',');
var packet = new Array();
var i = 0; // args
var u = 0; // packet
while (i < args.length) {
switch (args[i]) {
case 'ptr':
packet[u] = 254;
i++;
u++;
break;
case 'end':
packet[u] = 255;
i++;
u++;
break;
case 'test':
packet[u] = 127;
i++;
u++;
break;
case 'reset':
packet[u] = 128;
i++;
u++;
break;
case 'setPos':
packet[u] = 129
var newPos = parseInt(args[i + 1])
packet[u + 1] = (newPos >> 8) & 255
packet[u + 2] = newPos & 255
i += 2
u += 3
break
case 'getPos':
packet[u] = 130
i ++
u++
break
case 'block':
packet[u] = 131;
// a linked acceleration planned segment
// we'll be going betwee float-space for steps in the higher levels, so
var steps = parseInt(args[i + 1])
packet = packet.concat(pack32(steps))
// but accel and speeds need to be in floats
var entry = parseInt(args[i + 2])
packet = packet.concat(pack32(entry))
// pack 64 bit float to 32 bit?
var accel = parseInt(args[i + 3])
packet = packet.concat(pack32(accel))
var accelLength = parseInt(args[i + 4])
packet = packet.concat(pack32(accelLength))
var deccelLength = parseInt(args[i + 5])
packet = packet.concat(pack32(deccelLength))
i += 6
u += 21
break;
case 'wait':
packet[u] = 132;
// a linked acceleration planned segment
// this one flagged as a wait period via the delimiter
// we'll be going betwee float-space for steps in the higher levels, so
var steps = parseInt(args[i + 1])
packet = packet.concat(pack32(steps))
// but accel and speeds need to be in floats
var entry = parseInt(args[i + 2])
packet = packet.concat(pack32(entry))
// pack 64 bit float to 32 bit?
var accel = parseInt(args[i + 3])
packet = packet.concat(pack32(accel))
var accelLength = parseInt(args[i + 4])
packet = packet.concat(pack32(accelLength))
var deccelLength = parseInt(args[i + 5])
packet = packet.concat(pack32(deccelLength))
i += 6
u += 21
break;
case 'speed':
packet[u] = 141;
var speed = parseInt(args[i +1])
packet = packet.concat(pack32(speed))
var duty = parseInt(args[i + 2])
packet = packet.concat(pack32(duty))
i += 3;
u += 9;
break;
default:
packet[u] = parseInt(args[i]);
u++;
i++;
break;
}
}
packet.unshift(packet.length + 1); // push the length into header
data_out(packet);
// now through bytes
} else if (data.includes('dummy packet')) {
var packet = Buffer.from([12, 3, 1, 254, 4, 255, 1, 2, 3, 4, 5, 6]);
data_out(packet);
} else if (data.includes('help')) {
logAdvice();
} else if (data.includes('exit')) {
process.exit(0);
} else {
data_out(data);
}
}
function pack32(val) {
var pack = new Array();
pack[0] = (val >> 24) & 255;
pack[1] = (val >> 16) & 255;
pack[2] = (val >> 8) & 255;
pack[3] = val & 255;
return pack;
}
function packFloat(val) {
var pack; // the array of bytes
// as a view into a typed array
var view = new DataView(new ArrayBuffer(4));
view.setFloat32(0, val);
pack = Array.apply(null, { length: 4 }).map((_, i) => view.getUint8(i))
console.log('packed', val, 'as', pack)
return pack
}
function logAdvice() {
console.log('use serialport-list to find ports')
console.log("command line: node serialterminal portname");
console.log('route,ptr,end,command,args')
console.log('test: sends byte 128 to network test')
console.log('steps: {steps uint32_t, speed steps/s float, dir uint8_t}')
console.log('block: steps, entry, accel, accelLength, deccelLength')
}
//----------------------------------------- parsing
/*
does the business
*/
var parser = port.pipe(new ByteLengthParser({ length: 1 }));
parser.on('data', data_in);
function data_in(data) {
console.log(data[0]);
}
function data_out(data) {
console.log('sent: ', data);
port.write(data, function(err) {
if (err) {
return console.log('port error on write: ', err.message);
}
});
}
port.on('open', function(err) {
console.log('port open');
});
port.on('error', function(err) {
console.log('port error: ', err.message);
});
\ No newline at end of file
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment