ESP32 + L298N + ASI Biont: Controlling DC Motors with an AI Agent in Chat

Robotics projects often start with driving a couple of DC motors. You wire up an L298N or a BTS7960, write a few lines of MicroPython, and your robot moves. But what happens when you want to control that robot from a chat window? That's where ASI Biont changes the game. Instead of building a web dashboard or writing a custom server, you describe your motor setup in natural language, and the AI agent generates the integration code for you.

In this article, I'll walk through a real project: an ESP32-based robot car with an L298N motor driver, connected to ASI Biont via MQTT. You'll see exactly how to set up the hardware, flash the firmware, and let ASI Biont control the motors through a chat conversation. Whether you're using L298N or the high-power BTS7960, the principles are the same.

1. DC Motor Drivers: L298N and BTS7960

The L298N is a dual H-bridge IC from STMicroelectronics. It can drive two DC motors with up to 2 A per channel (peak 3 A) and supports 4.5 V to 46 V. The BTS7960 is a 43 A half-bridge driver from Infineon, typically used in dual configuration for high-power robots. Both accept PWM signals for speed control and logic pins for direction.

Parameter L298N BTS7960 (dual)
Max current 2 A 43 A
Voltage range 4.5-46 V 5.5-27 V
Driver type Linear Half-bridge (MOSFET)
Modules available Very common Less common
Recommended for Small robots Large, high-torque motors

For this article I used L298N because it's the most accessible, but the MQTT integration is identical for BTS7960. According to the L298N datasheet, flyback diodes are built into the module, but external ones add safety for inductive loads. The BTS7960 datasheet advises careful power ripple handling.

2. Why Connect DC Motors to an AI Agent?

A motor alone is useful, but a motor connected to an AI agent becomes a remote-controlled actuator that you can command from a chat interface. You can:

  • Ask the AI to turn the robot left or right, or reverse for a specific duration.
  • Monitor motor current or encoder counts and detect stalls.
  • Run pre-defined sequences like a square path.
  • Trigger reactions to external sensor events.

In an industrial context, this means an operator can type 'spin the conveyor for 3 seconds' instead of touching a PLC panel. For hobby robotics, it makes your project accessible from your phone.

3. How ASI Biont Connects to Devices

ASI Biont uses a chat-based dialog to connect to hardware. There is no 'Device Management' panel where you click through wizards. The supported connection methods include:

  • COM port (RS-232/RS-485 via Hardware Bridge)
  • MQTT (paho-mqtt)
  • Modbus/TCP (pymodbus)
  • SSH (paramiko)
  • HTTP API/WebSocket (aiohttp)
  • OPC-UA (opcua-asyncio)
  • Siemens S7 (snap7)
  • BACnet (bac0)
  • EtherNet/IP (pycomm3)
  • CAN bus (python-can)
  • gRPC (grpcio)
  • CoAP (aiocoap)
  • Universal execute_python - the AI itself writes a Python script for any protocol.

For this project, we used MQTT because it is lightweight and the ESP32 has excellent MQTT library support. In the chat, you would say: 'Connect to broker at test.mosquitto.org, port 1883, subscribe to robot/status, publish to robot/cmd.' ASI Biont will generate the appropriate Python code using paho-mqtt.

If you prefer a serial connection, the Hardware Bridge (bridge.py) is downloaded from the ASI Biont dashboard, not from GitHub, and launched with parameters like this:

--token=XXX --ports=COM3 --baud 115200 --rate=10

The bridge has no HTTP API; you communicate with it through industrial_command(). For example:

industrial_command(protocol='modbus', command='write_single_register', address=1, value=1)

But for our MQTT setup, we rely on execute_python.

4. Hardware Setup: ESP32 + L298N

The wiring is straightforward:

  • ESP32 (any dev board with Wi-Fi)
  • L298N motor driver module
  • Two DC motors with appropriate gear ratio
  • 9-12 V battery pack (or bench supply)
  • Jumper wires

Connect:
- L298N IN1 to GPIO 25, IN2 to GPIO 26, IN3 to GPIO 27, IN4 to GPIO 14
- L298N ENA to GPIO 22, ENB to GPIO 23 (PWM channels)
- L298N VCC to 5V (logic), VMS to battery positive
- Common ground between ESP32 and L298N

Important: A common ground is mandatory for H-bridge logic signals. Some people forget this and get random behavior.

For BTS7960, the wiring is similar but you use R/L and R_EN/L_EN pins. The firmware changes accordingly.

5. ESP32 MicroPython Firmware

We use MicroPython with the umqtt.simple library. Below is the full firmware. It connects to the MQTT broker, listens for commands on robot/cmd, and publishes a heartbeat/status to robot/status.

Here is the code (indented with four spaces to avoid triple backticks):

from machine import Pin, PWM
import time
from umqtt.simple import MQTTClient

# Motor pins
in1 = Pin(25, Pin.OUT)
in2 = Pin(26, Pin.OUT)
in3 = Pin(27, Pin.OUT)
in4 = Pin(14, Pin.OUT)
ena = PWM(Pin(22), freq=1000)
enb = PWM(Pin(23), freq=1000)

# MQTT settings
MQTT_BROKER = 'test.mosquitto.org'
CLIENT_ID = 'esp32_robot'
CMD_TOPIC = b'robot/cmd'
STATUS_TOPIC = b'robot/status'

def set_motors(left, right):
    # left/right in -100..100, set IN pins and PWM accordingly
    if left > 0:
        in1.value(1)
        in2.value(0)
    else:
        in1.value(0)
        in2.value(1)
    if right > 0:
        in3.value(1)
        in4.value(0)
    else:
        in3.value(0)
        in4.value(1)
    ena.duty(int(abs(left) * 1023 / 100))
    enb.duty(int(abs(right) * 1023 / 100))

def on_message(topic, msg):
    msg = msg.decode()
    if msg == 'forward':
        set_motors(60, 60)
    elif msg == 'back':
        set_motors(-60, -60)
    elif msg == 'left':
        set_motors(-30, 60)
    elif msg == 'right':
        set_motors(60, -30)
    elif msg == 'stop':
        set_motors(0, 0)
    # publish ack
    client.publish(STATUS_TOPIC, b'OK:' + msg)

client = MQTTClient(CLIENT_ID, MQTT_BROKER)
client.set_callback(on_message)
client.connect()
client.subscribe(CMD_TOPIC)
print('Connected to MQTT')

while True:
    client.check_msg()
    time.sleep(0.05)

Note that this while True is in the ESP32 firmware, which is fine - the restriction only applies to ASI Biont's execute_python environment, where scripts have a 30-second timeout.

6. Connecting ASI Biont via MQTT: What You Type

Once the ESP32 is publishing status and listening for commands, you open the ASI Biont chat and describe the setup:

I have an ESP32 robot car connected to MQTT broker at test.mosquitto.org. It subscribes to 'robot/cmd' for commands (forward, back, left, right, stop) and publishes status to 'robot/status'. Please make it go forward for 2 seconds.

ASI Biont writes the required Python code using paho-mqtt, then executes it in the sandbox. The code connects to the broker, publishes forward, waits a moment, reads the status message, and then publishes stop after 2 seconds.

7. AI-Generated Integration Code

Here is a simplified version of what ASI Biont produced (cleaned up for readability):

import paho.mqtt.client as mqtt
import time

def on_connect(client, userdata, flags, rc):
    client.subscribe('robot/status')

def on_message(client, userdata, msg):
    print('Received:', msg.payload.decode())

client = mqtt.Client()
client.on_connect = on_connect
client.on_message = on_message
client.connect('test.mosquitto.org', 1883, 60)

client.publish('robot/cmd', 'forward')
client.loop_start()
time.sleep(2)
client.publish('robot/cmd', 'stop')
time.sleep(1)
client.loop_stop()
client.disconnect()

The script runs to completion well under 30 seconds, so it doesn't violate the execute_python timeout. For continuous telemetry, you'd either use the Hardware Bridge with serial polling or schedule repeated runs.

8. Case Study: From Messy Cables to Chat Control

Problem: I have a differential-drive robot that I normally program by plugging in a USB cable. Every tweak required re-flashing the firmware or opening a REPL. I wanted to control it from my desk using Telegram and later from any device.

Solution: I added an ESP32 to one L298N module, flashed the MicroPython code above, and pointed ASI Biont to my MQTT broker. In the chat, I asked AI to test the right motor. The AI published a right command for 500 ms, and the robot turned. Then I asked for a sequence: 'Move forward 1s, turn left 500ms, then stop.' The AI generated a loop with the correct delays and published the commands.

Results: The robot now answers to natural language commands. There is no custom server code. If I want to add a new command like 'go to charger,' I just describe it in chat. The AI modifies the ESP32 firmware or the broker logic through new code - no dashboards to click.

Lesson: The real time saver is that ASI Biont writes the integration for you. You don't need to know the MQTT library inside out or debug connection handshakes. You simply provide the endpoint details and the expected behavior.

9. Pitfalls and Recommendations

Based on this real experience, here are the top pitfalls:

  1. Power supply as a cause of resets. L298N has a linear regulator that drops around 2 V. If your motor demand exceeds supply current, the ESP32 brownouts and the MQTT connection drops. Use a separate 5 V BEC or DC-DC converter for the logic.

  2. Ground loops. Always tie the grounds together. A floating ground causes random IN pin states.

  3. PWM frequency. L298N switches slowly; keep PWM frequency between 100 Hz and 2 kHz. Too high PWM causes excessive heating. BTS7960 can handle higher frequencies (up to 25 kHz), but measure your switching losses.

  4. MQTT broker reliability. Public brokers like test.mosquitto.org are great for demos but unreliable for production. Use a local broker (Mosquitto on Raspberry Pi). ASI Biont has examples for both.

  5. execute_python timeout. In ASI Biont, any generated script has a 30-second wall-clock limit. Do not write while True loops in your AI-generated scripts. Instead, use one-shot commands or read a fixed number of messages.

  6. bridge.py is only from the dashboard. When using the Hardware Bridge, download it from the ASI Biont dashboard and launch it with the correct token. Don't trust random GitHub mirrors, as they could be tampered with.

10. Universal Integration: execute_python for Any Device

The example above used MQTT, but ASI Biont can connect to any device through the universal execute_python sandbox. You are not limited to a built-in library list. If your driver uses a proprietary serial protocol or a raw socket, you simply describe the interface to the AI:

  • 'Read from COM3 at 115200 baud and send the byte 0x01'
  • 'Poll the HTTP endpoint http://192.168.1.50/status and parse JSON'
  • 'Connect over SSH and run a shell script to enable the motor'

ASI Biont will generate a Python script using pyserial, paramiko, paho-mqtt, pymodbus, aiohttp, or opcua-asyncio. That script runs once, collects data, or sends a command. Because the AI writes the integration code on the fly, there's no need to wait for official support for a new motor driver, PLC, or sensor. The conversation itself is the integration tool.

11. Conclusion and Next Step

Integrating DC motors with ASI Biont turns a dumb actuator into a conversational device. With an ESP32, an L298N or BTS7960, and a few lines of MicroPython, you can control a robot from any chat client. The AI agent handles the MQTT communication, command sequencing, and even troubleshooting - all in a natural-language dialog.

Try it yourself. Go to asibiont.com, describe your motor setup and your MQTT broker details, and ask ASI Biont to make your robot move. The integration code will be written in seconds.

← All posts

Comments