cleanup, robustify
This commit is contained in:
parent
a15b490b42
commit
1cff400d00
21
README.md
21
README.md
@ -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.
|
||||
|
@ -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);
|
||||
|
14
src/main.rs
14
src/main.rs
@ -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) => {
|
||||
cortex_m::interrupt::free(|_| {
|
||||
unsafe { IIR_CH[request.channel as usize] = request.iir; };
|
||||
});
|
||||
Response{ code: 200, message: "ok" }
|
||||
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);
|
||||
|
@ -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())
|
||||
|
Loading…
Reference in New Issue
Block a user