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 * dual channel
* SPI ADC * SPI ADC
* SPI DAC * SPI DAC
* fixed AFE gains * 500 kHz rate, timed sampling
* 500 kHz rate, timed * 2 µs latency, unmatched between channels
* < 2 µs latency, unmatched
* f32 IIR math * f32 IIR math
* generic biquad (second order) IIR filter * generic biquad (second order) IIR filter
* anti-windup * anti-windup
* derivative kick avoidance * 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 ## Hardware
@ -33,3 +39,10 @@ See https://github.com/sinara-hw/Stabilizer
* `rustup target add thumbv7em-none-eabihf` * `rustup target add thumbv7em-none-eabihf`
* `openocd -f stabilizer.cfg` and leave it running * `openocd -f stabilizer.cfg` and leave it running
* `cargo run --release` * `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) x.iter().zip(a.iter()).map(|(&i, &j)| i * j).fold(y0, |y, xa| y + xa)
} }
#[allow(unused)]
impl IIR { impl IIR {
pub fn set_pi(&mut self, kp: f32, ki: f32, g: f32) -> Result<(), &str> { pub fn set_pi(&mut self, kp: f32, ki: f32, g: f32) -> Result<(), &str> {
let ki = copysign(ki, kp); let ki = copysign(ki, kp);

View File

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

View File

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