cleanup, robustify

This commit is contained in:
Robert Jördens 2019-05-28 10:15:15 +00:00
parent a15b490b42
commit 1cff400d00
4 changed files with 32 additions and 12 deletions

View File

@ -9,14 +9,20 @@
* dual channel
* SPI ADC
* SPI DAC
* fixed AFE gains
* 500 kHz rate, timed
* < 2 µs latency, unmatched
* 500 kHz rate, timed sampling
* 2 µs latency, unmatched between channels
* f32 IIR math
* generic biquad (second order) IIR filter
* anti-windup
* derivative kick avoidance
* configurable output limits
## Limitations/TODOs
* Fixed AFE gains
* The IP and MAC address are [hardcoded](src/main.rs)
* Expose configurable limits
* 100Base-T only
* Digital IO, GPIO header, AFE header, EEM header are not handled
## Hardware
@ -33,3 +39,10 @@ See https://github.com/sinara-hw/Stabilizer
* `rustup target add thumbv7em-none-eabihf`
* `openocd -f stabilizer.cfg` and leave it running
* `cargo run --release`
## Protocol
Stabilizer can be configured via newline-delimited JSON over TCP.
It listens on port 1235. [stabilizer.py](stabilizer.py) contains a reference
implementation of the protocol.

View File

@ -39,6 +39,7 @@ fn macc<T>(y0: T, x: &[T], a: &[T]) -> T
x.iter().zip(a.iter()).map(|(&i, &j)| i * j).fold(y0, |y, xa| y + xa)
}
#[allow(unused)]
impl IIR {
pub fn set_pi(&mut self, kp: f32, ki: f32, g: f32) -> Result<(), &str> {
let ki = copysign(ki, kp);

View File

@ -692,7 +692,7 @@ fn main() -> ! {
#[derive(Deserialize,Serialize)]
struct Request {
channel: i8,
channel: u8,
iir: IIR,
}
@ -731,10 +731,14 @@ fn handle_command(socket: &mut net::socket::TcpSocket) {
} else {
match from_slice::<Request>(&data) {
Ok(request) => {
if request.channel > 1 {
Response{ code: 500, message: "invalid channel" }
} else {
cortex_m::interrupt::free(|_| {
unsafe { IIR_CH[request.channel as usize] = request.iir; };
});
Response{ code: 200, message: "ok" }
}
},
Err(err) => {
warn!("parse error {}", err);

View File

@ -32,12 +32,13 @@ class StabilizerConfig:
class IIR:
t_update = 2e-6
full_scale = float((1 << 15) - 1)
def __init__(self):
self.ba = np.zeros(5, np.float32)
self.y_offset = 0.
self.y_min = -float(1 << 15)
self.y_max = float(1 << 15) - 1
self.y_min = -self.full_scale - 1
self.y_max = self.full_scale
def as_dict(self):
iir = OD()
@ -70,7 +71,7 @@ class IIR:
self.ba[4] = 0.
def set_x_offset(self, o):
b = self.ba[:3].sum()*((1 << 15) - 1)
b = self.ba[:3].sum()*self.full_scale
self.y_offset = b*o
@ -100,6 +101,7 @@ if __name__ == "__main__":
i.set_x_offset(args.offset)
s = StabilizerConfig()
await s.connect(args.stabilizer)
assert args.channel in range(2)
r = await s.set(args.channel, i)
loop.run_until_complete(main())