Open falk12 opened 3 years ago
Hi, I am facing the same problem of @falk12.
I creted a simple controller for 42099 model:
Model speed and direction are mapped on a Vertical/horizontal axis of the joystick. I was excepting that encoder of servo motor (motor C) are listed on motor callback function. But results are the same of @falk12
Here the pData* plotted as HEX:
START COMMUNICATION CONNECTED TO HUB New callback: 5 0 45 2 0 1 Move to endstop New callback: 5 0 45 2 FF 1 New callback: 5 0 45 2 FE 1 New callback: 5 0 45 2 F8 1 New callback: 5 0 45 2 EF 1 New callback: 5 0 45 2 E3 1 New callback: 5 0 45 2 D7 1 New callback: 5 0 45 2 CF 1 New callback: ESP32_LEGOINO_42099_v00.zip 5 0 45 2 C5 1 New callback: 5 0 45 2 B6 1 New callback: 5 0 45 2 C5 1 New callback: 5 0 45 2 C8 1 New callback: 5 0 45 2 C0 1 New callback: 5 0 45 2 B4 1 New callback: 5 0 45 2 AC 1 New callback: 5 0 45 2 A6 1 New callback: 5 0 45 2 9F 1 New callback: 5 0 45 2 9C 1 Reset encoder New callback: 5 0 45 2 0 1 New callback: 5 0 45 2 7F 1 Move to center New callback: 5 0 45 2 0 1 New callback: 5 0 45 2 5 1 New callback: 5 0 45 2 D 1 New callback: 5 0 45 2 18 1 New callback: 5 0 45 2 22 1 New callback: 5 0 45 2 2C 1 New callback: 5 0 45 2 19 1 New callback: 5 0 45 2 11 1 New callback: 5 0 45 2 10 1 New callback: 5 0 45 2 11 1 New callback: 5 0 45 2 12 1 New callback: 5 0 45 2 15 1 New callback: 5 0 45 2 7F 1 Calibration done! New callback: 5 0 45 2 0 1 New callback: 5 0 45 2 7F 1 New callback: 5 0 45 2 0 1 and so on...
Any clue?
Thank you.
Hi @Gcopper1984 , @falk12 ! Thanks for reporting that issue. Unfortunately i have never tested the rotation stuff with my TechnicLarge and XLarge motors. I have currently done a fixed mapping of the so called mode to specific device types. But i forgot to add the mappings for all possible devices and the Technic Motors was missing. So if you change the following method in the Lpf2Hub.cpp
file, the sensors should trigger value updates on an rotation. Can you please try it out in changing that code part in your files and test it again?
byte Lpf2Hub::getModeForDeviceType(byte deviceType)
{
switch (deviceType)
{
case (byte)DeviceType::SIMPLE_MEDIUM_LINEAR_MOTOR:
return (byte)HubPropertyOperation::ENABLE_UPDATES_DOWNSTREAM;
case (byte)DeviceType::TRAIN_MOTOR:
return (byte)HubPropertyOperation::ENABLE_UPDATES_DOWNSTREAM;
case (byte)DeviceType::MEDIUM_LINEAR_MOTOR:
return (byte)HubPropertyOperation::ENABLE_UPDATES_DOWNSTREAM;
case (byte)DeviceType::MOVE_HUB_MEDIUM_LINEAR_MOTOR:
return (byte)HubPropertyOperation::ENABLE_UPDATES_DOWNSTREAM;
case (byte)DeviceType::COLOR_DISTANCE_SENSOR:
return 0x08;
case (byte)DeviceType::MOVE_HUB_TILT_SENSOR:
return 0x00;
case (byte)DeviceType::TECHNIC_MEDIUM_ANGULAR_MOTOR:
return (byte)HubPropertyOperation::ENABLE_UPDATES_DOWNSTREAM;
case (byte)DeviceType::TECHNIC_LARGE_ANGULAR_MOTOR:
return (byte)HubPropertyOperation::ENABLE_UPDATES_DOWNSTREAM;
case (byte)DeviceType::TECHNIC_LARGE_LINEAR_MOTOR:
return (byte)HubPropertyOperation::ENABLE_UPDATES_DOWNSTREAM;
case (byte)DeviceType::TECHNIC_XLARGE_LINEAR_MOTOR:
return (byte)HubPropertyOperation::ENABLE_UPDATES_DOWNSTREAM;
default:
return 0x00;
}
}
I have to prepare that mapping for all possible devices and have to update the library soon. Maybe i rewrite this code part because the main modes are always the same.
Additionally it would be a good manner to check if a device is really connected and registered before sending update requests. You can do this with a code snipped as follows (done in the TrainColor.ino example):
byte portForDevice = myHub.getPortForDeviceType((byte)DeviceType::COLOR_DISTANCE_SENSOR);
Serial.println(portForDevice, DEC);
if (portForDevice != 255)
{
...
}
Here you check if you get a port value for an expected device (in your cases the TECHNIC_LARGE_LINEAR_MOTOR
or the TECHNIC_XLARGE_LINEAR_MOTOR
) If a port value is returned, you can send the activatePortDevice
call to get updates. Otherwise the activatePortDevice
message will be dropped.
Hi Cornelius,
thanks for your comments. Result: MoveHub/ControlPlusHub Boost/Motor/L-Motor All report values
PoweredUpHub doesn't report any motor, neither 0 nor constant strange values. In other words: callback isn't triggered (casue the Serial.print don't appear)
I'm not quite happy with that all, because it makes things very complicated. I wanted to write: Hub.motor(portA,50). For all hubs, for all motors.
Some Questions and Ideas: Is there some command-syntax like int rotation = Hub.xxxxxxxxxxxxxxx ? with xxxxxxxxxxxx representing "port" and "rotation"? Why is there no battery-voltage any more? I only get battery-level Why do motors do not run more quickly with value higher than 80? With 80-100 speed remains same.
What about some "connect"-routine? Including the delays? Putting the Hubs into a class or structure? Is it possible to wait for the answer of activate in legoino instead of using delays on user site?
Hi @falk12 !
PoweredUpHub doesn't report any motor, neither 0 nor constant strange values. In other words: callback isn't triggered (casue the Serial.print don't appear)
I have evaluated the PoweredUpHub issue and this was a bug in the device connection method. Every hub behaves a littlebit different and i don't know why, but the PoweredUpHub intitially sends a disconnect event on both ports if a technic motor is attached. This initial disconnect event was decrementing a counter variable below 0 which does not make sense. So long story short, i have fixed it on the develop branch and will soon release an bugfix version 1.0.2
I'm not quite happy with that all, because it makes things very complicated. I wanted to write: Hub.motor(portA,50). For all hubs, for all motors.
Ok.. not good to hear that. I can think of a inherited function for all hubs and motors so that the basic functions are named the same for all motors. I will think about that. But overall it depends on the connected type of motor which commands are possible.
Some Questions and Ideas: Is there some command-syntax like int rotation = Hub.xxxxxxxxxxxxxxx ? with xxxxxxxxxxxx representing "port" and "rotation"?
Can you explain this a little bit more in detail? I didn't get that idea.
Why is there no battery-voltage any more? I only get battery-level
Due to the restructuring of the library, the voltage is no longer a global variable. Voltage an current values are assigned to internal Ports. So they are not a hub property value but a "sensor" value attached to a port. You can have a look on the MoveHubDeviceInfo.ino
example. Here the voltage and current are read in as port values.
Why do motors do not run more quickly with value higher than 80? With 80-100 speed remains same.
Was this different in the version below 1.0.0?
What about some "connect"-routine? Including the delays? Putting the Hubs into a class or structure? Is it possible to wait for the answer of activate in legoino instead of using delays on user site?
Good question. I will think of a more generic, more easy way of handling the connection procedure and to deal with an array of hubs as you have done it before. But maybe that will take some time.
Hi,
yes, it works. I will try to do some experiments with combined mode (as stated in BLE protocol) in order to get position and speed in one shoot).
Thanks.
Hi Cornelius,
I have evaluated the PoweredUpHub issue and this was a bug in the device connection method. Every hub behaves a littlebit different and i don't know why, but the PoweredUpHub intitially sends a disconnect event on both ports if a technic motor is attached. This initial disconnect event was decrementing a counter variable below 0 which does not make sense. So long story short, i have fixed it on the develop branch and will soon release an bugfix version 1.0.2
No, doesn't work with the PoweredUpHub. callback isn't triggered. If the hub is "on" when starting the ESP it triggers once, with unpredictable results. 0 , 256, -12032
Ok.. not good to hear that. I can think of a inherited function for all hubs and motors so that the basic functions are named the same for all motors. I will think about that. But overall it depends on the connected type of motor which commands are possible.
Im absolutly not familiar with c/c++. But setMotorSpeed(portA,50) could be possible for all Motors?
Is there some command-syntax like int rotation = Hub.xxxxxxxxxxxxxxx ? with xxxxxxxxxxxx representing "port" and "rotation"?
Sure. Getting the angle? It is for a while constant, so no callback. So I have to take the initial callback when connecting and store the value in a variable. Is there any way to get the value like int rotations myHub.(portA,ROTATION) or int batlevel myHub(BATTERYLEVEL) or similar? This is not a request, just a question if there is a way to get the values or to invoke the callback with a command ?
And how to get the speed of the rotation?
Due to the restructuring of the library, the voltage is no longer a global variable. Voltage an current values are assigned to internal Ports. So they are not a hub property value but a "sensor" value attached to a port. You can have a look on the
MoveHubDeviceInfo.ino
example. Here the voltage and current are read in as port values.
No. As your program shows: BatteryLevel, values betwenn 0 an 100. BatteryVoltage (as in 0.8.x) would values like 8,53 (V)
Why do motors do not run more quickly with value higher than 80? With 80-100 speed remains same. Was this different in the version below 1.0.0?
No, it was never different. Seems that your pogram only expects values between 0 an 80, your examples runs them between 0 and 100.
Good question. I will think of a more generic, more easy way of handling the connection procedure and to deal with an array of hubs as you have done it before. But maybe that will take some time.
Perhaps this should be dicussed somewhere else? But here is my routine. It uses a structure, where the hubs and their properties are held, and is invoked like that to connect 5 Hubs:
` if (!Remotes[1].pHub.isConnected()) Connect(Remotes[1]);
if (Remotes[1].hubButton) { if (!Hubs[1].pHub.isConnected() && Remotes[1].AButtonStop) Connect(Hubs[1], 1); if (!Hubs[2].pHub.isConnected() && Hubs[1].pHub.isConnected() && Remotes[1].AButtonStop) Connect(Hubs[2]); if (!Hubs[3].pHub.isConnected() && Remotes[1].BButtonStop) Connect(Hubs[3], 1); if (!Hubs[4].pHub.isConnected() && Hubs[3].pHub.isConnected() && Remotes[1].BButtonStop) Connect(Hubs[4], 1); `
So I got some routines like for {int i = 1;i<10;i++} Hub(i).ShutDown;
Here is the function: (don't know why not shown as code?!?)
`// ------------------------------------------ // connect // ------------------------------------------
void Connect (structHubs & id, int remote = 0)
{ bool connTyp = false;
if (id.pHub.isConnected()) return; string x = " " + id.name + " -> " + id.MACadr; logn((" ...Suche Hub : " + x).c_str(), id.blk, colr); if (id.useMacAddr > 0) { id.pHub.init(userHubs[id.useMacAddr].macAddr); } else { id.pHub.init(); } delay(100); if (id.pHub.isConnecting()) { logn((id.name + " connecting" ).c_str(), id.blk, colb); if (id.isRemote == true && id.pHub.getHubType() == HubType::POWERED_UP_REMOTE) connTyp = true; if (id.isRemote == false && id.pHub.getHubType() == HubType::POWERED_UP_HUB ) connTyp = true; if (id.isRemote == false && id.pHub.getHubType() == HubType::CONTROL_PLUS_HUB) connTyp = true; logn(connTyp); logn("---------------"); if (connTyp) { if (id.pHub.connectHub()) { logn((id.name + " connected" ).c_str(), id.blk, colg); // ---------------------------------- id.pHub.setLedColor(id.LEDcolor); id.recMACadr = id.pHub.getHubAddress(); id.recHubType = id.pHub.getHubType(); id.recName = id.pHub.getHubName(); id.status = "CONN";
delay(cDelay);
id.pHub.activateHubPropertyUpdate( HubPropertyReference::BATTERY_VOLTAGE, hubProperties);
delay(cDelay);
id.pHub.activateHubPropertyUpdate( HubPropertyReference::BUTTON, hubProperties);
delay(cDelay);
if (id.pHub.getHubType() == HubType::POWERED_UP_REMOTE)
{
delay(cDelay);
id.pHub.activatePortDevice(FB_A, remoteButtons);
delay(cDelay);
id.pHub.activatePortDevice(FB_B, remoteButtons);
delay(cDelay);
}
}
} }`
@falk12
No, doesn't work with the PoweredUpHub. callback isn't triggered. If the hub is "on" when starting the ESP it triggers once, with unpredictable results. 0 , 256, -12032
Have you tried it with the version 1.0.2 ?
No. As your program shows: BatteryLevel, values betwenn 0 an 100. BatteryVoltage (as in 0.8.x) would values like 8,53 (V)
Thats correct but there is also the following part of the code which shows (if an update is available) the current and voltage measured from the hub. And this voltage should be exaclty the same e.g. 7.14 as in the "old" versions of the library. Here you can find the code part in the MoveHubDeviceInfo.ino
sektch where the real Voltage and Current values are processed:
void portValueChangeCallback(void *hub, byte portNumber, DeviceType deviceType, uint8_t *pData)
{
Lpf2Hub *myHub = (Lpf2Hub *)hub;
if (deviceType == DeviceType::VOLTAGE_SENSOR)
{
double voltage = myHub->parseVoltageSensor(pData);
Serial.print("Voltage: ");
Serial.println(voltage, 2);
return;
}
if (deviceType == DeviceType::CURRENT_SENSOR)
{
double current = myHub->parseCurrentSensor(pData);
Serial.print("Current: ");
Serial.println(current, 2);
return;
}
No, it was never different. Seems that your pogram only expects values between 0 an 80, your examples runs them between 0 and 100.
Ok, i will do a check and try to compare it with the PoweredUp App
And how to get the speed of the rotation?
I think you can calculate it by your own in checking the time deltas and angle deltas from callback to callback or there is maybe another mode in the Motor which sends you the speed directly. For the DuploTrain there is a build in Speedometer which sends you changes of the speed. But i think for the motors, the speed values are not exposed
Hi,
thanks for your response
Have you tried it with the version 1.0.2 ?
Yes, the on that changed the behaviour of the ControlPlus and MovHub
Thats correct but there is also the following part of the code which shows (if an update is available) the current and voltage measured from the hub.
Yes, thanks. The constant is called BATTERY_VOLTAGE, but gives the level, I missed that.
I think you can calculate it by your own in checking the time deltas and angle deltas from callback to callback or there is maybe another mode in the Motor which sends you the speed directly.
Sure, but then I have to set up many timers. I have to think about that.
Thanks for today.
Hi @falk12, @corneliusmunz
I try the PoweredUp hub with mmotor (lego batmobile set) and I also found that callback trigger are not fired (also with new library 1.0.2 and file edited as suggested).
After (a lot) of debugging I send to hub the Port Request Information with "information type " = 0x01 and this is the reply (command 0x43)
B 0 43 1 1 1 1 0 0 1 0
Just write better: 0x0B - 0x00 - 0x43 - 0x01 - 0x01 - 0x01 - 0x01 - (int16)(0x00 0x00) - (int16)(0x00 0x01) -> the int16 byte are swapped In other words: B: lenght of message (in HEX) 0x00 : hub number 0x43: command reply "Port information" 0x01: port number (port B in this case) 0x01: information type MODE INFO 0x01: Capabilities: only output (as seen from hub) 0x01: total number of port modes (1) (int16)(0x00 0x00): input modes = 0 NO INPUT (int16)(0x00 0x01): output mode only 0 is available.
So, I understood that this motor can only send power, no feedback from nothing.
Another clue of this point is that if I check the philohome motor comparison:
https://www.philohome.com/motors/motorcomp.htm
the powered Up medium motor do not has an encoder like other new motors
Could be this a solution?
Any feedback are welcome.
Thanks
Hi @Gcopper1984
I try the PoweredUp hub with mmotor (lego batmobile set) and I also found that callback trigger are not fired (also with new library 1.0.2 and file edited as suggested).
The so called M-motor ist not a tacho-motor. So this is normal and correct.
But discussion here ist about Boost-Motor, L-Motor and XL-Motor. And they do report on MoveHub and ControlHub but not on PoweredupHub.
Ok so I miss the point.
Just to understand, which is the MoveHub? Is it the same from the Boost bub? L-motor and XL-motor are in the 42099 set, right?
Hi,
it's a little bit complicated, because "Boost" is only a "theme" and "control+" only an App and no hardware at all.
There are three Hubs: MoveHub (in the Boost Sets) Lego-Name: LPF2 HUB MOTOR 6X16X4 NO. 1 / 88006 Hub (in the CityStes) Lego-Name: HUB NO. 4 / 88009 technicHub(in technic Sets) Lego-Name: HUB, NO. 2 / 88012
and the Motors
M-Motor (WeDo 2.0, Batmobil) | Lego-Name: ??? / 45303 Boost-Motor (in Boost Sets)| Lego-Name: LPF2 TACHO MOTOR 4X6X3, NO. 1 / 88008 Train-Motor (in City) Lego-Name: MOTOR, NO. 4 / 88011 L -Motor (in technic-sets) Lego-Name: MOTOR, NO. 2 / 88013 XL-Motor( in technic-stes) Lego-Name: MOTOR, NO. 3 / 88014
The problem: the "common names" in Col. A change with the language.
Hi,
very good recap.
MoveHub/ControlPlusHub Boost/Motor/L-Motor All report values
PoweredUpHub doesn't report any motor, neither 0 nor constant strange values. In other words: callback isn't triggered (casue the Serial.print don't appear)
Ok, so your problem is that if you connect a lego L -Motor or XL-Motor to HUB NO. 4 / 88009 you do not get any feedback, right?
No, the problem is that it ( the Hub that LEGO calls "Hub", others "CityHub" or "TrainHub" or "HubNo4", and legoino calls "PowerdUpHub", yes, the 88009, doesn't trigger with all motors I tried. And it should with all tacho-Motors: Boost, L, XL and all angulars (which I can't test)
@falk12 Thanks for the good overview of the confusing naming schemes 👍 It is really weired. I have tested it with the 1.0.2 version, the 88009 hub and the Boost Motor and it works. The only important thing is in my point of view, that the timing of the 88009 hub seems to be a little bit different than the timing of the move and technicHub. The 88009 hub is way more slower in detecting the connected devices. So here it is very important to check if the device is really connected before activating the device for updates. Can you please check the following (adapted) rotation sketch?
/**
* A MoveHub basic example to connect a boost hub, set the led color of the hub
* dependent on the detected rotation of the boost tacho motor. Usage of callback function
* if motor angle is changed
*
* (c) Copyright 2020 - Cornelius Munz
* Released under MIT License
*
*/
#include "Lpf2Hub.h"
// create a hub instance
Lpf2Hub myHub;
byte portMediumLinearMotor = 255;
bool isInitialized = false;
void buttonCallback(void *hub, HubPropertyReference hubProperty, uint8_t *pData)
{
Lpf2Hub *myHub = (Lpf2Hub *)hub;
if (hubProperty == HubPropertyReference::BUTTON)
{
if (myHub->parseHubButton(pData) == ButtonState::PRESSED) {
myHub->setAbsoluteMotorEncoderPosition(portMediumLinearMotor, 0);
}
}
}
// callback function to handle updates of sensor values
void tachoMotorCallback(void *hub, byte portNumber, DeviceType deviceType, uint8_t *pData)
{
Lpf2Hub *myHub = (Lpf2Hub *)hub;
Serial.print("sensorMessage callback for port: ");
Serial.println(portNumber, DEC);
if (deviceType == DeviceType::MEDIUM_LINEAR_MOTOR)
{
int rotation = myHub->parseTachoMotor(pData);
Serial.print("Rotation: ");
Serial.print(rotation, DEC);
Serial.println(" [degrees]");
myHub->setLedHSVColor(abs(rotation), 1.0, 1.0);
}
}
void setup()
{
Serial.begin(115200);
myHub.init(); // initalize the MoveHub instance
}
// main loop
void loop()
{
// connect flow. Search for BLE services and try to connect if the uuid of the hub is found
if (myHub.isConnecting())
{
myHub.connectHub();
if (myHub.isConnected())
{
Serial.println("Connected to HUB");
delay(100);
myHub.activateHubPropertyUpdate(HubPropertyReference::BUTTON, buttonCallback);
myHub.setLedColor(GREEN);
}
else
{
Serial.println("Failed to connect to HUB");
}
}
// if connected, you can set the name of the hub, the led color and shut it down
if (myHub.isConnected() && !isInitialized)
{
delay(200);
Serial.println("check ports... if needed sensor is already connected: ");
portMediumLinearMotor = myHub.getPortForDeviceType((byte)DeviceType::MEDIUM_LINEAR_MOTOR);
Serial.print("Port for MEDIUM_LINEAR_MOTOR: ");
Serial.println(portMediumLinearMotor, DEC);
if (portMediumLinearMotor != 255)
{
myHub.activatePortDevice(portMediumLinearMotor, tachoMotorCallback);
isInitialized = true;
}
}
} // End of loop
Hi @corneliusmunz ,
yes, that works. Where in the example was delay(200), sometimes I have to wait more than 2000ms. So I'ill have to generate special subroutines for this whole theme. I'll check.
Thanks for your efforts.
@falk12 I will try to update all examples and update the documentation too. I think it is time to think about an easier handling of connection and setup of the hubs and connected devices. Currently a lot of boilerplate code is needed to have a setup after you can make the real use of the library functions.
Features would be:
Any other requests/ideas out there?? @falk12 @Gcopper1984
Hi @corneliusmunz,
maybe another useful function could be the implementation of multi mode reply
https://lego.github.io/lego-ble-wireless-protocol-docs/#port-input-format-setup-combinedmode
where i can get multiple informations about motor and sensor in only 1 reply. For example, motor can reply with it speed, position and position absolute in a single message.
Last thing could be the extension of this library for other ble board like the ble sense
https://store.arduino.cc/arduino-nano-33-ble-sense
Thank you.
Hi @corneliusmunz ,
@falk12 I will try to update all examples and update the documentation too. I think it is time to think about an easier handling of connection and setup of the hubs and connected devices. Currently a lot of boilerplate code is needed to have a setup after you can make the real use of the library functions.
Indeed. Program could be:
Connect(Hub);
Serial.println(Hub,PORTA,ROTATIONS)
Two Lines! ;-)
* Single Setup command where the hub with attached devices, callbacks could be defined * Support of use and array multiple hub instances * Get rid of the isConnecting / connectHub methods and do this internally in the library
This is just what my "microHub" project does. (it's running with 1.0.2) https://www.1000steine.de/de/gemeinschaft/forum/?entry=1&id=443479#id443479 There have been some betatesters, and it works, includung Web-Interface to configure. I have some solutions implemented, but I am absolutetly lost with classes an pointers in C, so it's very simple.
Tell me: where should we start a discussion about that?
Hi,
I don't get anything working except the boost. below the results for all hubs and motors with the columns motor/result when connected/feedback if turned manually MoveHub Boost Rotation: 0 [degrees] Ok L Rotation: 10240 [degrees] none XL Rotation: 33559552 [degrees] none intern Rotation: 0 [degrees] Ok
ControlPlusHub Boost Sometimes working L Rotation: 16792320 [degrees] none XL Rotation: 16792320 [degrees] none
PoweredUpHub Boost Rotation: -12032 [degrees] none L Rotation: -12032 [degrees] none XL Rotation: -12032 [degrees] none
Here is the code based on your exmaple: Only type of ports is changed, checking of DeviceType removed. Please note: the delay(100) after init() makes connection much easier and faster