Skip to content

Commit 4d4e21f

Browse files
committed
Drafted LoadDemo, fixed address in header
1 parent 49527b5 commit 4d4e21f

4 files changed

Lines changed: 569 additions & 10 deletions

File tree

demos/LoadDemo/LoadDemo.ino

Lines changed: 232 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,232 @@
1+
/**
2+
* @file LoadDemo.ino
3+
* @brief Manually control the actuator
4+
* @version 0.2.1
5+
* @since Winter 2026
6+
* @author Noah (@BobSaidHi <https://github.com/bobsaidhi>) for
7+
* @CalPolyWindPower <https://github.com/calpolywindpower>
8+
* @author Inspired by Trevor (@rover-t <https://github.com/rover-t>) at
9+
* @CalPolyWindPower <https://github.com/calpolywindpower>
10+
*
11+
* The Unexpected Maker ProS3[D] has one USB C port. The baud rate is set
12+
* to to 115,000 below and uses the internal USB peripheral, not a separate
13+
* chip. Some compatible serial monitors include the Arduino IDE
14+
* <https://www.arduino.cc/en/software/>, VSCode "Serial" extension from
15+
* Microsoft
16+
* <https://marketplace.visualstudio.com/items?itemName=ms-vscode.vscode-serial-monitor>,or
17+
* PuTTY.
18+
*
19+
* To re-flash:
20+
* 1. Install Arduino IDE (I recommend >v2.0) from
21+
* https://www.arduino.cc/en/software/ if you don't have it.
22+
* 2. Go to the boards manager in the left sidebar and install
23+
* "esp32" by Espressif Systems.
24+
* A. If it's missing, go to the following board URL under
25+
* File > Preferences > Settings >
26+
* Additional Board Manager URLS:
27+
* `https://espressif.github.io/arduino-esp32/package_esp32_index.json`
28+
* (See also:
29+
* https://docs.espressif.com/projects/arduino-esp32/en/latest/installing.html)
30+
* 3. Load the attached sketch or the latest version from GitHub:
31+
* https://github.com/CalPolyWindPower/2026-Controls_Load/blob/main/demos/LoadDemo/LoadDemo.ino
32+
* 4. Set the board to "UM PROS3". It may show up as "ESP32 Family Device at first" or even multiple devices (Select the first one).
33+
* 5. Under Tools, set "USB CDC On Boot" to "Enabled"
34+
* 6. [Recommended] Under Tools, set "Core Debug Level" to "Info"
35+
* 7. Select Upload
36+
* 8. Open a serial terminal
37+
* A. In Arduino IDE, got Tools > Serial Monitor and switch to 115200 baud
38+
*
39+
* @author Noah (@BobSaidHi <https://github.com/bobsaidhi>) for Cal Poly Wind
40+
* Power (@calpolywindpower <https://github.com/calpolywindpower>)
41+
* @see Inspired by
42+
* https://github.com/rover-t/CPWP2024-Controls/blob/main/ControlCode/OpenLoopController/OpenLoopController.ino
43+
* @see Inspired by
44+
* https://github.com/rover-t/CPWP2024-Controls/blob/main/ControlCode/OpenLoopController_alt/OpenLoopController_alt.ino
45+
* @see Based on https://github.com/CalPolyWindPower/2026-Controls_Nacelle/blob/main/demos/ActuatorDemo/ActuatorDemo.ino
46+
*/
47+
48+
// MARK: Imports
49+
#include <Arduino.h>
50+
#include <cstdint> // Fixed size integers
51+
#include <Wire.h>
52+
#include "./src/MCP23008T/MCP23008T.hpp"
53+
54+
// MARK: Globals
55+
56+
/**
57+
* @brief Configuration for serial (UART) communication
58+
* @details A namespace can be used to organize related constants, variables,
59+
* and objects together.
60+
* @see https://www.geeksforgeeks.org/cpp/namespace-in-c/
61+
* @details `constexpr` is similar to `#define` macros but type checked. Macros
62+
* and `constexpr` variables are guaranteed and to be evaluated at compile
63+
* time, and may even be embedded in the immediate field of an instruction,
64+
* which means they do not take up additional storage space, memory, or
65+
* registers at turn time.
66+
* @see https://en.cppreference.com/w/cpp/language/constexpr.html
67+
* @see https://www.sciencedirect.com/topics/computer-science/immediate-operand
68+
*/
69+
namespace SERIAL_CONFIG {
70+
constexpr long BAUD = 115200; // BAUD rate (bits per second)
71+
} // namespace SERIAL_CONFIG
72+
73+
/**
74+
* @brief Configuration for the load and related pins
75+
* @details The standard integer types, such as int, only specify a minimum
76+
* size. FEEDBACK_PIN is of the fixed width unsigned integer type `uint8_t`,
77+
* which is always 8 bits. This was chosen because the `pinmode()` function
78+
* takes an `uint8_t` as an argument.
79+
*/
80+
namespace LOAD {
81+
/**
82+
* Valid addresses are 0x40, 0x42, 0x44, 0x46, 0x48, 0x4A, 0x4C, & 0x4E
83+
*/
84+
constexpr MCP23008T::I2C_ADDRESS I2C_ADDRESS = MCP23008T::I2C_ADDRESS::I2C_ADDR_0x27; // A0-A2 all high
85+
86+
/**
87+
* @brief Bitmask for the load control pins.
88+
* @details Only the first 6 pins (0-5) are used for load control.
89+
*/
90+
constexpr uint8_t PINS_Msk = 0b0011'1111;
91+
92+
MCP23008T loadDevice(I2C_ADDRESS,
93+
&Wire);
94+
95+
bool configureLoad() {
96+
// Check all addr.
97+
// for(MCP23008T::I2C_ADDRESS addr = MCP23008T::I2C_ADDRESS::I2C_ADDR_0x40; addr <= MCP23008T::I2C_ADDRESS::I2C_ADDR_0x4E; addr = (MCP23008T::I2C_ADDRESS)(addr + 2)) {
98+
// MCP23008T tempLoad(addr, &Wire);
99+
// for(uint8_t addr = 0; addr <= 0b0111'1111; addr++) {
100+
// MCP23008T tempLoad(addr, &Wire);
101+
// if (!tempLoad.begin()) {
102+
// ESP_LOGE("cL", "Failed to initialize MCP23008T device at 0x%02X",
103+
// addr);
104+
// } else {
105+
// ESP_LOGI("cL", "Sucess init MCP23008T device at 0x%02X",
106+
// addr);
107+
// }
108+
// }
109+
110+
111+
if (!loadDevice.begin()) {
112+
ESP_LOGE("cL", "Failed to initialize MCP23008T device at 0x%02X",
113+
loadDevice.getAddress());
114+
}
115+
116+
// First six pins outputs, made last two inputs as that's the default
117+
if (!loadDevice.setIODir(0b1100'0000)) {
118+
ESP_LOGE("cL", "Failed to set IODIR on MCP23008T at 0x%02X",
119+
loadDevice.getAddress());
120+
return false;
121+
}
122+
123+
// Disable sequential operation, other settings default
124+
if (!loadDevice.setConfig(0b0010'0000)) {
125+
ESP_LOGW("cL", "Failed to set IOCON on MCP23008T at 0x%02X",
126+
loadDevice.getAddress());
127+
}
128+
129+
// Set all outputs low, note that pin 0 is inverted
130+
if (!loadDevice.setGPIO(0b0000'0000)) {
131+
ESP_LOGE("cL", "Failed to set GPIO on MCP23008T at 0x%02X",
132+
loadDevice.getAddress());
133+
return false;
134+
}
135+
136+
// Else: success
137+
return true;
138+
}
139+
} // namespace LOAD
140+
141+
/**
142+
* @brief Configuration for the LED and related pins
143+
* @details As we have more program storage space, and hopefully more RAM than
144+
* we need, the slight performance boost from the fast integer types, such ast
145+
* uint_fast32_t, are likely worth it for us. These types specify a minium
146+
* size, but allow the compiler (actually the system/ standard libraries) to
147+
* substitute a type that a particular chip (micro-architecture) is more
148+
* optimized for.
149+
*/
150+
// namespace LED {
151+
// constexpr uint8_t PIN = 15; // LED pin
152+
// constexpr uint_fast32_t TIME_ON_MS =
153+
// 1000; // Time LED stays on in milliseconds
154+
// constexpr uint_fast32_t TIME_OFF_MS =
155+
// 3000; // Time LED stays off in milliseconds
156+
// } // namespace LED
157+
158+
/**
159+
* @details put your setup code here, to run once:
160+
*/
161+
void setup() {
162+
Serial.begin(SERIAL_CONFIG::BAUD); // Start serial
163+
164+
// The DFRobot FireBeetle 2 ESP32-C5 has one user controllable LED built in
165+
// #if defined(ESP32)
166+
// /**
167+
// * @see
168+
// * https://docs.arduino.cc/language-reference/en/functions/digital-io/pinMode/
169+
// */
170+
// pinMode(LED::PIN, OUTPUT); // Setup LED
171+
// digitalWrite(LED::PIN, HIGH); // Toggle LED
172+
173+
// // Debug actuator pin
174+
// // pinMode(Actuator::CONTROL_PIN, OUTPUT); // Setup LED
175+
// // digitalWrite(Actuator::CONTROL_PIN, HIGH); // Toggle LED
176+
// // while(1) {}
177+
// #endif
178+
179+
/**
180+
* @details The load object, is in the Actuator namespace
181+
*/
182+
Wire.begin(8, 9); // SDA, SCL
183+
LOAD::configureLoad();
184+
LOAD::loadDevice.setGPIO(0b0000'0000);
185+
Serial.print("Input load setPoint as a 7 bit unsigned integer: ");
186+
}
187+
188+
/**
189+
* @details put your main code here, to run repeatedly:
190+
*/
191+
void loop() {
192+
// Check if Serial data is available
193+
if (Serial.available() > 0) {
194+
int setPoint = Serial.parseInt();
195+
196+
// It would appear parseInt returns 0 on failure
197+
if (setPoint != 0) {
198+
// Check and write position
199+
if (setPoint < 0) {
200+
Serial.print("\nsetPoint too small: ");
201+
Serial.println(setPoint);
202+
} else if ((setPoint > LOAD::PINS_Msk)) {
203+
Serial.print("\nsetPoint too large: ");
204+
Serial.println(setPoint);
205+
} else {
206+
Serial.print("\nNew setPoint: ");
207+
Serial.println(setPoint);
208+
LOAD::loadDevice.setGPIO(0b0000'0000);
209+
}
210+
211+
Serial.print("Input load setPoint as a bitset: ");
212+
}
213+
}
214+
215+
// #if defined(ESP32)
216+
// // Toggle LED because why not, but only on the EPS32
217+
// static int lastLEDTime_ms = 0; // Track time toggled
218+
// static bool LEDOn = false; // Track LED state
219+
220+
// // Check LED state and update
221+
// if (!LEDOn && millis() - lastLEDTime_ms > LED::TIME_OFF_MS) {
222+
// digitalWrite(LED::PIN, HIGH); // Toggle LED
223+
// lastLEDTime_ms = millis(); // Save time
224+
// LEDOn = true;
225+
// } else if (LEDOn && millis() - lastLEDTime_ms > LED::TIME_ON_MS) {
226+
// digitalWrite(LED::PIN, LOW); // Toggle LED
227+
// lastLEDTime_ms = millis(); // Save time
228+
// LEDOn = false;
229+
// }
230+
// #endif
231+
}
232+
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
[ 5123][V][esp32-hal-periman.c:235] perimanSetBusDeinit(): Deinit function for type I2C_MASTER_SDA (30) successfully set to 0x42004d58
2+
[ 5123][V][esp32-hal-periman.c:235] perimanSetBusDeinit(): Deinit function for type I2C_MASTER_SCL (31) successfully set to 0x42004d58
3+
[ 5124][I][esp32-hal-i2c-ng.c:112] i2cInit(): Initializing I2C Master: num=0 sda=8 scl=9 freq=100000
4+
[ 5125][V][esp32-hal-periman.c:160] perimanSetPinBus(): Pin 8 successfully set to type I2C_MASTER_SDA (30) with bus 0x1
5+
[ 5125][V][esp32-hal-periman.c:160] perimanSetPinBus(): Pin 9 successfully set to type I2C_MASTER_SCL (31) with bus 0x1
6+
[ 5126][W][Wire.cpp:300] begin(): Bus already started in Master Mode.
7+
[ 5126][V][esp32-hal-i2c-ng.c:231] i2cAddDeviceIfNeeded(): added device: bus=0 addr=0x27 handle=0x3c050dc8
8+
[ 5127][V][esp32-hal-i2c-ng.c:272] i2cWrite(): i2c_master_transmit: bus=0 addr=0x27 handle=0x3c050dc8 size=2
9+
[ 5128][V][esp32-hal-i2c-ng.c:272] i2cWrite(): i2c_master_transmit: bus=0 addr=0x27 handle=0x3c050dc8 size=2
10+
[ 5128][V][esp32-hal-i2c-ng.c:272] i2cWrite(): i2c_master_transmit: bus=0 addr=0x27 handle=0x3c050dc8 size=2
11+
[ 5129][V][esp32-hal-i2c-ng.c:272] i2cWrite(): i2c_master_transmit: bus=0 addr=0x27 handle=0x3c050dc8 size=2
12+
[...]
13+
=========== After Setup Start ============
14+
INTERNAL Memory Info:
15+
------------------------------------------
16+
Total Size : 386472 B ( 377.4 KB)
17+
Free Bytes : 347496 B ( 339.4 KB)
18+
Allocated Bytes : 33424 B ( 32.6 KB)
19+
Minimum Free Bytes: 342220 B ( 334.2 KB)
20+
Largest Free Block: 286708 B ( 280.0 KB)
21+
------------------------------------------
22+
SPIRAM Memory Info:
23+
------------------------------------------
24+
Total Size : 8388608 B (8192.0 KB)
25+
Free Bytes : 8385032 B (8188.5 KB)
26+
Allocated Bytes : 1152 B ( 1.1 KB)
27+
Minimum Free Bytes: 8385032 B (8188.5 KB)
28+
Largest Free Block: 8257524 B (8064.0 KB)
29+
------------------------------------------
30+
GPIO Info:
31+
------------------------------------------
32+
GPIO : BUS_TYPE[bus/unit][chan]
33+
--------------------------------------
34+
8 : I2C_MASTER_SDA[0]
35+
9 : I2C_MASTER_SCL[0]
36+
19 : USB_DM
37+
20 : USB_DP
38+
43 : UART_TX[0]
39+
44 : UART_RX[0]
40+
============ After Setup End =============
41+
42+
New setPoint: 5
43+
[280218][V][esp32-hal-i2c-ng.c:272] i2cWrite(): i2c_master_transmit: bus=0 addr=0x27 handle=0x3c050dc8 size=2
44+
[...]

0 commit comments

Comments
 (0)