Commit 9b629821 authored by Jake Read's avatar Jake Read

bones of standalone controller

parent a1b083a0
......@@ -2,3 +2,4 @@
**.rhl
archive/
**cam/
**node_modules/
\ No newline at end of file
......@@ -2,6 +2,8 @@
## 2019 11
https://github.com/ChrisEberl/Python_DIC
### Vision Controller Hello-World
We're currently working to build a computer vision based displacement sensing method for the DEX. Since our machine (or, many machines manufactured by novices / in the public domain) are liable to flex (indeed, nothing is infinitely stiff!), the thought is to measure local displacements of the sample, at the sample, rather than measuring open-loop through the machine's structure.
......
# DEX Controller
I've decided to roll a standalone controller for DEX. I've made a little ad-hoc breadboard circuit to connect one stepper driver, one load cell amp, to an Adafruit Feather M4 - an arduino variant.
So, this should just be a short project - I mostly have the codes I need to run the thing in cuttlefish implementations, here will just be wrapping those up in a standalone system. I can also experiment with 'no handcuffs' programming models, not having to manage this all through various homebrew dataflow environments.
So, first task is getting the embedded code up to competency. Compexity will live in JS, so the embedded just needs to do two things:
- `step <int32 steps>`
- accelstepper's this count, replies when complete
- microsteps are baked in: calculate transmission ratio as well?
- `read <uint32 averaging samples>`
- does read, replies with int32 (or whatever width is HX711) back, simple
Then, steps / mm land, zeroing, etc, will live in JS. As will load cell calibration, and plotting, etc. I can bottle each of those low level commands in JS promises, making 'running' the machine big async codes. This should be easy-ish, let's see.
## Install
``npm install express``
``npm install ws``
``npm install serialport``
``npm install esm``
\ No newline at end of file
.pio
.vscode/.browse.c_cpp.db*
.vscode/c_cpp_properties.json
.vscode/launch.json
.vscode/ipch
# Continuous Integration (CI) is the practice, in software
# engineering, of merging all developer working copies with a shared mainline
# several times a day < https://docs.platformio.org/page/ci/index.html >
#
# Documentation:
#
# * Travis CI Embedded Builds with PlatformIO
# < https://docs.travis-ci.com/user/integration/platformio/ >
#
# * PlatformIO integration with Travis CI
# < https://docs.platformio.org/page/ci/travis.html >
#
# * User Guide for `platformio ci` command
# < https://docs.platformio.org/page/userguide/cmd_ci.html >
#
#
# Please choose one of the following templates (proposed below) and uncomment
# it (remove "# " before each line) or use own configuration according to the
# Travis CI documentation (see above).
#
#
# Template #1: General project. Test it using existing `platformio.ini`.
#
# language: python
# python:
# - "2.7"
#
# sudo: false
# cache:
# directories:
# - "~/.platformio"
#
# install:
# - pip install -U platformio
# - platformio update
#
# script:
# - platformio run
#
# Template #2: The project is intended to be used as a library with examples.
#
# language: python
# python:
# - "2.7"
#
# sudo: false
# cache:
# directories:
# - "~/.platformio"
#
# env:
# - PLATFORMIO_CI_SRC=path/to/test/file.c
# - PLATFORMIO_CI_SRC=examples/file.ino
# - PLATFORMIO_CI_SRC=path/to/test/directory
#
# install:
# - pip install -U platformio
# - platformio update
#
# script:
# - platformio ci --lib="." --board=ID_1 --board=ID_2 --board=ID_N
{
// See http://go.microsoft.com/fwlink/?LinkId=827846
// for the documentation about the extensions.json format
"recommendations": [
"platformio.platformio-ide"
]
}
This directory is intended for project header files.
A header file is a file containing C declarations and macro definitions
to be shared between several project source files. You request the use of a
header file in your project source file (C, C++, etc) located in `src` folder
by including it, with the C preprocessing directive `#include'.
```src/main.c
#include "header.h"
int main (void)
{
...
}
```
Including a header file produces the same results as copying the header file
into each source file that needs it. Such copying would be time-consuming
and error-prone. With a header file, the related declarations appear
in only one place. If they need to be changed, they can be changed in one
place, and programs that include the header file will automatically use the
new version when next recompiled. The header file eliminates the labor of
finding and changing all the copies as well as the risk that a failure to
find one copy will result in inconsistencies within a program.
In C, the usual convention is to give header files names that end with `.h'.
It is most portable to use only letters, digits, dashes, and underscores in
header file names, and at most one dot.
Read more about using header files in official GCC documentation:
* Include Syntax
* Include Operation
* Once-Only Headers
* Computed Includes
https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html
This directory is intended for project specific (private) libraries.
PlatformIO will compile them to static libraries and link into executable file.
The source code of each library should be placed in a an own separate directory
("lib/your_library_name/[here are source files]").
For example, see a structure of the following two libraries `Foo` and `Bar`:
|--lib
| |
| |--Bar
| | |--docs
| | |--examples
| | |--src
| | |- Bar.c
| | |- Bar.h
| | |- library.json (optional, custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html
| |
| |--Foo
| | |- Foo.c
| | |- Foo.h
| |
| |- README --> THIS FILE
|
|- platformio.ini
|--src
|- main.c
and a contents of `src/main.c`:
```
#include <Foo.h>
#include <Bar.h>
int main (void)
{
...
}
```
PlatformIO Library Dependency Finder will find automatically dependent
libraries scanning project source files.
More information about PlatformIO Library Dependency Finder
- https://docs.platformio.org/page/librarymanager/ldf.html
; PlatformIO Project Configuration File
;
; Build options: build flags, source filter
; Upload options: custom upload port, speed and extra flags
; Library options: dependencies, extra library storages
; Advanced options: extra scripting
;
; Please visit documentation for the other options and examples
; https://docs.platformio.org/page/projectconf.html
[env:adafruit_feather_m4]
platform = atmelsam
board = adafruit_feather_m4
framework = arduino
/*
utils/cobs.cpp
Jake Read at the Center for Bits and Atoms
(c) Massachusetts Institute of Technology 2019
This work may be reproduced, modified, distributed, performed, and
displayed for any purpose, but must acknowledge the squidworks and ponyo projects.
Copyright is retained and must be preserved. The work is provided as is;
no warranty is provided, and users accept all liability.
*/
#include "cobs.h"
// str8 crib from
// https://en.wikipedia.org/wiki/Consistent_Overhead_Byte_Stuffing
#define StartBlock() (code_ptr = dst++, code = 1)
#define FinishBlock() (*code_ptr = code)
size_t cobsEncode(uint8_t *ptr, size_t length, uint8_t *dst){
const uint8_t *start = dst, *end = ptr + length;
uint8_t code, *code_ptr; /* Where to insert the leading count */
StartBlock();
while (ptr < end) {
if (code != 0xFF) {
uint8_t c = *ptr++;
if (c != 0) {
*dst++ = c;
code++;
continue;
}
}
FinishBlock();
StartBlock();
}
FinishBlock();
// write the actual zero,
*dst++ = 0;
return dst - start;
}
size_t cobsDecode(uint8_t *ptr, size_t length, uint8_t *dst)
{
const uint8_t *start = dst, *end = ptr + length;
uint8_t code = 0xFF, copy = 0;
for (; ptr < end; copy--) {
if (copy != 0) {
*dst++ = *ptr++;
} else {
if (code != 0xFF)
*dst++ = 0;
copy = code = *ptr++;
if (code == 0)
break; /* Source length too long */
}
}
return dst - start;
}
/*
utils/cobs.h
consistent overhead byte stuffing implementation
Jake Read at the Center for Bits and Atoms
(c) Massachusetts Institute of Technology 2019
This work may be reproduced, modified, distributed, performed, and
displayed for any purpose, but must acknowledge the squidworks and ponyo projects.
Copyright is retained and must be preserved. The work is provided as is;
no warranty is provided, and users accept all liability.
*/
#ifndef UTIL_COBS_H_
#define UTIL_COBS_H_
#include <arduino.h>
size_t cobsEncode(uint8_t *src, size_t len, uint8_t *dest);
size_t cobsDecode(uint8_t *src, size_t len, uint8_t *dest);
#endif
/*
cobsserial.cpp
COBS delineated serial packets
Jake Read at the Center for Bits and Atoms
(c) Massachusetts Institute of Technology 2019
This work may be reproduced, modified, distributed, performed, and
displayed for any purpose, but must acknowledge the squidworks and ponyo projects.
Copyright is retained and must be preserved. The work is provided as is;
no warranty is provided, and users accept all liability.
*/
#include "cobsserial.h"
COBSSerial::COBSSerial(){
}
void COBSSerial::init(void){
// start the port...
Serial.begin(9600);
}
void COBSSerial::loop(void){
while(Serial.available()){
if(_pl > 0) break;
_encodedPacket[_bwp] = Serial.read();
if(_encodedPacket[_bwp] == 0){
// indicate we recv'd zero
// CLKLIGHT_TOGGLE;
// decode from rx-ing frame to interface frame,
size_t dcl = cobsDecode(_encodedPacket, _bwp, _packet);
_pl = dcl; // this frame now available, has this length,
// reset byte write pointer
_bwp = 0;
} else {
_bwp ++;
}
}
}
boolean COBSSerial::hasPacket(void){
if(_pl > 0){
return true;
} else {
return false;
}
}
void COBSSerial::getPacket(uint8_t **pck, uint16_t *pl){
*pck = _packet;
*pl = _pl;
}
void COBSSerial::clearPacket(void){
// frame consumed, clear to write-in,
_pl = 0;
}
void COBSSerial::sendPacket(uint8_t *pck, uint16_t pl){
size_t encLen = cobsEncode(pck, pl, _encodedOut);
Serial.write(_encodedOut, encLen);
}
/*
cobsserial.h
COBS delineated serial packets
Jake Read at the Center for Bits and Atoms
(c) Massachusetts Institute of Technology 2019
This work may be reproduced, modified, distributed, performed, and
displayed for any purpose, but must acknowledge the squidworks and ponyo projects.
Copyright is retained and must be preserved. The work is provided as is;
no warranty is provided, and users accept all liability.
*/
#ifndef COBSSERIAL_H_
#define COBSSERIAL_H_
#include <arduino.h>
#include "cobs.h"
#include "syserror.h"
#include "./drivers/indicators.h"
#define VPUSB_NUM_SPACES 8
#define VPUSB_SPACE_SIZE 1028
class COBSSerial {
private:
// unfortunately, looks like we need to write-in to temp,
// and decode out of that
uint8_t _encodedPacket[VPUSB_SPACE_SIZE];
uint8_t _packet[VPUSB_SPACE_SIZE];
uint16_t _pl = 0;
uint16_t _bwp = 0; // byte write pointer,
uint8_t _lastPacket = 0; // last packet written into
// outgoing cobs-copy-in,
uint8_t _encodedOut[VPUSB_SPACE_SIZE];
// this is just for debug,
uint8_t _ringPacket[VPUSB_SPACE_SIZE];
public:
COBSSerial();
// props
uint16_t maxSegLength = VPUSB_SPACE_SIZE - 6;
// code
void init(void);
void loop(void);
// handle incoming frames
boolean hasPacket(void); // check existence
void getPacket(uint8_t** pck, uint16_t* pl);
void clearPacket(void);
// dish outgoing frames, and check if cts
void sendPacket(uint8_t *pck, uint16_t pl);
};
#endif
#include "syserror.h"
uint8_t errBuf[1028];
uint8_t errEncoded[1028];
/*
boolean writeString(unsigned char* dest, uint16_t* dptr, String msg){
uint16_t len = msg.length();
dest[(*dptr) ++] = TS_STRING_KEY;
writeLenBytes(dest, dptr, len);
msg.getBytes(dest, len + 1);
return true;
}
boolean writeLenBytes(unsigned char* dest, uint16_t* dptr, uint16_t len){
dest[(*dptr) ++] = len;
dest[(*dptr) ++] = (len >> 8) & 255;
return true;
}
*/
// config-your-own-ll-escape-hatch
void sysError(String msg){
return;
// whatever you want,
//ERRLIGHT_ON;
uint32_t len = msg.length();
errBuf[0] = PK_LLERR; // the ll-errmsg-key
errBuf[1] = len & 255;
errBuf[2] = (len >> 8) & 255;
errBuf[3] = (len >> 16) & 255;
errBuf[4] = (len >> 24) & 255;
msg.getBytes(&errBuf[5], len + 1);
size_t ecl = cobsEncode(errBuf, len + 5, errEncoded);
if(Serial.availableForWrite() > (int64_t)ecl){
Serial.write(errEncoded, ecl);
Serial.flush();
}
}
#ifndef SYSERROR_H_
#define SYSERROR_H_
#include <arduino.h>
#include "./drivers/indicators.h"
#include "cobs.h"
#include "ts.h"
void sysError(String msg);
#endif
/*
osap/ts.cpp
typeset / keys / writing / reading
Jake Read at the Center for Bits and Atoms
(c) Massachusetts Institute of Technology 2019
This work may be reproduced, modified, distributed, performed, and
displayed for any purpose, but must acknowledge the squidworks and ponyo projects.
Copyright is retained and must be preserved. The work is provided as is;
no warranty is provided, and users accept all liability.
*/
#include "ts.h"
void ts_writeBoolean(boolean val, unsigned char *buf, uint16_t *ptr){
if(val){
buf[(*ptr) ++] = 1;
} else {
buf[(*ptr) ++] = 0;
}
}
void ts_readUint16(uint16_t *val, unsigned char *buf, uint16_t *ptr){
*val = buf[(*ptr) + 1] << 8 | buf[(*ptr)];
*ptr += 2;
}
void ts_writeUint16(uint16_t val, unsigned char *buf, uint16_t *ptr){
buf[(*ptr) ++] = val & 255;
buf[(*ptr) ++] = (val >> 8) & 255;
}
void ts_writeUint32(uint32_t val, unsigned char *buf, uint16_t *ptr){
buf[(*ptr) ++] = val & 255;
buf[(*ptr) ++] = (val >> 8) & 255;
buf[(*ptr) ++] = (val >> 16) & 255;
buf[(*ptr) ++] = (val >> 24) & 255;
}
void ts_writeString(String val, unsigned char *buf, uint16_t *ptr){
uint32_t len = val.length();
buf[(*ptr) ++] = len & 255;
buf[(*ptr) ++] = (len >> 8) & 255;
buf[(*ptr) ++] = (len >> 16) & 255;
buf[(*ptr) ++] = (len >> 24) & 255;
val.getBytes(&buf[*ptr], len + 1);
*ptr += len;
}
/*
osap/ts.h
typeset / keys / writing / reading
Jake Read at the Center for Bits and Atoms
(c) Massachusetts Institute of Technology 2019
This work may be reproduced, modified, distributed, performed, and
displayed for any purpose, but must acknowledge the squidworks and ponyo projects.
Copyright is retained and must be preserved. The work is provided as is;
no warranty is provided, and users accept all liability.
*/
#include <arduino.h>
// -------------------------------------------------------- Routing (Packet) Keys
#define PK_PPACK 77
#define PK_PTR 88
#define PK_DEST 99
#define PK_LLERR 44
#define PK_PORTF_KEY 11
#define PK_PORTF_INC 3
#define PK_BUSF_KEY 12
#define PK_BUSF_INC 5
#define PK_BUSB_KEY 14
#define PK_BUSB_INC 5
// -------------------------------------------------------- Destination Keys (arrival layer)
#define DK_APP 100 // application codes, go to -> main
#define DK_PINGREQ 101 // ping request
#define DK_PINGRES 102 // ping reply
#define DK_RREQ 111 // read request
#define DK_RRES 112 // read response
#define DK_WREQ 113 // write request
#define DK_WRES 114 // write response
// -------------------------------------------------------- Application Keys
#define AK_MOCODE 101
// -------------------------------------------------------- MVC Endpoints
#define EP_ERRKEY 150
#define EP_ERRKEY_QUERYDOWN 151
#define EP_ERRKEY_EMPTY 153
#define EP_ERRKEY_UNCLEAR 154
#define EP_NAME 171
#define EP_DESCRIPTION 172
#define EP_NUMVPORTS 181
#define EP_VPORT 182
#define EP_PORTTYPEKEY 183
#define EP_MAXSEGLENGTH 184
#define EP_PORTSTATUS 185
#define EP_PORTBUFSPACE 186
#define EP_PORTBUFSIZE 187
#define EP_NUMVMODULES 201
#define EP_VMODULE 202
#define EP_NUMINPUTS 211
#define EP_INPUT 212
#define EP_NUMOUTPUTS 221
#define EP_OUTPUT 222
#define EP_TYPE 231
#define EP_VALUE 232
#define EP_STATUS 233
#define EP_NUMROUES 243
#define EP_ROUTE 235
// ... etc, later
// -------------------------------------------------------- Reading and Writing
void ts_writeBoolean(boolean val, unsigned char *buf, uint16_t *ptr);
void ts_readUint16(uint16_t *val, uint8_t *buf, uint16_t *ptr);
void ts_writeUint16(uint16_t val, unsigned char *buf, uint16_t *ptr);
void ts_writeUint32(uint32_t val, unsigned char *buf, uint16_t *ptr);
void ts_writeString(String val, unsigned char *buf, uint16_t *ptr);
// for feather M4 express
#define CLKLIGHT_BM (uint32_t)(1 << 0)
#define CLKLIGHT_ON digitalWrite(13, HIGH)
#define CLKLIGHT_OFF digitalWrite(13, LOW)
#define CLKLIGHT_TOGGLE digitalWrite(13, !digitalRead(13))
#define CLKLIGHT_SETUP pinMode(13, OUTPUT)
//
// there's a neopixel on the board that could be used for this,
// maybe later
#define ERRLIGHT_BM (uint32_t)(1 << 0)
#define ERRLIGHT_ON
#define ERRLIGHT_OFF
#define ERRLIGHT_TOGGLE
#define ERRLIGHT_SETUP
#ifndef PERIPHERAL_NUMS_H_
#define PERIPHERAL_NUMS_H_
#define PERIPHERAL_A 0
#define PERIPHERAL_B 1
#define PERIPHERAL_C 2
#define PERIPHERAL_D 3
#define PERIPHERAL_E 4
#define PERIPHERAL_F 5
#define PERIPHERAL_G 6
#define PERIPHERAL_H 7
#define PERIPHERAL_I 8
#define PERIPHERAL_K 9
#define PERIPHERAL_L 10
#define PERIPHERAL_M 11
#define PERIPHERAL_N 12
#endif
\ No newline at end of file