Help required for m...
 
Notifications
Clear all

Help required for model railway project

276 Posts
10 Users
13 Reactions
5,305 Views
(@davee)
Member
Joined: 3 years ago
Posts: 1868
 

Hi @imillard,

  I have no personal experience of what you are attempting, but in addition to the starting point provided by @robotbuilder, and in line with @byron's comment, I note:

There is a servo library labelled with ESP8266 documented in the Arduino docs:

https://docs.arduino.cc/libraries/esp8266_isr_servo/#Releases

I haven't attempted to compare with the ESP32Servo library your code listing refers to, so it may not be compatible. However, it is at least an ESP8266 library ... the ESP8266 and ESP32 range are quite different chips, and hence tend to need different software!

In addition, all of the GPIO number lines referred to in your software (for a start, see roughly lines 7-12 in your listing) need to match the GPIO lines actually connected between the Wemos board and your hardware ...

For example, the following is snipped from the iotstarters website discussed previously:

image

which shows that GPIOs 18 and 19 (that are shown in your code listing), do not exist on the Wemos board. 

Although 'try it and see it' is often the appropriate pragmatic approach, you may also find it helpful to check that each of the GPIO ports you have connected are capable of doing the specific task. The ESP8266 has only a small number of GPIO pins, and there are quite a lot of rules as to what each pin can and can't do. You may find something helpful on the relevant sections of:

https://randomnerdtutorials.com/esp8266-pinout-reference-gpios/

---------

Sorry, this is more of an untested, cryptic clue, than a tested answer, plus some of the above referenced material is quite complex and confusing, even for 'more experienced' individuals. So don't panic, but perhaps you can try making the appropriate edits and report back.

Best wishes and good luck, Dave


   
ReplyQuote
Ron
 Ron
(@zander)
Father of a miniature Wookie
Joined: 4 years ago
Posts: 7666
 

@byron @imillard No, I have not used ESP-NOW for any serious work, but I have a fairly rich background in comms from my former day job. The only quibble I have with what Byron said is that the message itself should be acknowledged especially (or maybe only) if it is a 'take action' type msg. Of course after the action a msg the other way to confirm is standard procedure.

Broadcast msgs should be limited to non-critical things. I would go further and add a msg id that triggers specific logic in the receiver, and perhaps a msg seq # for non-broadcast types. Just thinking out loud, I don't know enough about the RR system to get more specific.

Best,

Ron (@zander)

I think I will try to dream up a project to use ESP-NOW around the apartment. If anyone has some thoughts, feel free to post or direct message me.

First computer 1959. Retired from my own computer company 2004.
Hardware - Expert in 1401, and 360, fairly knowledge in PC plus numerous MPU's and MCU's
Major Languages - Machine language, 360 Macro Assembler, Intel Assembler, PL/I and PL1, Pascal, Basic, C plus numerous job control and scripting languages.
My personal scorecard is now 1 PC hardware fix (circa 1982), 1 open source fix (at age 82), and 2 zero day bugs in a major OS.


   
ReplyQuote
byron
(@byron)
No Title
Joined: 5 years ago
Posts: 1179
 

Posted by: @zander

The only quibble I have with what Byron said is that the message itself should be acknowledged

I don't think I implied that, I was just indicating what the ESP-NOW libraries automatically do.  No receipt on a broadcast message, but an automatic receipt if the transmission is to a nominated mac address.

Its always a good practice to send a confirmation message concerning an action being completed if the sent message was to trigger an action.  Complete agreement I think. 😀 

If @imillard was not wishing to pursue learning code (but he confirms he does wish to take his coding abilities further 👍), only then a broadcast may have been the answer in this particular scenario.  E.g. send a broadcast signify a 'lock' should occur, and those other ESP boards reads and interprets the message as being for them, performs a lock function, and then perhaps turns on a Red LED.   When a staff is withdrawn, meaning all boards should perform a lock function, a beady eye would check that nothing was amis by checking all had their Red LED's glowing nicely.   Taking this one step further the code could check that all boards broadcast a 'function complete' message, and if messages from all are not received, then proceed to make an incredibly annoying buzzer sound at a high decibel level.

However, as @imillard indicated he was up for getting a bit stuck in with some more learning, especially for some other future projects on his model railway, I thought I had better elucidate a bit more on the difference of a 'broadcast' ESP-NOW message, and one sent to a specific mac address.   And to make it clear, if it was for my project, then I would not be considering the broadcast option.

As for an apartment based project, if I can think of anything then I will make a separate post.  However I feel that any apartment based comms project using ESP-NOW would be contrived as you surely have wifi available.  My foray into ESP-NOW was to use it in a place where wifi did not reach (currently).   And maybe that is also the type of project you may find it useful for.  ESP-NOW seems to have quit a long range so maybe its useful to connect to your veggie plot or an outside weather station etc.

And a final point for @imillard.  ESP-NOW is good, but so is wifi.  All the ESP boards work with wifi.  I would think its quite easy to get a cheapo wifi router thats permanently situated with your model railway set up (and transportable with said model if is moved to exhibitions etc.)  This would mean you have a wider range of microcontroller boards to pick from and communication would also work with small computers like the raspberry pi or a small widows PC etc. that you may eventually program for a full fat railway control feature.  (some scrolling departure screens, realistic 'control room' track situation displays etc. etc.)  Ha ha, getting a bit carried away I fear. 😎 

 

This post was modified 1 month ago by byron

   
ReplyQuote
Ron
 Ron
(@zander)
Father of a miniature Wookie
Joined: 4 years ago
Posts: 7666
 

@byron Correct, you did not, my poor interpretation.

As far as range, the garden is too far away (real esp-now is closer to 220m) My Lora gear almost reaches. The problem is there are two apartments in the way and I am on the wrong side so I have 7 concrete walls to traverse.

I do have WiFi but it is that WiFi 6 which has now taken over 192.168.4.1. I thought that was not allowed. I could maybe use my own router but that is the least of my problems.

I am currently working with 4 Doctors and there are I believe connections between my health problems but not every Dr has all the information. I am trying to educate them but it is almost impossible to get a hold of them except by visit and I am now scheduled a month out at least.

Once I get the docs all pulling together, I still need ideas.

Fortunatly only the good die young so I have a long way to go.

Best,

Ron (@zander)

First computer 1959. Retired from my own computer company 2004.
Hardware - Expert in 1401, and 360, fairly knowledge in PC plus numerous MPU's and MCU's
Major Languages - Machine language, 360 Macro Assembler, Intel Assembler, PL/I and PL1, Pascal, Basic, C plus numerous job control and scripting languages.
My personal scorecard is now 1 PC hardware fix (circa 1982), 1 open source fix (at age 82), and 2 zero day bugs in a major OS.


   
ReplyQuote
robotBuilder
(@robotbuilder)
Member
Joined: 5 years ago
Posts: 2221
 

@imillard 

I probably should have just bought more of the same ESP32 boards, but was chasing something with a smaller footprint and a bit cheaper, and I obviously was unaware of the coding differences.

As far as I can see you probably only have to change the GPIO pins used and the servo library.

This is an example designed to run on ESP8266 platform using two servos signal wires are attached to D7 and D8

https://github.com/khoih-prog/ESP8266_ISR_Servo/blob/master/examples/ISR_MultiServos/ISR_MultiServos.ino

================================================================

I haven't had time to check out the @byron version which looks interesting. I don't use Python in my own projects and have only dabbled in it to get some idea of how it differs from all the other languages I have also dabbled in 🙂

My background is purely as a hobby programmer who feels most comfortable at the lowest level. In my hey day it was mostly the BASIC language and Assembler on the old home computers (z80, c64, Amiga and eventually TurboC++ on the MSDOS PC). 

I will have another look at the broadcast mode but I only have two esp32s and don't actually use them at this stage in my Arduino project (robot) although I can see how powerful they are and useful for the internet of things.

=================================================================

How I look at any programming problem is to start at a high level description.
The idea is that you are understanding the program at different levels.
You may or may not actually understand how someone else's particular module works such as those in the ESP-NOW and Servo includes, the important thing is you know what is required what it does and how to use it.

You only need to understand the inner workings of a module if you are writing it yourself although that module may itself use other modules that someone else has written.

Your program is very simple in pseudo code.

IF STAFF_MOVED_LEFT THEN LOCK_DRUM() AND SEND_MESSAGE("LOCK")
IF STAFF MOVED_RIGHT THEN UNLOCK_DRUM() AND SEND_MESSAGE("UNLOCK")

IF RECEIVED_MESSAGE = "LOCK" THEN LOCK_DRUM()
IF RECEUVED MESSAGE = "UNLOCK" THEN UNLOCK DRUM

You then have to flesh it out in a computer language of choice in this case Arduino C++.

if (digitalRead(BTN1) == LOW){
  lockDrum();
  sendMessage("lock");
}

if (digitalRead(BTN2) == LOW){
  unlockDrum();
  sendMessage("unlock");
}

if (receivedMessage() == "lock"{
  lockDrum();
}

if (receivedMessage() == "unlock"{
  unlockDrum();
}

Now you have to write the functions to carry out the actions,
lockDrum();
unlockDrum();
sendMessage(msg);
msg = receiveMessage();

Those functions include other functions that are written by others to control a servo and send/receive messages.

The sendMessage and receiveMessage could be left unchanged if you say implemented another kind of connections such as a wire connection, IR connection, audio or some other wireless connection such as using the NRF24L01 module I used to connect two Arduino boards, all you would change is the code in those functions. The main code would be unchanged.

Those functions are found in the servo and esp-now includes.

The format required by ESP-NOW to send and receive messages is a group of variables which in C++ is defined in a block of code called a STRUCT which is given a name (label). You can use that label to create and name an actual implementation of those structs and the name can be passed to, or received from, a function that uses the data in that defined struct. So in this case one is named incoming to receive data and the other is named outgoing to send data. You fill in the values of the outgoing and receive values in the incoming.

// define a struct called metData
typedef struct metData {
char msg[32];
int command; // 1 = lock, 2 = unlock
} metData;

// now use that definition to create two blocks of variables with different names.

// Create a metData struct called outgoing to hold outgoing readings
metData outgoing;

// Create a metData struct called incoming to hold incoming readings
metData incoming;

All this sending and receiving is done by the functions in ESP-NOW you only need to know how to set them up and use them.

 


   
ReplyQuote
imillard
(@imillard)
Member
Joined: 3 months ago
Posts: 86
Topic starter  

Hi all,

Many thanks for all your recent replies, however I think the D1 mini ESP8266 boards may not be the right board for my project.  I have been looking at the pinouts and I just don't think I have the correct GPIOs to drive my two servos and and to use the momentary switch, for which I believe I need pullup resistors on two GPIOs as per @robotbuilder's code.  I couldn't confirm if these boards have those.  Happy for someone to correct me here.

Plus I'm thinking I'm so out of my depth here with getting my head around the programming language to be able to work out what's required to modify the code for use with ESP8266.

So, my next step is to get more of the ESP32-C3-DEVKITC-02 and continue with those.  At least I know I can upload the known working code, and later I can work on trialling the ESP-NOW Broadcast feature to use for the third staff machine.

This may come across as me giving up on the 'learning to program' I said I would be happy to do, but at the moment, I just don't have the time to do that right now.

Thanks again for everyone's assistance and input with this project. If someone feels inclined to write the code to operate three machines, please feel free! 😀 

Cheers,

Ian

Ian Millard
Port Macquarie, NSW, Australia
ESP32/Arduino etc novice


   
ReplyQuote
robotBuilder
(@robotbuilder)
Member
Joined: 5 years ago
Posts: 2221
 

   
ReplyQuote
robotBuilder
(@robotbuilder)
Member
Joined: 5 years ago
Posts: 2221
 

There seems to be some glitch. The above post is blank after I save it. However if I choose edit the contents reappear but it doesn't appear after being saved and selected. Text seems to work as here but when I add an image and code it doesn't work just leaves it blank.

I wrote in it that when you get another board I will try and modify Bill's code to your requirements.

I modified Bill's code to get it to compile.

    //esp_now_register_recv_cb(receiveCallback);
    esp_now_register_recv_cb(esp_now_recv_cb_t(receiveCallback));
 

   
ReplyQuote
robotBuilder
(@robotbuilder)
Member
Joined: 5 years ago
Posts: 2221
 

@imillard 

The glitch is still there I can't add code or attach images!!!???

It was easier than I thought but I will have to just give the code in text.

Copy the code to your two esp32 boards and it will work the same as the peer to peer code.

It should also work if you copy the code below to three identical boards.

 

/*
  ESP-NOW Multi Unit Demo
  esp-now-multi.ino
  Broadcasts control messages to all devices in network
  Load script on multiple devices

  DroneBot Workshop 2022

  MODIFIED BY robotBuilder

*/

// Include Libraries
#include <WiFi.h>
#include <esp_now.h>

// ====    MET INPUTS   ===

#include <ESP32Servo.h>

Servo lockServo;
Servo galvoServo;
int lockServoPin = 18;  // GPIO 18
int galvoServoPin = 19;  // GPIO 19 IN USE SIGNAL
#define BTN1  0 // GPIO 0
#define BTN2  2 // GPIO 2
#define LED1  21  // GPIO 21

int locked = 0;  // state of lock

// ===== ===================
//  FUNCTIONS
//===========================

 // DRUM FUNCTIONS
void lockDrum(){
    lockServo.write(75);
    galvoServo.write(45);
    digitalWrite(LED1,HIGH);
}

void unlockDrum(){
    lockServo.write(0);
    galvoServo.write(0);
    digitalWrite(LED1,LOW);
}

//==========================
void formatMacAddress(const uint8_t *macAddr, char *buffer, int maxLength)
// Formats MAC Address
{
  snprintf(buffer, maxLength, "%02x:%02x:%02x:%02x:%02x:%02x", macAddr[0], macAddr[1], macAddr[2], macAddr[3], macAddr[4], macAddr[5]);
}
void receiveCallback(const uint8_t *macAddr, const uint8_t *data, int dataLen)
// Called when data is received
{
  // Only allow a maximum of 250 characters in the message + a null terminating byte
  char buffer[ESP_NOW_MAX_DATA_LEN + 1];
  int msgLen = min(ESP_NOW_MAX_DATA_LEN, dataLen);
  strncpy(buffer, (const char *)data, msgLen);

  // Make sure we are null terminated
  buffer[msgLen] = 0;

  // Format the MAC address
  char macStr[18];
  formatMacAddress(macAddr, macStr, 18);

  // Send Debug log message to the serial port
  Serial.printf("Received message from: %s - %s\n", macStr, buffer);
  // Check switch status
  if (strcmp("lock", buffer) == 0)
  {
    lockDrum();
  }

  if (strcmp("unlock",buffer) == 0)
  {
    unlockDrum();
  }
}
void sentCallback(const uint8_t *macAddr, esp_now_send_status_t status)
// Called when data is sent
{
  char macStr[18];
  formatMacAddress(macAddr, macStr, 18);
  Serial.print("Last Packet Sent to: ");
  Serial.println(macStr);
  Serial.print("Last Packet Send Status: ");
  Serial.println(status == ESP_NOW_SEND_SUCCESS ? "Delivery Success" : "Delivery Fail");
}

void broadcast(const String &message)
// Emulates a broadcast
{
  // Broadcast a message to every device in range
  uint8_t broadcastAddress[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
  esp_now_peer_info_t peerInfo = {};
  memcpy(&peerInfo.peer_addr, broadcastAddress, 6);
  if (!esp_now_is_peer_exist(broadcastAddress))
  {
    esp_now_add_peer(&peerInfo);
  }
  // Send message
  esp_err_t result = esp_now_send(broadcastAddress, (const uint8_t *)message.c_str(), message.length());

  // Print results to serial monitor
  if (result == ESP_OK)
  {
    Serial.println("Broadcast message success");
  }
  else if (result == ESP_ERR_ESPNOW_NOT_INIT)
  {
    Serial.println("ESP-NOW not Init.");
  }
  else if (result == ESP_ERR_ESPNOW_ARG)
  {
    Serial.println("Invalid Argument");
  }
  else if (result == ESP_ERR_ESPNOW_INTERNAL)
  {
    Serial.println("Internal Error");
  }
  else if (result == ESP_ERR_ESPNOW_NO_MEM)
  {
    Serial.println("ESP_ERR_ESPNOW_NO_MEM");
  }
  else if (result == ESP_ERR_ESPNOW_NOT_FOUND)
  {
    Serial.println("Peer not found.");
  }
  else
  {
    Serial.println("Unknown error");
  }
}

void setup()
{

  // Set up Serial Monitor
  Serial.begin(115200);
  delay(1000);

  // Set ESP32 in STA mode to begin with
  WiFi.mode(WIFI_STA);
  Serial.println("ESP-NOW Broadcast Demo");

  // Print MAC address
  Serial.print("MAC Address: ");
  Serial.println(WiFi.macAddress());

  // Disconnect from WiFi
  WiFi.disconnect();

  // Initialize ESP-NOW
  if (esp_now_init() == ESP_OK)
  {
    Serial.println("ESP-NOW Init Success");
    //esp_now_register_recv_cb(receiveCallback);
    esp_now_register_recv_cb(esp_now_recv_cb_t(receiveCallback));
    esp_now_register_send_cb(sentCallback);
  }
  else
  {
    Serial.println("ESP-NOW Init Failed");
    delay(3000);
    ESP.restart();
  }

  // ======   MET SETUP =====
  pinMode(BTN1,INPUT_PULLUP); //configure pin as input with pullup enabled
  pinMode(BTN2,INPUT_PULLUP);
  pinMode(LED1,OUTPUT);

  lockServo.attach(lockServoPin);
  lockServo.write(0);  // 0 to 170 degrees
  galvoServo.attach(galvoServoPin);
  galvoServo.write(0);
  //==========================

}

void loop()
{
  // Send a message to all devices

  // send lock drum if BTN1 pressed
  if (digitalRead(BTN1) == LOW){
    broadcast("lock");
    lockDrum();
  }

  // send unlock drum if BTN2 pressed
  if (digitalRead(BTN2) == LOW){
    broadcast("unlock");
    unlockDrum();
  }
   
  delay(500);
}
 

   
ReplyQuote
imillard
(@imillard)
Member
Joined: 3 months ago
Posts: 86
Topic starter  

@robotbuilder

Thanks John.

So, from what I can see, for a three machine setup, there's no need to specify individual MAC addresses, just load the above code on all three boards.

Would it affect other boards running the peer to peer code for each pair of machines?  I would assume not, as there are unique MAC addresses specified in the peer to peer code.

When I get some other ESP32 boards, I'll trial your code and report back.

Many thanks.

Ian

Ian Millard
Port Macquarie, NSW, Australia
ESP32/Arduino etc novice


   
ReplyQuote
robotBuilder
(@robotbuilder)
Member
Joined: 5 years ago
Posts: 2221
 

@imillard 

I tested it on just two boards no need in your application for peer to peer with MAC addresses.

 


   
ReplyQuote
imillard
(@imillard)
Member
Joined: 3 months ago
Posts: 86
Topic starter  

Quick question to anyone.

I've been looking at the ESP32-C3-DevKitM-1 board as an alternative to the C3-DevKitC-02 I already have, as it is half the price.

As can be noted from @robotbuilder's code above and previously posted, my switch is connected to GPIO 0 & GPIO 2 and he has enabled the (what I presume) internal pullup on each.

What I can't work out is are there equivalent GPIOs on the C3-DevKitM that are the same as the C3-DevKitC, or do most GPIOs on both boards have internal pullups that can be enabled through code.

So, what I want to know is, would the C3-DevKitM board be OK to use for my two servos and two button (switch) inputs.

I've been going through the datasheets on both boards but finding it hard to confirm.

Cheers,

Ian

image
image

 

Ian Millard
Port Macquarie, NSW, Australia
ESP32/Arduino etc novice


   
ReplyQuote
robotBuilder
(@robotbuilder)
Member
Joined: 5 years ago
Posts: 2221
 

@imillard 

Although I can't give you a definitive answer to your question I suspect that GPIO 0 is not a good choice.

Maybe change the pin numbers in the code and in the hardware.

This gives you the ok pins and other details.

https://randomnerdtutorials.com/esp32-pinout-reference-gpios/

 


   
AndyD reacted
ReplyQuote
Ron
 Ron
(@zander)
Father of a miniature Wookie
Joined: 4 years ago
Posts: 7666
 

@imillard Do not use GPIO0, it is reserved. GPIOany is the same on all ESP32's other than when the pins are physically not there as the esp32 can be bought in 30 pins and up to 38 pins. For your project 30 is plenty., and I think they all have internal pullups. I would recommend you NOT use any Series 3 board as the S3 API is undergoing changes. The cheapest esp32 will work fine for you, the DOIT is a popular choice.

On Aliexpress I quickly found $0.97 boards, I bet with some search time that can be bettered if need be.

First computer 1959. Retired from my own computer company 2004.
Hardware - Expert in 1401, and 360, fairly knowledge in PC plus numerous MPU's and MCU's
Major Languages - Machine language, 360 Macro Assembler, Intel Assembler, PL/I and PL1, Pascal, Basic, C plus numerous job control and scripting languages.
My personal scorecard is now 1 PC hardware fix (circa 1982), 1 open source fix (at age 82), and 2 zero day bugs in a major OS.


   
ReplyQuote
(@davee)
Member
Joined: 3 years ago
Posts: 1868
 

Hi @imillard,

  Allocating GPIO pins is one of those areas that it is very easy for a designer to fall down a rabbit hole ... microcontroller designers tend to work very hard on providing the eventual circuit designer/user lots of options, but the chip designer must also minimise the silicon surface area and number of pins, so each pin may have its own set of 'special' rules, some of which may easily be missed.

------

  With respect to this question:

or do most GPIOs on both boards have internal pullups that can be enabled through code.

It is probable that all ESPxx style chips have the option of enabling a pull-up on all of their GPIO pins, but all the GPIO pins can be allocated a number of different roles, which in some cases includes determining what happens at power up. So, as @robotbuilder has already indicated, and provided a good reference, it is necessary to check whether each pin also has a conflicting interest.

Sorry, but this is an area that the circuit designer needs to carefully read all available information sources, and even then, carefully prototype the intended arrangement, in case they have missed a 'special' case.  Luckily, others, including the Random Nerds have provided some good starting points.

-----------

For the ESP32-C3 processor, the technical manual from

https://www.espressif.com/sites/default/files/documentation/esp32-c3_technical_reference_manual_en.pdf#iomux

shows on Page 156, the basic circuit for each GPIO pin:

image

This includes "WPD" and "WPU", both of which have a switch which can be enabled by the programmer. Thus, for "pull up", the switch connected to WPU would be set to 'closed'.

This suggests that each GPIO pin of the ESP32-C3 will have the capability of being set to pull up.

BUT it should be understood that the pull up is described as WPU ... Weak Pull Up. That is, the resistor is a fairly high value ... chip manufacturers typically aim for somewhere between 25 kOhm and 100 kOhm.

This means it is fine for ensuring the pin is pulled high if any tracks/wires connected to the pin are short, such as when it connects to a nearby configuration switch or link on the same board. However, if it is connected to (say) an external limit switch by longer wires, then there is a risk that electrical interference will override the effect of the Weak Pull Up resistor. In this case, and external, lower value resistor of say 1 kOhm -10 kOhm is always a good precaution.

Note that this type of hazard, in which, even prototyping can catch you out, as electrical interference often depends on operating conditions, etc. Many manufacturers have found themselves with expensive recalls and warranty claims for products that worked fine in the development lab, but not in their customer's environment!

----------

As a final point, the 'good' news is adding an external resistor or two is usually one of the easiest and cheapest circuit additions, so please don't consider it to be a major issue.

A 'bargain' pack of wire ended resistors can be obtained from many sources for just a few pounds, and may be sufficient for your resistor needs for many years. A quick web search showed the following example:

www.amazon.co.uk/UMTMedia%C2%AE-600pcs-Assorted-Resistors-Electronic/dp/B0987MZ7RC/ref=sr_1_6

image

This is just a suggestion ... there are many alternatives available.

-----------------

Sorry if this is more of a sermon than an instant answer, but hopefully it will be useful.

Best wishes, Dave


   
ReplyQuote
Page 18 / 19