Wireless pendant using ESP-NOW!

I designed and programmed a wireless remote controller for my portable MPCNC carver. After nearly a year of hacking, coding, soldering, and learning, this pendant is now working very well. But it is still in the prototype stage, as there are some more bells and whistles to add. It uses Espressif’s ESP-NOW wireless protocol, which is not WiFi or Bluetooth and does not need a router or internet connection. This wireless protocol has MANY useful features, as detailed in my YouTube video about the pendant: https://youtu.be/lYjtsSwlnhk

As always, I welcome any feedback, comments, suggestions or corrections!

00:00 Intro
00:12 Potter’s Portable Primo MPCNC
00:50 Inspirations for my pendant design
01:01 ESP-NOW intro
01:51 Knobs and buttons!!
02:30 My pendant’s functions, overview of its controls
03:03 Homing function demo
03:47 Fast jogging with the Rotary Optical Encoder
04:16 Joystick proportional control
04:59 Setting origin manually
05:10 Z-probing
06:21 Set origin to current Z
06:35 Step movement with pushbuttons
07:17 Move rapidly to Home and Park locations
07:45 Fine jogging with the ROE, speed comparison
10:53 Components used to build the wireless pendant
12:08 More about ESP-NOW wireless protocol
12:51 Receiver (ESP32) and Teensy 4.1 controller
14:00 Programming and software
15:11 Future improvements
16:01 Outro


That is really nice work. I have wanted to try using the espnow protocol for a while. You’re controller seems to fit your needs perfectly.

I am curious about the interface to the teensy. Is it sending gcode?


Thanks. Yes, the receiver ESP32 acts just like any sender, and uses G code. However, I have not implemented running a job from sd cards yet. It negotiates who is in control (IOsender or my pendant) using an “MPG” digital line that is part of grblHAL. It makes good use of the grbl Real-time commands, and keeps polling the Teensy for status updates.

My main goal is to get people to start using ESP-NOW more. It is 5 years ahead of anything else. I just LOVE it.


It looks a lot like Matter.

My biggest complaint is that it is so low level. Constructing packets up to 250B in size is fine for specific applications where you author both sides. But is there any standard for what goes into those 250B? It would be nice if (in the future) someone could buy any one of several pendants, connect them wirelessly to any one of several controllers, and they would all work together. Is there something I am missing?


As usual, I don’t think you are missing anything! Your vision sounds like a great one.

If Matter can take the best of what ESP-NOW is doing and move on from the nearly 50-year old Internet Protocol, that would be great. I believe that ESP-NOW (at the hardware/machine code level) is proprietary still, so Espressif would have to open-source it.

I don’t think it would be too hard to create a new standard for packet structure that allows interoperability for the CNC/pendant world. Maybe those of you who are younger and full of energy can pursue that :wink: Mine is just the first (as far as I know) ESP-NOW based pendant, so it is early days.

For the curious, here is what my packet structure looks like:

typedef struct packet_struct {  // Struct of data sent between Pendant and Receiver. 
// Max 250 bytes/transmission. Max rate is about 5ms per packet, round trip. 
// That's about 200 Hz * 250bytes = 50kB/s bandwidth for peer-peer ESP-NOW, which has confirmations. (Broadcast ESPNOW does not)
  // ROE
  bool X_ROEenabled = false; //Momentary button held down during jogging with ROE.
  bool Y_ROEenabled = false;
  bool Z_ROEenabled = false;
  int ROE_RotDir = 0;  // 1 = CW = positive change, 0= no movement; -1 = CCW = neg.
  int ROE_DeltaCounts = 0;
  uint16_t ROEmultiplier = 1; 
  // Joystick stuff
  bool JOYenabled = false; // True means the joystick enable button is being held down.
  int JoyX = 0; //Values range from -1000 to 1000
  int JoyY = 0; //Values range from -1000 to 1000
  bool MPGmode; // indicates the !state of the pin 12 on Receiver, Pin 41 on Teensy.
  // Buttons pulled strongly to ground when pressed; Signals flipped upon reading in Pendant so 1 == ON
  bool IncrementButton = 0;
  bool DecrementButton = 0;
  bool MenuButton = 0; // If I get tight for bytes in the ESP-NOW packet, I could send these as two or four bytes.
  int  MenuClicksCount = 0; // mechanical encoder with detents for navigating menus.
  bool Vacuum = 0;     // bool uses one byte each.
  bool SetXYto0 = 0;  
  bool Light = 0;
  bool ProbeZ = 0;
  bool GoTo00 = 0;
  bool HomeXYZ = 0;  
  bool SetZto0 = 0;
  bool Start = 0;
  bool Pause_Halt = 0;
  bool Reset = 0; // Does not use inverse logic.
  bool Spindle_ON = 0; // Not inverse logic. High when latched/pressed,
                       // because that made the switch's LED easy to light when pressed.
                       // Signal is on the N.C. line to ground, so pulled up weakly when pressed.
  bool Park = 0; //to park the spindle out of the way
  char MessageText[MSG_SIZE]; // Brings us very close to the 250 byte limit.
                              // For status reports from grbl. Regardless of how many chars are in the message, it sends the full size of the array. 
} packet_struct;

packet_struct ESPNOWpacket2send; // Create a structure variable of type packet_struct called ESPNOWpacket
packet_struct ReceivedESPNOWpacket; // Info sent to Pendant by Receiver, such as .MPGmode and .MessageText
packet_struct SENTpacket = ESPNOWpacket2send; // To detect changes.

I am wasting bytes by using an entire byte as a flag for some boolean variables, so it could be made smaller to fit more stuff in the packet, if needed. 250 bytes seemed plenty for my purposes, even with this inefficient way of coding booleans.


if you had the gcode generated on the dongle rather than on the receiver, then it would be universal because the cnc’s speak gcode and the radio transmit receive would just be sending packets of gcode. Then the issue is getting different radios to connect. Is that what @jeffeb3 is after?

There was a company called Jennic a few years back that came out with a 802.15.4 radio set that wasn’t zigbee, but it was on the 2.4Ghz band and it did something similar to this and it worked really well. They were then purchased by NXP and got folded into their line. ESPNOW sounds very similar to that. Cypress did a similar thing with their psoc chips used in mice. They called it PRoc. It is used on many wireless mice dongles you purchase. Each has a proprietary radio transmission set that is nonstandard and they all use 2.4GHz. I’m not seeing how this ESPNOW is much different except maybe more people have ESP32 devices and that might be the difference and then knowing how to parse the packet will be the key.

I believe that even if you had the receiver just receive and pass on g-code to the grbl core processor, you are still facing having to program both the pendant and receiver to speak to each other in the same language. There is a lot of stuff involved in that, such as packet acknowledgments, sending back status reports from grbl, and other things. You can read the Wiki on the gnea/grbl github where it talks about writing a sender/GUI to get an idea that this is a complex two-way conversation, which for a wireless sender, all have to go through both the receiver and the pendant.

As with the mouse and dongle system, you have to buy the two as a matched and paired set. I am all for the idea of creating an open standard that works as well as ESP-NOW. But until then, ESP-NOW has a LOT of great features: https://youtu.be/QmvMtgNs9r8

1 Like

I watched part of your video on the button features of the pendant in the original post and it is very impressive. I didn’t mention the fact that your pendant is truly awesome and I really like it. You made my point about the wireless mouse though. They are a paired set as would the pendant and the receiver have to be in order to communicate. any pendant would have to have an esp32NOW setup and within that any ESP32 they communicate with would need to have the correct firmware to receive the data, making them a matched pair.

1 Like


If every CNC pendant were to come with a USB dongle, like wireless mouses do, then I think we agree. That pair of mated devices speaks grbl, which is a good, open universal standard. It doesn’t make much difference whether that g code is being devised/calculated in the pendant or dongle (what I call Receiver). I chose to put calculations in the receiver, based on subtle and not very important factors.

My main point was that ESP-NOW is a really useful wireless protocol. Do you think the others you mentioned are better? Are they open source at the hardware level? I would like to learn more, if so. Being closed and only on Espessif devices are the only downsides of ESP-NOW I can see.

Here is a good overview: https://youtu.be/QmvMtgNs9r8

Let me know if you have more comments, ideas, questions or suggestions…It is still a work in progress.


other wireless protocols: you would need a matching transmit/recieve chip pair unless you go with wifi or bluetooth. I was going to use a rpi zero for my dongle and send all the data as text over a socket connection with wifi. I also used a wii remote over bluetooth, but in each case it required custom software, so the issue/problem/solution is similar in each case. The receiving program will need to be adapted to accept the input.

A google search indicates that many of the available pendants communicate straight grbl (I’m assuming gcode) over a serial connection. Connecting the dots from serial input and wireless input might be the integration key. for mass adoption. I’d like to have one, but I don’t use esp on my system…

You bring up an interesting point: There are some ESP32-based CNC controllers out there, and if you are using one of them, then using ESP-NOW for a pendant (instead of Wifi or Bluetooth or a wired USB) makes even more sense, as it would get rid of what I call the Receiver ESP32 (controller and Receiver are one).

My pendant and ESP-NOW got a brief writeup in Hackaday!


The guy that made my board uses two ESP32 for his wireless controller with Estlcam as well. I am not sure about him using the ESP-NOW technology though.

Can you put a link to that board here?

Sure: CNC Handrad - Funk - Display - ESP32 - OPEN-CNC-Shield 2 - Automatische Kalibrierung - YouTube It’s German though. You can see how it works and his software in this video: OPEN-CNC-Shield 2 - ESP32 Firmware aufspielen/konfigurieren und Autosquaring einstellen - YouTube

Here’s the wiki for the board: https://docs.timos-werkstatt.de/open-cnc-shield-2/mainboard


How did I miss this. I even watched the video yesterday. Didn’t see the article or this post.



My goodness, the comments on both places are ridiculous…

I think it’s fantastic and it actually looks super fun. If you need sub fempto-second reaction times, game pad holographic format, 295,494 bit encryption, and someone to do everything for you while you watch and critique…build your own.


Love how the pendant shows off wicked fast precise motion.

Ideally the article author would have emphasized the pendant intentionally has an eclectic design to help inspire and educate the kids/others that Steve demonstrates to across Ireland. With that perspective, existing and future readers will likely add more constructive comments.


I found my way to the source code and it does seem to make use of ESP-NOW for at least some of its functions, though I think he said that if you want to use the MPG (jogwheel) you use a cable. This is a beautiful pendant (though a lot fewer features than mine). @Tokoloshe How do you like it? Have you found it to be as functional/responsive as mine in terms of joystick or MPG jogging?

I never really look at comments, so I went back, it is wild the stuff people complain about. Great Job. So many things you can do with it. I can guarantee I will never be savvy enough to implement it, but great job!