Wizfloats
Wizfloats are a type of floating device for ocean health. The floats will collect temperature, depth, and biogeochemical data information
Software Apps and online services
WIZFLOATS
Wizfloats are a type of floating device for ocean health. The floats will collect temperature, depth, and biogeochemical data information.
Before I create this Wizfloats, which has been widely implemented worldwide. And everyone can freely access the data for research, such as Argo.ucsd.edu and Mbari.org. However, these tools or applications have not been widely distributed in Indonesia. Because all activities will be regulated by the government through the BMKG agency. So the system I am creating has never been tested in my own country.
bifloats is a prototype of an autonomous underwater robot, which consists of only one cylinder carrying several sensors. The system works very simply: this floating robot will automatically sink using a ballast tank system similar to submarines, then it will read all conditions within the sea, including depth and temperature. After some time, it will resurface. Ideally, in this experiment, the data collected should be automatically transmitted using wifi or satellite, but for this project, I have difficulty finding devices that can support the components and size of my cylinder. Therefore, for now, it only utilizes cables for data transmission. With the presence of Wizfloats.
In this production, there are several steps involved:
- 3D Design using Solidworks 2022 Student Version
- Mechanical Assembly
- Controller Design
- Programming
Hardware
- Surf5
- WIZPOE-P1
- Stepper Motor
- A4988 - Stepper Motor Driver
- Depth/ Pressure Sensor (ms5837 blue robotics)
- DS18B20 Waterproof Temperature Sensor
- limit switch
- syringe 20ml
- Lippo Battery 2 cell
- UBEC
Software
- Visual Studio
- Solidworks
Step 1: 3D Design
Every time I work on a project, after coming up with an idea, I always design it using the CAD application that I usually use, which is Solidworks 2022 Student Version. By using this CAD application, I can lay out the mechanical components of the project I'm working on. I can even simulate whether the position and movements are okay.
Video Design
Step 2 : Mechanical Assembly
The mechanical system in this Wizfloats is based on the ballast tank system used in submarines. The following are the materials that will be used in the construction of bifloats:
- Acrylic tube
- Acrylic for end cap, syringe stand and stepper mounting
- Smooth rod stainless steel 304 8mm, pcb spacer , bolt and hexnut
- Syringe 20ml
- Stepper motor, leadScrew T8-2-D8, Copper nut LeadScrew, Flexible coupling (all part from cnc machine)
- Stopper speccer (make from 3d prtinter)
- Electronic component
The mechanical system in the bifloats robot mimics the style of submarine systems using a ballast tank system. Three syringes will be used as ballast tanks, which will be operated by a stepper motor. This allows the bifloat to adjust its buoyancy by adding water into the cylinder.
This ballast tank system thatt will cause the Wizfloat to move up and down in the water.
Video Assembly
next step make a waterproof using super glue and epocxy glue
Before casting, first, to adhere the syringe to acrylic, we will apply super glue on the syringe side. After applying the super glue and waiting for it to dry, the we add epoxy resin as a waterproof coating or sealer. I'm using epoxy from Devcon
Video Waterproof
STEP 3: Controller Design
- Surf5
- DS18B20 Waterproof Temperature Sensor
- Depth/ Pressure Sensor (ms5837 blue robotics)
- A4988 - Stepper Motor Driver
- On off switch (blue robotics)
- limit switch
- UBEC
This for Electronic schematic
Limitswitch Position
STEP 4 : PROGRAMMING
Test stepper motor
For test motor stepper, use code from example surf5 (projects/W7500x_StdPeriph_Examples/GPIO/GPIO_IOToggle) , stepper need 2 pin digital as dir pin and step pin. so first must be initialization
#define DIR_PIN GPIO_Pin_14
#define STEP_PIN GPIO_Pin_13
add function GPIO_Config
static void GPIO_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_15;
GPIO_InitStructure.GPIO_Direction = GPIO_Direction_OUT;
GPIO_InitStructure.GPIO_AF = PAD_AF1;
GPIO_Init(GPIOC, &GPIO_InitStructure);
// Configure the pins for the stepper motor control
GPIO_InitStructure.GPIO_Pin = DIR_PIN | STEP_PIN;
GPIO_Init(GPIOC, &GPIO_InitStructure);
}
and then code in looping
while (1) {
GPIO_SetBits(GPIOC, DIR_PIN);
// Rotate stepper motor one revolution in one direction
for(int i = 0; i < 1000; i++) {
GPIO_SetBits(GPIOC, STEP_PIN);
Delay(1000); // Adjust the delay for stepper speed
GPIO_ResetBits(GPIOC, STEP_PIN);
Delay(1000);
}
Delay(800000);
// Set direction to counterclockwise
GPIO_ResetBits(GPIOC, DIR_PIN);
// Rotate stepper motor one revolution in the other direction
for(int i = 0; i < 1000; i++) {
GPIO_SetBits(GPIOC, STEP_PIN);
Delay(1000); // Adjust the delay for stepper speed
GPIO_ResetBits(GPIOC, STEP_PIN);
Delay(1000);
}
Delay(800000);
}
and this result after upload
Test stepper motor and limitswitch
and then add 2 limit switch to give maximum and minimum stepper movement,
add initialization for 2 limit switch in pin 8 and pin 9
#define LIMIT1_PIN GPIO_Pin_8
#define LIMIT2_PIN GPIO_Pin_9
add function gpio_config
GPIO_InitStructure.GPIO_Pin = LIMIT1_PIN | LIMIT2_PIN;
GPIO_InitStructure.GPIO_Direction = GPIO_Direction_IN;
GPIO_Init(GPIOC, &GPIO_InitStructure);
upload program for trial test limit switch and stepper
while (1) {
if (GPIO_ReadInputDataBit(GPIOC, LIMIT1_PIN) == Bit_RESET) {
printf("LIMIT1 Pressed\r\n");
GPIO_SetBits(GPIOC, DIR_PIN); // Set direction to CW
}
else if (GPIO_ReadInputDataBit(GPIOC, LIMIT2_PIN) == Bit_RESET) {
printf("LIMIT2 Pressed\r\n");
GPIO_ResetBits(GPIOC, DIR_PIN); // Set direction to CCW
}
// Step the motor
GPIO_SetBits(GPIOC, STEP_PIN);
Delay(1000);
GPIO_ResetBits(GPIOC, STEP_PIN);
Delay(1000);
}
return 0;
}
because we need wizfloat can controll with browser so, we can add 3 button in browser to controll it, add new variabel for CW and CCW movement
void Stepper_MoveCW(void);
void Stepper_MoveCCW(void);
add function stepper movement
volatile uint8_t stepper_state = 0; // 0: stopped, 1: CW, 2: CCW
/* Moves the stepper motor CW */
void Stepper_MoveCW(void)
{
GPIO_SetBits(GPIOC, DIR_PIN); // Set direction to CW
// Generate a step pulse
GPIO_SetBits(GPIOC, STEP_PIN);
delay(1); // Short delay for pulse width
GPIO_ResetBits(GPIOC, STEP_PIN);
delay(1); // Short delay for pulse spacing
}
/* Moves the stepper motor CCW */
void Stepper_MoveCCW(void)
{
GPIO_ResetBits(GPIOC, DIR_PIN); // Set direction to CCW
// Generate a step pulse
GPIO_SetBits(GPIOC, STEP_PIN);
delay(1); // Short delay for pulse width
GPIO_ResetBits(GPIOC, STEP_PIN);
delay(1); // Short delay for pulse spacing
}
and then call in webserver
int32_t WebServer(uint8_t sn, uint8_t* buf, uint16_t port)
{
uint8_t i;
uint8_t adcChannelOffset = 2;
int32_t ret;
uint16_t size = 0;
uint8_t destip[4];
uint16_t destport;
uint8_t adc_buf[128] = { '\0', };
switch (getSn_SR(sn))
{
case SOCK_ESTABLISHED:
if (getSn_IR(sn) & Sn_IR_CON) {
getSn_DIPR(sn, destip);
destport = getSn_DPORT(sn);
printf("%d:Connected - %d.%d.%d.%d : %d\r\n", sn, destip[0], destip[1], destip[2], destip[3], destport);
setSn_IR(sn, Sn_IR_CON);
}
if ((size = getSn_RX_RSR(sn)) > 0) {
if (size > DATA_BUF_SIZE) size = DATA_BUF_SIZE;
ret = recv(sn, buf, size);
if (ret <= 0) return ret;
printf("%s", buf);
// Check for button press
if (strstr((char*)buf, "GET /?led=on") != NULL) {
// Turn on LED (or GPIO)
GPIO_SetBits(GPIOC, GPIO_Pin_15);
} else if (strstr((char*)buf, "GET /?led=off") != NULL) {
// Turn off LED (or GPIO)
GPIO_ResetBits(GPIOC, GPIO_Pin_15);
} else if (strstr((char*)buf, "GET /?stepper=cw") != NULL) {
// Start moving stepper motor CW
stepper_state = 1;
} else if (strstr((char*)buf, "GET /?stepper=ccw") != NULL) {
// Start moving stepper motor CCW
stepper_state = 2;
} else if (strstr((char*)buf, "GET /?stepper=stop") != NULL) {
// Stop moving stepper motor
stepper_state = 0;
}
// Send HTML response
ret = send(sn, "HTTP/1.1 200 OK\r\n"
"Content-Type: text/html\r\n"
"Connection: close\r\n"
"\r\n"
"<!DOCTYPE HTML>\r\n"
"<html>\r\n"
"<body>\r\n"
"<h1>WIZnet Web Server</h1>\r\n"
"<p>Analog input values:</p>\r\n", sizeof("HTTP/1.1 200 OK\r\n"
"Content-Type: text/html\r\n"
"Connection: close\r\n"
"\r\n"
"<!DOCTYPE HTML>\r\n"
"<html>\r\n"
"<body>\r\n"
"<h1>WIZnet Web Server</h1>\r\n"
"<p>Analog input values:</p>\r\n") - 1);
if (ret < 0) {
close(sn);
return ret;
}
for (i = 0; i < 4; i++) {
ADC_Cmd(ENABLE);
if(i >= 2) adcChannelOffset = 4;
else if (i < 2) adcChannelOffset = 2;
ADC_ChannelConfig(i+adcChannelOffset);
ADC_StartOfConversion();
sprintf(adc_buf, "analog input %d is %d<br />\r\n", i+adcChannelOffset, ADC_GetConversionValue());
ret = send(sn, adc_buf, strlen(adc_buf));
if (ret < 0) {
close(sn);
return ret;
}
ADC_Cmd(DISABLE);
memset(adc_buf, '\0', 128);
}
// Add buttons to the HTML
ret = send(sn, "<br /><button onclick=\"location.href='/?led=on'\">Turn LED On</button>\r\n", strlen("<br /><button onclick=\"location.href='/?led=on'\">Turn LED On</button>\r\n"));
if (ret < 0) {
close(sn);
return ret;
}
ret = send(sn, "<button onclick=\"location.href='/?led=off'\">Turn LED Off</button>\r\n", strlen("<button onclick=\"location.href='/?led=off'\">Turn LED Off</button>\r\n"));
if (ret < 0) {
close(sn);
return ret;
}
ret = send(sn, "<br /><button onclick=\"location.href='/?stepper=cw'\">Move Stepper CW</button>\r\n", strlen("<br /><button onclick=\"location.href='/?stepper=cw'\">Move Stepper CW</button>\r\n"));
if (ret < 0) {
close(sn);
return ret;
}
ret = send(sn, "<button onclick=\"location.href='/?stepper=ccw'\">Move Stepper CCW</button>\r\n", strlen("<button onclick=\"location.href='/?stepper=ccw'\">Move Stepper CCW</button>\r\n"));
if (ret < 0) {
close(sn);
return ret;
}
ret = send(sn, "<button onclick=\"location.href='/?stepper=stop'\">Stop Stepper</button>\r\n", strlen("<button onclick=\"location.href='/?stepper=stop'\">Stop Stepper</button>\r\n"));
if (ret < 0) {
close(sn);
return ret;
}
ret = send(sn, "</body></html>\r\n", sizeof("</body></html>\r\n") - 1);
if (ret < 0) {
close(sn);
return ret;
}
disconnect(sn);
}
break;
case SOCK_CLOSE_WAIT:
if ((ret = disconnect(sn)) != SOCK_OK) return ret;
printf("%d:Socket Closed\r\n", sn);
break;
case SOCK_INIT:
printf("%d:Listen, Web server, port [%d]\r\n", sn, port);
if ((ret = listen(sn)) != SOCK_OK) return ret;
break;
case SOCK_CLOSED:
if ((ret = socket(sn, Sn_MR_TCP, port, 0x00)) != sn) return ret;
break;
default:
break;
}
// Check the stepper state and move accordingly
switch (stepper_state)
{
case 1:
Stepper_MoveCW();
break;
case 2:
Stepper_MoveCCW();
break;
default:
break;
}
return 1;
}
edit gui for display ground controller
ret = send(sn, "HTTP/1.1 200 OK\r\n"
"Content-Type: text/html\r\n"
"Connection: close\r\n"
"\r\n"
"<!DOCTYPE HTML>\r\n"
"<html>\r\n"
"<head>\r\n"
"<style>\r\n"
"body { font-family: Arial, sans-serif; background: linear-gradient(to right, #8e2de2, #4a00e0); display: flex; justify-content: center; align-items: center; height: 100vh; margin: 0; }\r\n"
".container { background-color: white; border-radius: 15px; padding: 30px; display: flex; box-shadow: 0 0 20px rgba(0, 0, 0, 0.1); }\r\n"
".left-section { margin-right: 20px; }\r\n"
".right-section { display: flex; flex-direction: column; justify-content: center; }\r\n"
"h1 { color: #333; margin-bottom: 20px; }\r\n"
".data { background-color: #f2f2f2; padding: 10px; border-radius: 10px; margin: 10px 0; display: inline-block; width: 100%; text-align: center; }\r\n"
".button { background-color: #4CAF50; color: white; padding: 15px; border: none; border-radius: 10px; cursor: pointer; margin: 10px 0; width: 100%; text-align: center; }\r\n"
".button:hover { background-color: #45a049; }\r\n"
"</style>\r\n"
"</head>\r\n"
"<body>\r\n"
"<div class='container'>\r\n"
"<div class='right-section'>\r\n"
"<h1>WIZFLOAT</h1>\r\n"
"<div class='data'><strong>Temperature</strong><p>30 C</p></div>\r\n"
"<div class='data'><strong>Depth</strong><p>1.2 Meters</p></div>\r\n"
"</body>\r\n"
"</html>\r\n", sizeof("HTTP/1.1 200 OK\r\n"
"Content-Type: text/html\r\n"
"Connection: close\r\n"
"\r\n"
"<!DOCTYPE HTML>\r\n"
"<html>\r\n"
"<head>\r\n"
"<style>\r\n"
"body { font-family: Arial, sans-serif; background: linear-gradient(to right, #8e2de2, #4a00e0); display: flex; justify-content: center; align-items: center; height: 100vh; margin: 0; }\r\n"
".container { background-color: white; border-radius: 15px; padding: 30px; display: flex; box-shadow: 0 0 20px rgba(0, 0, 0, 0.1); width:50%;}\r\n"
".left-section { margin-right: 20px; }\r\n"
".right-section { display: flex; flex-direction: column; justify-content: center; }\r\n"
"h1 { color: #333; margin-bottom: 20px; }\r\n"
".data { background-color: #f2f2f2; padding: 10px; border-radius: 10px; margin: 10px 0; display: inline-block; width: 100%; text-align: center; }\r\n"
".button { background-color: #4CAF50; color: white; padding: 15px; border: none; border-radius: 10px; cursor: pointer; margin: 10px 0; width: 100%; text-align: center; }\r\n"
".button:hover { background-color: #45a049; }\r\n"
"</style>\r\n"
"</head>\r\n"
"<body>\r\n"
"<div class='container'>\r\n"
"<div class='right-section'>\r\n"
"<h1>WIZFLOAT</h1>\r\n"
"<div class='data'><strong>Temperature</strong><p>30 C</p></div>\r\n"
"<div class='data'><strong>Depth</strong><p>1.2 Meters</p></div>\r\n"
"</body>\r\n"
"</html>\r\n") - 1);
this result for gui grond controller
after program run, then assemble in syrnge and test stepper motor and limitswitch in hardware
Final test Bifloats
GUI for Bifloats