diff --git a/Cargo.lock b/Cargo.lock index b53b6fc..1f25da2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -93,7 +93,7 @@ dependencies = [ "regex", "rustc-hash", "shlex", - "syn 2.0.74", + "syn 2.0.75", "which", ] @@ -129,7 +129,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.74", + "syn 2.0.75", ] [[package]] @@ -146,9 +146,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "camino" -version = "1.1.7" +version = "1.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0ec6b951b160caa93cc0c7b209e5a3bff7aae9062213451ac99493cd844c239" +checksum = "8b96ec4966b5813e2c0507c1f86115c8c5abaadc3980879c3424042a02fd1ad3" dependencies = [ "serde", ] @@ -188,9 +188,12 @@ dependencies = [ [[package]] name = "cc" -version = "1.1.10" +version = "1.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9e8aabfac534be767c909e0690571677d49f41bd8465ae876fe043d52ba5292" +checksum = "72db2f7947ecee9b03b510377e8bb9077afa27176fdbff55c51027e976fdcc48" +dependencies = [ + "shlex", +] [[package]] name = "cexpr" @@ -238,9 +241,9 @@ dependencies = [ [[package]] name = "cmake" -version = "0.1.50" +version = "0.1.51" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a31c789563b815f77f4250caee12365734369f942439b7defd71e18a48197130" +checksum = "fb1e43aa7fd152b1f968787f7dbcdeb306d1867ff373c69955211876c053f91a" dependencies = [ "cc", ] @@ -340,7 +343,7 @@ dependencies = [ "ident_case", "proc-macro2", "quote", - "syn 2.0.74", + "syn 2.0.75", ] [[package]] @@ -351,7 +354,7 @@ checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" dependencies = [ "darling_core", "quote", - "syn 2.0.74", + "syn 2.0.75", ] [[package]] @@ -374,7 +377,7 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn 2.0.74", + "syn 2.0.75", ] [[package]] @@ -532,7 +535,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.74", + "syn 2.0.75", ] [[package]] @@ -855,9 +858,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.3.0" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de3fc2e30ba82dd1b3911c8de1ffc143c74a914a14e99514d7637e3099df5ea0" +checksum = "93ead53efc7ea8ed3cfb0c79fc8023fbb782a5432b52830b6518941cebe6505c" dependencies = [ "equivalent", "hashbrown", @@ -880,9 +883,9 @@ checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" [[package]] name = "js-sys" -version = "0.3.69" +version = "0.3.70" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" +checksum = "1868808506b929d7b0cfa8f75951347aa71bb21144b7791bae35d9bccfcfe37a" dependencies = [ "wasm-bindgen", ] @@ -901,9 +904,9 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" [[package]] name = "libc" -version = "0.2.155" +version = "0.2.158" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" +checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439" [[package]] name = "libloading" @@ -1032,7 +1035,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.74", + "syn 2.0.75", ] [[package]] @@ -1066,7 +1069,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5f12335488a2f3b0a83b14edad48dca9879ce89b2edd10e80237e4e852dd645e" dependencies = [ "proc-macro2", - "syn 2.0.74", + "syn 2.0.75", ] [[package]] @@ -1270,29 +1273,29 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.207" +version = "1.0.208" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5665e14a49a4ea1b91029ba7d3bca9f299e1f7cfa194388ccc20f14743e784f2" +checksum = "cff085d2cb684faa248efb494c39b68e522822ac0de72ccf08109abde717cfb2" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.207" +version = "1.0.208" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6aea2634c86b0e8ef2cfdc0c340baede54ec27b1e46febd7f80dffb2aa44a00e" +checksum = "24008e81ff7613ed8e5ba0cfaf24e2c2f1e5b8a0495711e44fcd4882fca62bcf" dependencies = [ "proc-macro2", "quote", - "syn 2.0.74", + "syn 2.0.75", ] [[package]] name = "serde_json" -version = "1.0.124" +version = "1.0.125" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66ad62847a56b3dba58cc891acd13884b9c61138d330c0d7b6181713d4fce38d" +checksum = "83c8e735a073ccf5be70aa8066aa984eaf2fa000db6c8d0100ae605b366d31ed" dependencies = [ "itoa", "memchr", @@ -1368,7 +1371,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.74", + "syn 2.0.75", ] [[package]] @@ -1390,9 +1393,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.74" +version = "2.0.75" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fceb41e3d546d0bd83421d3409b1460cc7444cd389341a4c880fe7a042cb3d7" +checksum = "f6af063034fc1935ede7be0122941bafa9bacb949334d090b77ca98b5817c7d9" dependencies = [ "proc-macro2", "quote", @@ -1429,7 +1432,7 @@ checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261" dependencies = [ "proc-macro2", "quote", - "syn 2.0.74", + "syn 2.0.75", ] [[package]] @@ -1524,9 +1527,9 @@ dependencies = [ [[package]] name = "unicode-xid" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" +checksum = "229730647fbc343e3a80e463c1db7f78f3855d3f3739bee0dda773c9a037c90a" [[package]] name = "untrusted" @@ -1591,34 +1594,35 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.92" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" +checksum = "a82edfc16a6c469f5f44dc7b571814045d60404b55a0ee849f9bcfa2e63dd9b5" dependencies = [ "cfg-if", + "once_cell", "wasm-bindgen-macro", ] [[package]] name = "wasm-bindgen-backend" -version = "0.2.92" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" +checksum = "9de396da306523044d3302746f1208fa71d7532227f15e347e2d93e4145dd77b" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2", "quote", - "syn 2.0.74", + "syn 2.0.75", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-macro" -version = "0.2.92" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" +checksum = "585c4c91a46b072c92e908d99cb1dcdf95c5218eeb6f3bf1efa991ee7a68cccf" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -1626,22 +1630,22 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.92" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" +checksum = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836" dependencies = [ "proc-macro2", "quote", - "syn 2.0.74", + "syn 2.0.75", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.92" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" +checksum = "c62a0a307cb4a311d3a07867860911ca130c3494e8c2719593806c08bc5d0484" [[package]] name = "webpki-roots" diff --git a/Cargo.toml b/Cargo.toml index 506b30e..f6437fb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,8 +22,8 @@ log = { version = "0.4.22", default-features = false } esp-idf-svc = { version = "0.49.1", features = ["default", "pio", "embassy-sync", "critical-section"], default-features = false } embedded-svc = { version = "0.28.0", features = ["std"], default-features = false} anyhow = { version = "1.0.86", features = ["std"], default-features = false} -serde = { version = "1.0.207", features = ["std", "derive"], default-features = false} -serde_json = { version = "1.0.124", features = ["std"], default-features = false} +serde = { version = "1.0.208", features = ["std", "derive"], default-features = false} +serde_json = { version = "1.0.125", features = ["std"], default-features = false} [build-dependencies] embuild = "0.32.0" \ No newline at end of file diff --git a/README.md b/README.md index dcf4224..3c04d54 100644 --- a/README.md +++ b/README.md @@ -16,8 +16,8 @@ POST http://192.168.4.64/boat Content-Type: application/json { - "motor_speed": 255, - "rudder_angle": 90 + "motor_speed": "120", + "rudder_angle": "90" } ``` diff --git a/build.rs b/build.rs index 2738708..fff1a62 100644 --- a/build.rs +++ b/build.rs @@ -1,6 +1,6 @@ fn main() { embuild::espidf::sysenv::output(); - println!("cargo:rustc-env=WIFI_AP_MODE=1"); // Set to anything else for client mode (connects to your netwok) - println!("cargo:rustc-env=WIFI_SSID=WIFI_BOAT_HOTSPOT"); // Replace with your own SSID (AP SSID or Network SSID) + println!("cargo:rustc-env=WIFI_AP_MODE=1"); // Set to 1 for AP mode, anything else for client mode (connects to your netwok) + println!("cargo:rustc-env=WIFI_SSID=Boat_Hotspot"); // Replace with your own SSID (AP SSID or Network SSID) println!("cargo:rustc-env=WIFI_PASSWORD=password"); // Replace with your own password (AP password or Network password) } diff --git a/espflash.toml b/espflash.toml index 4c3b127..f0bb709 100644 --- a/espflash.toml +++ b/espflash.toml @@ -9,4 +9,4 @@ vid = "303a" pid = "1001" [flash] -size = "8MB" +size = "16MB" diff --git a/src/boat.rs b/src/boat.rs new file mode 100644 index 0000000..500df30 --- /dev/null +++ b/src/boat.rs @@ -0,0 +1,80 @@ +use anyhow::Result; +use esp_idf_svc::hal::ledc::LedcDriver; + +pub(crate) struct Boat<'a> { + pub(crate) motor: Motor<'a>, + pub(crate) rudder: Rudder<'a>, +} + + +pub(crate) struct Motor<'a> { + pwm: LedcDriver<'a>, + max_duty: u32 +} + +impl<'a> Motor<'a> { + pub(crate) fn new(pwm: LedcDriver<'a>) -> Self { + let max_duty = pwm.get_max_duty(); + Motor { pwm, max_duty } + } + + pub(crate) fn start(&mut self) -> Result<()> { + self.pwm.enable()?; + self.set_power(self.max_duty / 2)?; + Ok(()) + } + + pub(crate) fn set_power(&mut self, value: u32) -> Result<()> { + self.pwm.set_duty(value)?; + Ok(()) + } +} + +pub(crate) struct Rudder<'a> { + servo: LedcDriver<'a>, + min_duty: u32, + max_duty: u32, + min_angle: u32, + max_angle: u32 +} + +impl<'a> Rudder<'a> { + + + + pub(crate) fn new(servo: LedcDriver<'a>) -> Self { + let max_duty = servo.get_max_duty(); + let min_duty = max_duty * 25 / 1000; + let max_duty = max_duty * 125 / 1000; + Rudder { + servo, + min_duty, + max_duty, + min_angle: 0, + max_angle: 180 + } + } + + pub(crate) fn start(&mut self) -> Result<()> { + self.servo.enable()?; + self.set_angle(90) + } + + + pub(crate) fn set_angle(&mut self, angle: u32) -> Result<()> { + let duty = map_angle_to_duty( + angle, + self.min_angle, + self.max_angle, + self.min_duty, + self.max_duty + ); + self.servo.set_duty(duty)?; + Ok(()) + } + +} + +fn map_angle_to_duty(x: u32, in_min: u32, in_max: u32, out_min: u32, out_max: u32) -> u32 { + (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min +} \ No newline at end of file diff --git a/src/boat/mod.rs b/src/boat/mod.rs deleted file mode 100644 index 63d7597..0000000 --- a/src/boat/mod.rs +++ /dev/null @@ -1,7 +0,0 @@ -pub(crate) mod motor; -pub(crate) mod rudder; - -pub(crate) struct Boat<'a> { - pub(crate) motor: motor::Motor<'a>, - pub(crate) rudder: rudder::Rudder<'a>, -} diff --git a/src/boat/motor.rs b/src/boat/motor.rs deleted file mode 100644 index 5a5a232..0000000 --- a/src/boat/motor.rs +++ /dev/null @@ -1,40 +0,0 @@ -use anyhow::Result; -use esp_idf_svc::hal::{ - ledc::{config::TimerConfig, LedcDriver, LedcTimerDriver}, - prelude::*, -}; - -pub(crate) struct Motor<'a> { - pwm: LedcDriver<'a>, -} - -impl<'a> Motor<'a> { - pub(crate) fn new(pwm: LedcDriver<'a>) -> Self { - Motor { pwm } - } - - pub(crate) fn start(&mut self) -> Result<()> { - self.pwm.enable()?; - Ok(()) - } - - pub(crate) fn set_power(&mut self, value: u8) -> Result<()> { - self.pwm.set_duty(value.into())?; - Ok(()) - } -} - -pub(crate) fn setup_motor() -> Result> { - let peripherals = Peripherals::take()?; - let pwm = LedcDriver::new( - peripherals.ledc.channel0, - LedcTimerDriver::new( - peripherals.ledc.timer0, - &TimerConfig::new().frequency(10.kHz().into()), - )?, - peripherals.pins.gpio5, - )?; - let mut motor = Motor::new(pwm); - motor.start()?; - Ok(motor) -} diff --git a/src/boat/rudder.rs b/src/boat/rudder.rs deleted file mode 100644 index cd44ed1..0000000 --- a/src/boat/rudder.rs +++ /dev/null @@ -1,58 +0,0 @@ -use std::sync::{Arc, Mutex}; - -use anyhow::Result; -use esp_idf_svc::hal::{ - ledc::{self, config::TimerConfig, LedcDriver, LedcTimerDriver}, - prelude::*, -}; - -pub(crate) struct Rudder<'a> { - servo: Arc>>, - min_angle: u32, - spread: u32, -} - -impl<'a> Rudder<'a> { - pub(crate) fn new(servo: Arc>>) -> Self { - let max_duty = servo.lock().unwrap().get_max_duty(); - let max_angle = max_duty / 8; - let min_angle = max_duty / 40; - let spread = max_angle - min_angle / 180; - Rudder { - servo, - min_angle, - spread, - } - } - - pub(crate) fn start(&mut self) -> Result<()> { - self.servo.lock().unwrap().enable()?; - Ok(()) - } - - pub(crate) fn set_angle(&mut self, angle: u32) -> Result<()> { - let duty = angle * self.spread + self.min_angle; - self.servo.lock().unwrap().set_duty(duty)?; - Ok(()) - } -} - -pub(crate) fn setup_rudder() -> Result> { - let peripherals = Peripherals::take()?; - let servo = Arc::new(Mutex::new( - LedcDriver::new( - peripherals.ledc.channel1, - LedcTimerDriver::new( - peripherals.ledc.timer1, - &TimerConfig::new() - .frequency(50.Hz()) - .resolution(ledc::Resolution::Bits14), - )?, - peripherals.pins.gpio5, - ) - .unwrap(), - )); - let mut rudder = Rudder::new(servo); - rudder.start()?; - Ok(rudder) -} diff --git a/src/main.rs b/src/main.rs index 856b9de..706eaa5 100644 --- a/src/main.rs +++ b/src/main.rs @@ -3,36 +3,72 @@ mod server; mod wifi; use anyhow::Result; -use log::{debug, info}; +use boat::{Motor, Rudder}; +use esp_idf_svc::hal::{ledc::{config::TimerConfig, LedcDriver, LedcTimerDriver, Resolution}, prelude::*}; +use log::info; use std::{thread::sleep, time::Duration}; const WIFI_SSID: &str = env!("WIFI_SSID"); const WIFI_PASSWORD: &str = env!("WIFI_PASSWORD"); const WIFI_AP_MODE: &str = env!("WIFI_AP_MODE"); + fn main() -> Result<()> { // Initialize ESP-IDF system and logging. esp_idf_svc::sys::link_patches(); esp_idf_svc::log::EspLogger::initialize_default(); + let peripherals = Peripherals::take()?; + info!("connecting to wifi..."); - let wifi = wifi::setup_wifi(WIFI_SSID, WIFI_PASSWORD, WIFI_AP_MODE == "1")?; + let wifi = wifi::setup_wifi(WIFI_SSID, WIFI_PASSWORD, WIFI_AP_MODE == "1", peripherals.modem)?; sleep(Duration::from_secs(1)); let ip = wifi.sta_netif().get_ip_info()?.ip; info!("connected to wifi with ip: {ip:?}"); // Create the boat and its components. - let boat = boat::Boat { - motor: boat::motor::setup_motor()?, - rudder: boat::rudder::setup_rudder()?, - }; + let motor_channel = peripherals.ledc.channel0; + let motor_timer = peripherals.ledc.timer0; + let motor_timer_config = TimerConfig::new() + .frequency(50.kHz().into()) + .resolution(Resolution::Bits8); + let motor_pwm_pin = peripherals.pins.gpio5; + let motor_timer_driver = LedcTimerDriver::new( motor_timer, &motor_timer_config)?; + let motor_pwm = LedcDriver::new( + motor_channel, + motor_timer_driver, + motor_pwm_pin, + )?; + + let mut motor = Motor::new(motor_pwm); + motor.start()?; + + + let servo_channel = peripherals.ledc.channel1; + let servo_timer = peripherals.ledc.timer1; + let servo_timer_config = TimerConfig::default() + .frequency(50.Hz()) + .resolution(Resolution::Bits14); + let servo_pwm_pin = peripherals.pins.gpio6; + let servo_timer_driver = LedcTimerDriver::new(servo_timer, &servo_timer_config)?; + let servo = LedcDriver::new( + servo_channel, + servo_timer_driver, + servo_pwm_pin, + )?; + + let mut rudder = Rudder::new(servo); + rudder.start()?; + + + let boat = boat::Boat{ motor, rudder }; // Set up http server and keep a reference to it (otherwise it drops out of scope). let _server = server::setup_server(boat)?; // Keep the main thread alive by sleeping periodically. loop { - debug!("server is still running."); - sleep(Duration::from_secs(10)); + info!("server is still running. wifi status: {}", wifi.is_connected()?); + sleep(Duration::from_secs(20)); } } diff --git a/src/server.rs b/src/server.rs index 905643e..46adf76 100644 --- a/src/server.rs +++ b/src/server.rs @@ -1,18 +1,19 @@ use crate::boat::Boat; use anyhow::Result; use embedded_svc::http::Headers; -use esp_idf_svc::http::{ +use esp_idf_svc::{http::{ server::{EspHttpConnection, EspHttpServer, Request}, Method, -}; +}, io::Write}; use esp_idf_svc::io::Read; +use log::info; use serde::{Deserialize, Serialize}; use std::sync::{Arc, Mutex}; #[derive(Debug, Serialize, Deserialize)] struct BoatInstruction { - pub(crate) motor_speed: u8, - pub(crate) rudder_angle: u32, + pub(crate) motor_speed: String, + pub(crate) rudder_angle: String, } pub(crate) fn setup_server(boat: Boat<'static>) -> Result> { @@ -28,9 +29,17 @@ pub(crate) fn setup_server(boat: Boat<'static>) -> Result // Boat instruction handler server.fn_handler::("/boat", Method::Post, move |mut request| { let instruction = extract_boat_instruction(&mut request)?; + info!("sending boat instruction: {instruction:?}"); let mut boat_guard = boat.lock().unwrap(); - boat_guard.motor.set_power(instruction.motor_speed)?; - boat_guard.rudder.set_angle(instruction.rudder_angle)?; + boat_guard.motor.set_power(instruction.motor_speed.parse()?)?; + boat_guard.rudder.set_angle(instruction.rudder_angle.parse()?)?; + Ok(()) + })?; + + // Web UI handler + let html = include_str!("./web/index.html"); + server.fn_handler::("/", Method::Get, | request| { + request.into_ok_response()?.write_all(html.as_bytes())?; Ok(()) })?; diff --git a/web/index.html b/src/web/index.html similarity index 81% rename from web/index.html rename to src/web/index.html index 355990f..838792a 100644 --- a/web/index.html +++ b/src/web/index.html @@ -4,30 +4,31 @@ Boat Controller - + + - -
-

Boat Controller

+ + +

Boat Controller

+ +
+
- + 0
@@ -36,15 +37,18 @@

Boat Controller

- +
+