the roadster originally (oct 2014 -- dec 2015) had a fairly minimal software controller and a more or less traditional instrument panel. i rightly realized that the software effort was substantial so i put the software portion of the project off until later (which eventually became now). this is a rough description of the software and hardware architecture as documentation for myself; this isn't intended to be a how-to project.
i partitioned the car mentally into two: the chassis and the instrument panel. the chassis is of course the guts of the car; everything auto-motive, from the tires up to the top of the air cleaner. this mainly means the engine and it's sensors and actuators, lighting, and miscellaneous (fuel tank). the chassis computer is bolted to the human-side of the firewall and has tendrils of one sort or another into all sensors and actuators directly (hard wire to temperature sensors, oil pressure sensors, starter motor, fan and water pump, etc) or indirectly (the rear computer sends fuel sensor and controls tail lights). the chassis computer is "invisible", in that it has no interface (one LED and two test switches) and as should be obvious, once a car is running you can easily drive it well with no electrical, instrumental, controls or indicators at all. steering wheel, the pedals, breeze in your face and engine sounds in your ear suffice. this fact clearly demonstrates the prosthetic nature of a car.
prosthetic or otherwise, you will eventually get into trouble without instruments; likely you'll run out of gas without a fuel gauge (or, i suppose, a dip-stick to push into the tank). but the instrumentation -- or more specifically, the arrangement of the information produced by the chassis and presented to the human driver -- is clearly requried in practice. the presentation of this information is quite separate from the chassis; the information is an abstract view of what the metal is up to at any given moment.
it took a while to work out this observation, as obvious as it seems to me now, and then i took it to an extreme that ended up with some convenient side effects. unlike most cars the connection between the chassis and the instrument panel consist of only four wires:
this simple scheme supports unlimited information to/from chassis and instrument panel, and has some interesting side effects covered later. the simple electrical scheme above supports a deceivingly simple informational scheme -- messages. a single, simple, message scheme communicates all information from the chassis (temperatures, pressures, voltage, whatever) and commands to the chassis computer (ignition on/off, start motor, blink light, etc). messages are very brief text messages -- you can type them by hand (and i do so, in testing and development). messages consist of a "number" (i call it payload) and a message name (a letter). "55M" means 55 miles per hour; "50P" means 50 PSI engine oil pressure, "15L" means blink left turn lights on 15 times.
in typical operation the chassis computer sends the instrument panel about 20 messages per second; tach, speedo, temperatures, battery voltage, fuel level, etc. some frequently (oil pressure, 8 times per second) some slowly (fuel level, once every 5 seconds). the panel sends messages to the chassis controller mostly in response to switch presses.
since messages (and "commands" delivered as messages) are brief, self-contained texts, they can come from anywhere... the instrument panel, obviously, but anything that can translate simple actions (button press, sensor reading) into a text message can take part in the "conversation". the instrument panel screwed to the car in front of the driver contains a small 2.4GHz radio that talks to a complete "instrument panel" consisting of a small LCD display with fours buttons that can completely drive the car. the same box can be plugged in directly -- in place of the fixed instrument panel -- with no change in basic operation.
this little (ugly) test box is a complete, if minimal, instrument panel. what's not obvious is that it talks to the main panel via radio, or directly via cable to the lower left (the identical 4-pin connector). the USB cable plugged in here is for charging the internal battery only. the idea wasn't a radio "remote control" so much as a portable instrument panel for under-hood use and other maintenance. the four membrane switches control turn signals and hazards, headlights, ignition and starter. the knob selects which information is displayed on the LCD display.
the messaging system also allows for some sophisticated error recovery features -- when any computer (chassis or panel) is reset (power fail, error, etc) it tells all other computers via a message, and the other computer(s) respond by messaging their complete internal state -- meaning that the chassic controller, for example, can recover from a software or hardware failure in about 25 feet of travel at 60 mph. take that, Toyota.
the messaging scheme means also that all and any car state can be logged in realtime (it's just text) and with minimal massaging of data, loaded into a spreadsheet or other program.
all of my code is available on Github. a general overview of my code, libraries and other software thingies are on this site.
the system is a series of interconnected sort-of standalone controller boxes that communicate via messages, described/implemented in the SRmessage library docs. these are simple postfix notation ASCII messages sent serially. controllers are cast aluminum chassis boxes with barrier strips for car electrics and 4-pin waterproof pigtails for interprocessor comm. the controllers have their own filtered DC supply fed from a double-pi LC filter network (50 year old car electrics generate monstrous load dumps).
there are two functional blocks, the instrument panel and the chassis controller aka main controller. the panel actually contains three processors, the panel controller (Arduino Mega 2560), a power controller (Pro Mini) with nRF24L01+ radio module running my SRFlock radio protocol, and another Pro Mini on the LCD display. the power controller is always on, listens via radio for security credentials and optionally commands from a radio dongle. when the right conditions are met the power controller powers-on the panel controller, which in turn powers on the chassis controller. once powered on, the panel and chassis controllers both control their own power supply.
the functional breakdown between controllers is straightforward; the panel is the human interface to the chassis controller, which runs all engine functions. given the antiquity of the drivetrain, the chassis controller only controls ignition power and derives sensor information; the EDIS ignition has it's own controller (MegaJolt Light Jr.), fuel system is via carburetor (Weber 32/36). the chassis controller drives filtered, smoothed, error-checked sensor data to the panel controller which does it's own processing for display and control (described below).
all sensor, actuator, status and overhead is transmitted via the SR Message scheme. SR Messages store odometer and other persistent data in the panel's EEPROM. the chassis controller, in the front of the car, is the busiest; it receives most of the engine sensors and most of it's actuators. it generates approximately 20 messages/second, to the panel controller. the panel normal case is to send messages only in response to driver actions (with some exceptions). the only interface to the chassis controller is over the serial message link.
inter-processor messages are safeguarded by runtime bounds and age checks in the panel controller. the mood meter calcs generate a nominal-green pattern for normal operation (scalars like engine temperature and fuel level, but also vectors like oil pressure vs. RPM) and indicate bad/missing/old data with blacked-out pixels.
status and control messages flow between all components -- chassis controller, panel, power, and the two radio-interfaced controllers, the pocket dongle and the radio LCD instrument panel box -- equally well, and with reasonable security. the pocket dongle's only function is to transmit the security credential required to operate the panel (via the power controller), while the radio LCD box is a complete instrument panel with minimal but functional controls, enough to operate the car.
security is via a simple credential system. radio on the power controller in the car remains in receive mode, silently awaiting packet(s) from the dongle, listening on a random channel (see SRFLock radio protocol). when the pocket dongle is powered on it searches channels for the power controller's radio; in response the power controller issues a challenge, the dongle responds, embedding a command ("on") in the response. if this is correct the panel is powered on and the credential forwarded to the panel. the dongle (or the panel) can delete the credential for various reasons. (the current kludgey system will be replaced "real soon now" with a one-time pad and EEPROM-stored key.)
all effector actions begin with a message, and all sensor data generates messages. substantial effort has gone into a design that does not need to maintain internal "software" state that could get out of sync with the physical. the requirement for persistent software state is mainly around manual interfaces eg. the RUN/START switch logic and turn signal logic shown here. clean state machines allow for redundancy and failsafe interlocks that ensure reasonable behavior eg. starter motor not engaged when engine is running, etc.
all panel indicators, including turn signals, are via closed-loop feedback or state machines, eg. a switch command is sent to the chassis (or appropriate) controller, and the result of the requested action itself messages back the command's status. all of the controllers are reset-safe. if any controller resets (hardware or software glitch) then it's neighbor/peer refreshes the reset controller's status within 20 milliseconds. if the chassis controller is reset it will recover (ignition on, lighting, brake lights, etc) within 6 feet of travel at 60 mph.
all of my realtime code has the same overall construction, following the Wiring model. loop() in each controller executes a list of tasks in round-robin order. each task cooperatively multitasks; no code blocks, anywhere, ever. task execution time (time slice) is generally under 200 microseconds each, the longest normal task execution under 5 milliseconds. inherently slow functions (eg. EEPROM write) are unwound and enforce their own execution time limits. monitor software within loop() flags exceptions (programmer errors) and indicates error on the instrument panel.
interrupts are not used (exceptions are speedometer and tachometer pulse counters). heap allocation in each controller is used sparingly, and only once, in setup(). memory so allocated is never released/deleted (hence no leaks). nonetheless heap size and location is checked at runtime for errors (minimally). all code is [intended to be] deterministic, there are no non-terminating loops without a failsafe exit. wherever possible the code adheres to MISRA-C:2004 standards (though i don't have a formal testing regime; there is compilable TESTING code that stress-tests interprocessor messages and serial data and task timing).